好文档 - 专业文书写作范文服务资料分享网站

USB驱动编程指南

天下 分享 时间: 加入收藏 我要投稿 点赞

- .

USB驱动编写指南

1 概念:模块和设备文件

1.1模块

模块是在核空间运行的程序,实际上是一种目标对象文件,没有,不能独立运行,但是可以装载到系统中作为核的一部分运行,从而可以动态扩充核的功能。模块最主要的用处就是用来实现设备驱动程序。Linux下对于一个硬件的驱动,可以有两种方式:直接加载到核代码中,启动核时就会驱动此硬件设备。另一种就是以模块方式,编译生成一个.ko文件(在2.4以下核中是用.o作模块文件,我们以2.6的核为准,以下同)。当应用程序需要时再加载到核空间运行。所以我们所说的一个硬件的驱动程序,通常指的就是一个驱动模块。 1.2设备文件

设备文件对于一个设备,它可以在/dev下面存在一个对应的逻辑设备节点,这个节点以文件的形式存在,但它不是普通意义上的文件,它是设备文件,更确切 的说,它是设备节点。这个节点是通过mknod命令建立的,其中指定了主设备号和次设备号。主设备号表明了某一类设备,一般对应着确定的驱动程序;次设备号一般是区分不同属性,例如不同的使用方法,不同的位置,不同的操作。这个设备号是从/proc/devices文件中获得的,所以一般是先有驱动程序在核中,才有设备节点在目录中。这个设备号(特指主设备号)的主要作用,就是声明设备所使用的驱动程序。驱动程序和设备号是一一对应的,当你打开一个设备文件时,操作系统就已经知道这个设备所对应的驱动程序。对于一个硬件,Linux是这样来进行驱动的:首先,我们必须提供一个.ko的驱动模块文件。我们要使用这个驱动程序,首先要加载它,我们可以用insmod xxx.ko,这样驱动就会根据自己的类型(字符设备类型或块设备类型,例如鼠标就是字符设备而硬盘就是块设备)向系统注册,注册成功系统会反馈一个主设备号,这个主设备号就是系统对它的唯一标识。驱动就是根据此主设备号来创建一个一般放置在/dev目录下的设备文件。在我们要访问此硬件时,就可以对设备文件通过open、read、write、close等命令进行。而驱动就会接收到相应的read、write操作而根据自己的模块中的相应函数进行操作 了。

2USB驱动程序如何应用

了解了上述理论后,我们就可以动手写驱动程序,如果你基本功好,而且写过linux下的硬件驱动,USB的硬件驱动和pci_driver很类似,那么写 USB的驱动就比较简单了,如果你只是大体了解了linux的硬件驱动,那也不要紧,因为在linux的核源码中有一个框架程序可以拿来借用一下,这个框架程序在/usr/src/~(你的核版本,以下同)/drivers/usb下,文件名为usb-skeleton.c。写一个USB的驱动程序最基本的要做四件事:驱动程序要支持的设备、注册USB驱动程序、探测和断开、提交和控制urb(USB请求块)(当然也可以不用urb来传输数据,下文我们会说到)。 2.1驱动程序支持的设备

驱动程序支持的设备有一个结构体struct usb_device_id,这个结构体提供了一列不同类型的该驱动程序支持的USB设备,对于一个只控制一个特定的USB设备的驱动程序来说,struct usb_device_id表被定义为: /* 驱动程序支持的设备列表 */

static struct usb_device_id skel_table = {

- -可修编-

- .

{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, { } /* 终止入口 */ };

MODULE_DEVICE_TABLE (usb, skel_table);

对于PC驱动程序,MODULE_DEVICE_TABLE是必需的,而且usb必需为该宏的第一个值,而USB_SKEL_VENDOR_ID和 USB_SKEL_PRODUCT_ID就是这个特殊设备的制造商和产品的ID了,我们在程序中把定义的值改为我们这款USB的,如: /* 定义制造商和产品的ID号 */

#define USB_SKEL_VENDOR_ID 0x1234 #define USB_SKEL_PRODUCT_ID 0x2345 这两个值可以通过命令lsusb,当然你得先把USB设备先插到主机上了。或者查看厂商的USB设备的手册也能得到,在我机器上运行lsusb是这样的结果: Bus 004 Device 001: ID 0000:0000

Bus 003 Device 002: ID 1234:2345 Abc Corp. Bus 002 Device 001: ID 0000:0000 Bus 001 Device 001: ID 0000:0000

得到这两个值后把它定义到程序里就可以了。 2.2注册USB驱动程序

注册USB驱动程序所有的USB驱动程序都必须创建的结构体是struct usb_driver。这个结构体必须由USB驱动程序来填写,包括许多回调函数和变量,它们向USB核心代码描述USB驱动程序。创建一个有效的struct usb_driver结构体,只须要初始化五个字段就可以了,在框架程序中是这样的:

static struct usb_driver skel_driver = { .owner = THIS_MODULE, .name = \.probe = skel_probe,

.disconnect = skel_disconnect, .id_table = skel_table, };

struct module *owner :指向该驱动程序的模块所有者的批针。USB核心使用它来正确地对该USB驱动程序进行引用计数,使它不会在不合适的时刻被卸载掉,这个变量应该被设置为THIS_MODULE宏。

const char *name:指向驱动程序名字的指针,在核的所有USB驱动程序中它必须是唯一的,通常被设置为和驱动程序模块名相同的名字。

int (*probe) (struct usb_interface *intf,const struct usb_device_id *id):这个是指向USB驱动程序中的探测函数的指针。当USB核心认为它有一个接口(usb_interface)可以由该驱动程序处理时,这个函数被调用。

void (disconnect)(struct usb_interface *intf):指向USB驱动程序中的断开函数的指针,当一个USB接口(usb_interface)被从系统中移除或者驱动程序正在从USB核心中卸载时,USB核心将调用这个函数。

const struct usb_device_id *id_table:指向ID设备表的指针,这个表包含了一列该驱动程序可以支持的USB设备,如果没有设置这个变量,USB驱动程序中的探测回调函数就不会被调用。

在这个结构体中还有其它的几个回调函数不是很常用,这里就不一一说明了。以struct

- -可修编-

- .

usb_driver 指针为参数的usb_register_driver函数调用把struct usb_driver注册到USB核心。一般是在USB驱动程序的模块初始化代码中完成这个工作的: static int __init usb_skel_init(void) {

int result;

/* 驱动程序注册到USB子系统中*/ result = usb_register(&skel_driver); if (result)

err(\return result; }

当USB驱动程序将要被卸载时,需要把struct usb_driver从核中注销。通过调用usb_deregister_driver来完成这个工作,当调用发生时,当前绑定到该驱动程序上的任何USB接口都被断开,断开函数将被调用: static void __exit usb_skel_exit(void) {

/* 从子系统注销驱动程序*/ usb_deregister(&skel_driver); }

2.3探测和断开

探测和断开当一个设备被安装而USB核心认为该驱动程序应该处理时,探测函数被调用,探测函数检查传递给它的设备信息,确定驱动程序是否真的适合该设备。当驱动程序因为某种原因不应该控制设备时,断开函数被调用,它可以做一些清理工作。探测回调函数中,USB驱动程序初始化任何可能用于控制USB设备的局部结构体,它还把所需的任何设备相关信息保存到一个局部结构体中,下面是探测函数的部分源码,我们加以分析。 /* 设置端点信息 */

/* 只使用第一个批量IN和批量OUT端点 */ iface_desc = interface->cur_altsetting;

for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint.desc; if (!dev->bulk_in_endpointAddr &&

(endpoint->bEndpointAddress & USB_DIR_IN) &&

((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { /* 找到一个批量IN端点 */

buffer_size = endpoint->wMaxPacketSize; dev->bulk_in_size = buffer_size;

dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!dev->bulk_in_buffer) {

err(\goto error; }

- -可修编-

USB驱动编程指南

-.USB驱动编写指南1概念:模块和设备文件1.1模块模块是在核空间运行的程序,实际上是一种目标对象文件,没有,不能独立运行,但是可以装载到系统中作为核的一部分运行,从而可
推荐度:
点击下载文档文档为doc格式
13kzd1weoe570pk9t8239nplx1m5bx00alx
领取福利

微信扫码领取福利

微信扫码分享