Linux设备驱动入门----USB设备驱动
/***************************************** USB主机与设备驱动* 主机侧:由底到高:USB主机控制器硬件-->* USB主机控制器驱动--> USB核心层 --> USB* 设备驱动层* 设备侧:UDC驱动程序、Gadget API和Gadget* 驱动程序* 逻辑组织:设备(1)配置(n)*配置
·
/****************************************
* 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 */
static struct usb_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串口设备驱动的模块加载函数 */
static int __init usb_serial_init(void)
{
int i;
int result;
/* 分配tty_driver */
usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
if(usb_serial_tty_driver)
{
return -ENOMEM;
}
/* 初始化全局变量 */
for(i = 0; i < SERIAL_TTY_MINORS; ++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__);
goto exit_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__);
goto exit_reg_driver;
}
/* 注册USB驱动 */
result = usb_register(&usb_serial_driver);
if (result < 0)
{
printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
__func__);
goto exit_tty;
}
/* register the generic driver, if we should */
result = usb_serial_generic_register(debug);
if (result < 0)
{
printk(KERN_ERR "usb-serial: %s - registering generic "
"driver failed\n", __func__);
goto exit_generic;
}
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return result;
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);
return result;
}
static void __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。
*
*/
static const struct tty_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
*/
static int __init usb_kbd_init(void)
{
int result = usb_register(&usb_kbd_driver); //注册USB设备驱动
if (result == 0)
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
return result;
}
static void __exit usb_kbd_exit(void)
{
usb_deregister(&usb_kbd_driver);
}
static struct usb_driver usb_kbd_driver = {
.name = "usbkbd",
.probe = usb_kbd_probe,
.disconnect = usb_kbd_disconnect,
.id_table = usb_kbd_id_table,
};
// 支持的设备列表
static struct usb_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的初始化,并设置接口的私有数据。
*/
static int usb_kbd_probe(struct usb_interface *iface,
const struct usb_device_id *id)
{
...
}
/* 设置接口私有数据为NULL、终止已提交的urb并注销输入设备。*/
static void usb_kbd_disconnect(struct usb_interface *intf)
{
...
}
/*
* 键盘中断处理函数中,也就是urb的完成函数中,将会通过input_report_key()
* 报告按键事件,通过input_sync()报告同步事件,并发起一次新的控制urb传输。
*/
static void usb_kbd_irq(struct urb *urb)
{
struct usb_kbd *kbd = urb->context;
int i;
switch (urb->status)
{
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
case -ESHUTDOWN:
return;
/* -EPIPE: should clear the halt */
default: /* error */
goto resubmit;
}
for (i = 0; i < 8; i++)
{
input_report_key(kbd->dev, usb_kbd_keycode[i + 224],
(kbd->new[0] >> i) & 1);
}
for (i = 2; i < 8; 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);
}
}
小结:
这个只能了解usb设备驱动的大概,要真正深刻理解USB驱动,需要对USB源码进行分析和对相关协议的理解。这里稍微总结一下:
USB驱动分为USB主机驱动和USB设备驱动,如果系统的USB主机控制器符合OHCI等标准,这主机驱动的绝大部分工作都可以沿用通用的代码。
对于一个USB设备而言,它至少具备两重身份:首先它是“USB”的,其次它是“自己”的。USB设备是“USB”的,指它挂接在USB总线上,其必须完成usb_driver的初始化和注册;USB设备是“自己”的,意味着本身可能是一个字符设备、tty设备、网路设备等,因此,USB设备驱动中必须实现符合相应框架的代码。
USB设备驱动的自身设备驱动部分的读写等操作流程有其特殊性,即以URB来贯穿始终,一个USB的生命周期通常包含创建、初始化、提交,和被USB核心及USB主机传递及完成后回调函数被调用的过程,当然,在URB被驱动提交后,也可以被取消。此外,简单的控制及批量消息传递可以用同步的usb_bulk_msg()、usb_control_msg()函数完成。
更多推荐
已为社区贡献1条内容
所有评论(0)