linux控制器与设备驱动,Linux设备驱动入门

本文深入解析了USB主机与设备驱动的工作原理,包括主机控制器驱动、USB核心层、设备驱动层的层次结构。介绍了设备描述符、配置描述符等标准描述符,以及urb的生命周期。此外,通过USB串口驱动和USB键盘驱动的实例,展示了驱动的注册、初始化、中断处理等关键过程。
摘要由CSDN通过智能技术生成

/****************************************

* USB主机与设备驱动

* 主机侧:由底到高:USB主机控制器硬件-->

* USB主机控制器驱动--> USB核心层 --> USB

* 设备驱动层

* 设备侧:UDC驱动程序、Gadget API和Gadget

* 驱动程序

* 逻辑组织:设备(1)  配置(n)

*           配置(1)  接口(n)

* 端点(0/n)  接口(1)  设置(n)

* USB主机控制驱动:控制插入其中的USB设备

* USB设备驱动:控制USB设备如何与主机通信

* 标准描述符:

* 设备描述符 usb_device_descriptor

* 配置描述符 usb_config_descriptor

* 接口描述符 usb_interface_descriptor

* 端点描述符 usb_endpoint_descriptor

* 字符串描述符 usb_string_descriptor

* 几个重要的数据结构:hc_driver usb_hcd

* ohci_hcd usb_driver urb(请求块)

* urb的典型生命周期:

* (1) 被一个USB设备驱动创建

* (2) 初始化,被安排给一个特定USB设备的特定端点

* (3) 被USB设备驱动提交给USB核心

* (4) 提交与USB核心指定的USB主机控制器驱动

* (5) 被USB主机控制器处理,进行一次到USB设备的传送

* (6) 当urb完成,USB主机控制器驱动通知USB设备驱动

*

* probe() 和 disconnect() 这两个函数比较重要

*

********************************************/

/*

* USB 设备驱动实例:USB串口驱动(部分)

*

*/

/* Driver structure we register with the USB core */

staticstructusb_driver usb_serial_driver = {

.name ="usbserial",

.probe = usb_serial_probe,

.disconnect = usb_serial_disconnect,

.suspend = usb_serial_suspend,

.resume = usb_serial_resume,

.no_dynamic_id = 1,

}

/* USB串口设备驱动的模块加载函数 */

staticint__init usb_serial_init(void)

{

inti;

intresult;

/* 分配tty_driver */

usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);

if(usb_serial_tty_driver)

{

return-ENOMEM;

}

/* 初始化全局变量 */

for(i = 0; i 

serial_table[i] = NULL;

/* 注册总线 */

result = bus_register(&usb_serial_bus_type);

if(result)

{

printk(KERN_ERR"usb-serial: %s - registering bus driver failed\n", __func__);

gotoexit_bus;

}

/* 初始化tty_driver */

usb_serial_tty_driver->owner = THIS_MODULE;

usb_serial_tty_driver->driver_name ="usbserial";

usb_serial_tty_driver->name ="ttyUSB";

usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;

usb_serial_tty_driver->minor_start = 0;

usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;

usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;

usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;

usb_serial_tty_driver->init_termios = tty_std_termios;

usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD

| HUPCL | CLOCAL;

usb_serial_tty_driver->init_termios.c_ispeed = 9600;

usb_serial_tty_driver->init_termios.c_ospeed = 9600;

tty_set_operations(usb_serial_tty_driver, &serial_ops);

/*  注册tty_driver */

result = tty_register_driver(usb_serial_tty_driver);

if(result)

{

printk(KERN_ERR"usb-serial: %s - tty_register_driver failed\n",

__func__);

gotoexit_reg_driver;

}

/* 注册USB驱动 */

result = usb_register(&usb_serial_driver);

if(result 

{

printk(KERN_ERR"usb-serial: %s - usb_register failed\n",

__func__);

gotoexit_tty;

}

/* register the generic driver, if we should */

result = usb_serial_generic_register(debug);

if(result 

{

printk(KERN_ERR"usb-serial: %s - registering generic "

"driver failed\n", __func__);

gotoexit_generic;

}

printk(KERN_INFO KBUILD_MODNAME": "DRIVER_DESC"\n");

returnresult;

exit_generic:

usb_deregister(&usb_serial_driver);

exit_tty:

tty_unregister_driver(usb_serial_tty_driver);

exit_reg_driver:

bus_unregister(&usb_serial_bus_type);

exit_bus:

printk(KERN_ERR"usb-serial: %s - returning with error %d\n",

__func__, result);

put_tty_driver(usb_serial_tty_driver);

returnresult;

}

staticvoid__exit usb_serial_exit(void)

{

usb_serial_console_exit();

usb_serial_generic_deregister();

usb_deregister(&usb_serial_driver);//注销usb_driver

tty_unregister_driver(usb_serial_tty_driver);// 注销tty_driver

put_tty_driver(usb_serial_tty_driver);// 减少引用计数

bus_unregister(&usb_serial_bus_type);// 注销bus

}

/*

* 在usb_driver的探测成员函数usb_serial_probe()中,将初始化USB端点

* 等信息,并通过usb_set_intfdata()设置接口私有数据,它也将初始化urb。

*

*/

staticconststructtty_operations serial_ops = {

.open =         serial_open,

.close =        serial_close,

.write =        serial_write,

.hangup =       serial_hangup,

.write_room =   serial_write_room,

.ioctl =        serial_ioctl,

.set_termios =  serial_set_termios,

.throttle =     serial_throttle,

.unthrottle =   serial_unthrottle,

.break_ctl =    serial_break,

.chars_in_buffer =  serial_chars_in_buffer,

.tiocmget =     serial_tiocmget,

.tiocmset =     serial_tiocmset,

.get_icount =   serial_get_icount,

.cleanup =      serial_cleanup,

.install =      serial_install,

.proc_fops =    &serial_proc_fops,

};

///

/*

* USB 设备驱动实例:USB键盘驱动(部分)

* 主要包含两部分:

*     usb_driver的成员函数

*     输入设备的打开、关闭、中断处理等函数

*

*/

/*

* 在USB键盘设备驱动的模块加载和卸载函数中

* ,将分别注册和注销对于USB键盘的usb_driver

* 结构体usb_kbd_driver

*/

staticint__init usb_kbd_init(void)

{

intresult = usb_register(&usb_kbd_driver);//注册USB设备驱动

if(result == 0)

printk(KERN_INFO KBUILD_MODNAME": "DRIVER_VERSION":"

DRIVER_DESC"\n");

returnresult;

}

staticvoid__exit usb_kbd_exit(void)

{

usb_deregister(&usb_kbd_driver);

}

staticstructusb_driver usb_kbd_driver = {

.name ="usbkbd",

.probe =    usb_kbd_probe,

.disconnect =   usb_kbd_disconnect,

.id_table = usb_kbd_id_table,

};

// 支持的设备列表

staticstructusb_device_id usb_kbd_id_table [] = {

{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,

USB_INTERFACE_PROTOCOL_KEYBOARD) },

{ }/* Terminating entry */

};

MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);

/*

* 在usb_driver的探测函数中,将进行input设备的初始化和注册。

* usb键盘要使用的中断urb和控制urb的初始化,并设置接口的私有数据。

*/

staticintusb_kbd_probe(structusb_interface *iface,

conststructusb_device_id *id)

{

...

}

/* 设置接口私有数据为NULL、终止已提交的urb并注销输入设备。*/

staticvoidusb_kbd_disconnect(structusb_interface *intf)

{

...

}

/*

* 键盘中断处理函数中,也就是urb的完成函数中,将会通过input_report_key()

* 报告按键事件,通过input_sync()报告同步事件,并发起一次新的控制urb传输。

*/

staticvoidusb_kbd_irq(structurb *urb)

{

structusb_kbd *kbd = urb->context;

inti;

switch(urb->status)

{

case0:/* success */

break;

case-ECONNRESET:/* unlink */

case-ENOENT:

case-ESHUTDOWN:

return;

/* -EPIPE:  should clear the halt */

default:/* error */

gotoresubmit;

}

for(i = 0; i 

{

input_report_key(kbd->dev, usb_kbd_keycode[i + 224],

(kbd->new[0] >> i) & 1);

}

for(i = 2; i 

{

if(kbd->old[i] > 3 &&

memscan(kbd->new+ 2, kbd->old[i], 6) == kbd->new+ 8)

{

if(usb_kbd_keycode[kbd->old[i]])

{

input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);

}

else

{

dev_info(&urb->dev->dev,

"Unknown key (scancode %#x) released.\n", kbd->old[i]);

}

}

if(kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8)

{

if(usb_kbd_keycode[kbd->new[i]])

input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);

else

dev_info(&urb->dev->dev,

"Unknown key (scancode %#x) released.\n", kbd->new[i]);

}

}

input_sync(kbd->dev);

memcpy(kbd->old, kbd->new, 8);

resubmit:

i = usb_submit_urb (urb, GFP_ATOMIC);

if(i)

{

err_hid ("can't resubmit intr, %s-%s/input0, status %d",

kbd->usbdev->bus->bus_name,

kbd->usbdev->devpath, i);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值