关闭

Linux设备驱动入门----USB设备驱动

2523人阅读 评论(2) 收藏 举报
分类:
/****************************************
 * 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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:121752次
    • 积分:1535
    • 等级:
    • 排名:千里之外
    • 原创:27篇
    • 转载:6篇
    • 译文:0篇
    • 评论:25条
    最新评论