USB驱动结构分析

drivers\usb\usb-skeleton.c


module_usb_driver(skel_driver) //是一个宏
...
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
const char *mod_name)
-->driver_register(&new_driver->drvwrap.driver)
   -->other = driver_find(drv->name, drv->bus) //从USB总线上查找名字为"drv->name"的driver,如果查找到,说明已注册了这个Driver
   -->ret = bus_add_driver(drv)//将该Driver添加到总线上去,并最后调用driver->proble
      -->error = driver_attach(drv) //
         -->bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)//从device所指的总线上取每个device和driver的名字匹配
            -->while ((dev = next_device(&i)) && !error)
  error = __driver_attach(dev, data);
                      -->driver_probe_device(drv, dev)
                         -->ret = really_probe(dev, drv)
                            -->ret = drv->probe(dev)


ret = drv->probe(dev)已在int usb_register_driver(struct usb_driver *new_driver, struct module *owner,const char *mod_name)
函数里赋值,
new_driver->drvwrap.for_devices = 0;
new_driver->drvwrap.driver.name = (char *) new_driver->name;
new_driver->drvwrap.driver.bus = &usb_bus_type;
new_driver->drvwrap.driver.probe = usb_probe_interface;
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
所以调用ret = drv->probe(dev)最终调用new_driver->drvwrap.driver.probe = usb_probe_interface;
static int usb_probe_interface(struct device *dev)
-->struct usb_interface *intf = to_usb_interface(dev);
   id = usb_match_id(intf, driver->id_table); //id_table和给的intf进行匹配
   error = driver->probe(intf, id);
这里的driver是skel_driver,所以 driver->probe(intf, id)即是
static struct usb_driver skel_driver = {
.name = "skeleton",
.probe = skel_probe,
.disconnect = skel_disconnect,
.suspend = skel_suspend,
.resume = skel_resume,
.pre_reset = skel_pre_reset,
.post_reset = skel_post_reset,
.id_table = skel_table,
.supports_autosuspend = 1,
};里的skel_probe函数。
static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
-->dev = kzalloc(sizeof(*dev), GFP_KERNEL);
   ...
   init_completion(&dev->bulk_in_completion);//初始化完成量,当数据传送完后会回调该函数
   iface_desc = interface->cur_altsetting;//获取接口描述符
   for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
   {
    //这里主要是接口的端点是输入还是输出端点,然后为接口的每个端点设置传送的地址、buffer、size,
   }
   usb_set_intfdata(interface, dev);//interface->dev->priv = dev
   retval = usb_register_dev(interface, &skel_class);//注册USB driver,这里注册的是host的控制器driver,主要是将skel_class加入到struct usb_class_driver
数组里,然后创建设备名为skel_class->name后带次设备号的设备skel%d
这时各种初始化都完成,


这里总结一下一个驱动的三部曲:
1,分配一个设备结构体
2,各种初始化
   1、结构体里的变量初始化,信号量,完成量,自旋锁,
   2、硬件的初始化,开始的时候可能需要出示一些寄存器,比如中断等
3.注册


接下来就是驱动必须的实现的open、read、write、ioctrl、close等等
使用一个driver,必须先open,用户open-->文件系统的open(file_open)-->driver的open
static int skel_open(struct inode *inode, struct file *file)
-->subminor = iminor(inode)//从节点中获取次设备号
   interface = usb_find_interface(&skel_driver, subminor);//根据次设备号和skel_driver查找接口interface
   dev = usb_get_intfdata(interface)//获取struct usb_skel 结构
   kref_get(&dev->kref)//这里kref->refcount++,以免后面的还有人在调用这个设备的时候,其他人去close这个设备
   file->private_data = dev;//任何一个driver在open的最后都必须把自己定义的struct结构体传送给file->private_data,供后面read/write等使用


static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
-->dev = file->private_data //o取pen函数里赋的值,在read write ioctrl等每次用的时候都要首先取自己私有的结构体
   rv = mutex_lock_interruptible(&dev->io_mutex)//获取互斥锁,避免多个用户一起读
   if (ongoing_io) //如果还在进行读操作
   {
    ...
    rv = wait_for_completion_interruptible(&dev->bulk_in_completion) //等待传输完成,可以被中断
    ev->processed_urb = 1 //如果传输完成,置为ev->processed_urb
   }
   if (!dev->processed_urb) //第一次传输就会调用这里
   {
    ...
    wait_for_completion(&dev->bulk_in_completion) //等待传输完成,不能被中断
   }
   if (dev->bulk_in_filled)//第一次读的时候bulk_in_filled = 0,所以不会走这里,这里有个疑点,就是不知道什么时候能走这里
   {
    size_t available = dev->bulk_in_filled - dev->bulk_in_copied;//buffer里还有多少数据没有读完
    ...
    rv = skel_do_read_io(dev, count);//当前缓冲区没有数据,需要执行I/O操作来填充URB对应的缓冲区,然后
                                     //retry,进行读操作


   }


static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos)
{
   if (!(file->f_flags & O_NONBLOCK)) //判断是否为非阻塞方式,如果在读写文件的时候没有指定
   //读写方式,那么默认的方式就是阻塞的方式
   ...
   urb = usb_alloc_urb(0, GFP_KERNEL);//创建urb并初始化为0
   buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,
&urb->transfer_dma);//最终是运用dma_alloc_coherent来分配一块内存,避免内存和cache不一致的问题
   if (copy_from_user(buf, user_buffer, writesize))//将要拷贝的数据user_buffer copy到buf里
   mutex_lock(&dev->io_mutex)//上锁,避免设备被其他的占用或拔掉
   usb_fill_bulk_urb(urb, dev->udev,
 usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
 buf, writesize, skel_write_bulk_callback, dev); //出示化urb,为传输总准备
   retval = usb_submit_urb(urb, GFP_KERNEL);//将数据传输到设备,
   usb_free_urb(urb);//释放申请的urb buffer
}

















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值