Chinaunix首页 | 论坛 | 博客
  • 博客访问: 26344
  • 博文数量: 9
  • 博客积分: 185
  • 博客等级: 入伍新兵
  • 技术积分: 90
  • 用 户 组: 普通用户
  • 注册时间: 2013-01-08 19:14
文章分类
文章存档

2013年(10)

我的朋友

分类:

2013-01-08 22:25:32

原文地址:linux中的USB驱动理解 作者:Acikee

今天内容:USB驱动

1.         在USB设备组织结构中,从上到下分为设备(device)、配置(config)、接口(interface)和端点(endpoint)四个层次。

2.         设备地代表了一个插入的USB设备,在内核使用数据结构 struct usb_device来描述。

3.         一个USB设备可以有多个配置,并可在它们之间转换以改变设备的状态。比如一个设备可以通过下载固件(firmware)的方式改变设备的使用状态(我感觉类似FP那么USB设备就要切换配置,来完成这个工作。一个时刻只能有一个配置可以被激活。Linux使用结构 struct usb_host_config 来描述USB配置。

4.         一个USB接口代表一个基本功能,每个USB驱动控制一个接口。所以一个物理上的硬件设备可能需要一个以上的驱动程序。

5.         端点可被看作一个单向的管道。4 种不同类型:控制(CONTROL)传输、批量(BULK)传输(U盘)、中断(INTERRUPT)传输(定时轮询如小数据量:鼠标键盘)、等时(ISOCHRONOUS)传输(类似UDP 不可靠大量数据的轮询:音频和视频设备)。

6.         USB枚举过程:由USB内核完成

1、第一次GetDescriptor :确定缺省管道控制断点的每次数据包大小(只确认前8字节)

2、SetAddress

3、再次发送GetDescriptor 根据描述符确定驱动程序

4、GetConfiguration,读取多个配置

5、SetConfiguration,确定需要使用的配置

7.         USB 设备驱动代码通过urb和所有的 USB 设备通讯。

 

 

 

一个 urb 的典型生命循环如下:
 (1)被创建;
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
 (2)被分配给一个特定 USB 设备的特定端点;

static inline void usb_fill_XXX_urb(struct urb *urb,

                 struct usb_device *dev,

                 unsigned int pipe,

                 void *transfer_buffer,

                 int buffer_length,

                 usb_complete_t complete_fn,

                 void *context,

                        int interval);

XXX 为int中断,bulk批量,control控制 等时传输没有初始化函数,只能手动初始化。
 (3)被提交给 USB 核心;

int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
 (4)被 USB 核心提交给特定设备的特定 USB 主机控制器驱动;
 (5)被 USB 主机控制器驱动处理, 并传送到设备;
 (6)以上操作完成后,USB主机控制器驱动通知 USB 设备驱动;

执行结束处理例程。()使用 void usb_kill_urb(struct urb *urb) 和

Int usb_unlink_usb(struct urb *urb) 取消一个已经提交的URB

 (7)urb的注销;void usb_free_urb(struct urb *urb);

1.         驱动程序把驱动对象注册到 USB 子系统中,之后使用供应商(idVendor)和设备(idProduct)标识来判断对应的硬件是否已经安装.struct usb_device_id 结构提供了这个驱动支持的不同类型 USB 设备的列表. USB 核心通过此列表用来决定设备对应的驱动,热插拔脚本也通过此列表来决定当特定设备被插入系统时,应该自动加载的驱动.

2.         开发步骤:

1     初始化厂商ID和设备ID :usb_device_id  skel_table[ ]

2     注册设备ID, 到usb核:MODULE_DEVICE_TABLE(usb, skel_table)

3     声明USB设备拥有资源的结构体

这个结构体的名字有开发人员自定义,它描述的是该驱动拥有的所有资源及状态:

struct usb_skel {

    struct usb_device    *udev;            /* the usb device for this device */ 该设备的usb_device 指针  制造商 ID  产品ID等等

    struct usb_interface    *interface; /* the interface for this device */ 接口

    struct semaphore    limit_sem;        /* limiting the number of writes in progress */  数据共享 ->竞态/并发    信号量  防止竞态发生

  struct usb_anchor submitted;/* in case we need to retract our submissions *

   unsigned char *bulk_in_buffer;/* the buffer to receive data */ 接送数据缓冲

   size_t  bulk_in_size;  /* the size of the receive buffer */    接受缓冲大小

    __u8   bulk_in_endpointAddr;  /* the address of the bulk in endpoint */

  __u8  bulk_out_endpointAddr;    /* the address of the bulk out endpoint */   批量输入、输出  8位 端点 地址

 int            errors; /* the last request tanked */

 int            open_count;        /* count the number of openers */

 spinlock_t        err_lock;        /* lock for errors */

 struct kref        kref;                            //内核引用的计数器

     struct mutex   io_mutex;/* synchronize I/O with disconnect */  同步 IO

};   

4     static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id) 需要完成的(在设备被插入时调用):1.在堆上声明一个usb_skl 的结构体,初始化各配置参数;2.从传入的interface中提取端点信息保存到usb_skl 结构体中;3.使用usb_set_intfdata(interface, dev)将usb_skl结构体中的各种信息保存到interface 中,方便以后访问。4.注册该设备到USB核心;

5     static void Skel_disconnect(struct usb_interface *interface)(设备被拔出时调用)。 1.usb_setintfdata(interface, NULL)清除interface 中保存的设备信息。2.注销USB设备3.清除usb_skel结构体中的信息。

6     声明一个usb_device 变量skel_driver初始化其.name .probe .disconnect 和.id_table

7     Open 通过1.interface = usb_find_interface(&skel_driver, subminor); 获取interface 信息;2.通过dev = usb_get_intfdata(interface);获取usb_skel 结构体。3.判断设备是否已经被打开,打开:retval = usb_autopm_get_interface(interface);未被:file->private_data = dev;

8     Read 1.通过dev = (struct usb_skel *)file->private_data; 获取usb_skel结构体;2.通过       retval=usb_bulk_msg(dev->udev,usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),dev->bulk_in_buffer,min(dev->bulk_in_size, count), &bytes_read, 10000);向读入的端点发送读数据请求 把数据读入dev->bulk_in_buffer 中;3.复制数据到用户空间;copy_to_user

9     Write 1.设定实际要写入的个数size_t writesize = min(count, (size_t)MAX_TRANSFER);2.获取usb_skel dev = (struct usb_skel *)file->private_data; 3.创建urb 结构urb = usb_alloc_urb(0, GFP_KERNEL); 4.为urb包含的数据分配DMA空间 buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma); 5.将用户空间的数据                                                                                                                                                                                                                                                                                                                            复制进内核 copy_from_user(buf, user_buffer, writesize);6.封装urb为bulk_urb 注册回调函数(1) usb_fill_bulk_urb(urb,dev->udev,usb_sndbulkpipe(dev->udev,dev->bulk_out_endpointAddr),buf, writesize,skel_write_bulk_callback,dev);(2)urb->transfer_flags|=URB_NO_TRANSFER_DMA_MAP;(3)usb_anchor_urb(urb, &dev->submitted); 7.将urb提交到USB中心retval = usb_submit_urb(urb, GFP_KERNEL); 8.释放urb usb_free_urb(urb);

10               Write_callback 1.判断返回状态;2.释放urb的buf,usb_buffer_free(urb->dev, urb->transfer_buffer_length,urb->transfer_buffer, urb->transfer_dma);

11               通过各种usbclass来匹配不同的USB设备。

 

阅读(848) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~