新闻中心

EEPW首页>嵌入式系统>设计应用> 嵌入式Linux下USB驱动程序的设计

嵌入式Linux下USB驱动程序的设计

作者: 时间:2013-10-08 来源:网络 收藏

  (2)probe()函数

  probe()函数的编写格式为:static void * skel_probe(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id);需要确认插入的设备是否可以被接受,如果不接受,或者在初始化的过程中发生任何错误,probe()函数返回一个NULL值。否则返回一个含有设备状态的指针,通过这个指针,就可以访问所有结构中的回调函数。

  在里,最后一点是要注册devfs(设备文件系统)。首先创建一个缓冲用来保存那些被发送给设备的数据和那些从设备上接受的数据,并为设备传输创建一个请求块(URB)以向设备写入数据,同时urb 被初始化,然后在devfs子系统中注册设备,允许devfs用户访问USB的设备。注册过程如下:

  /* initialize the devfs node for this device and register it */

  sprintf(name, "skel%d", skel->minor);

  skel->devfs = devfs_register (usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, USB_SKEL_MINOR_BASE + skel->minor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, skel_fops, NULL);

  如果devfs_register函数失败, devfs子系统会将此情况报告给用户。如果设备从USB总线拔掉,设备指针会调用disconnect 函数。驱动程序就需要清除那些被分配了的所有私有数据、关闭urbs,并且从devfs上注销调自己。调用函数的格式为:

  /* remove our devfs node */

  devfs_unregister(skel->devfs);

  现在,skeleton驱动就已经和设备绑定上了,任何用户态程序要操作此设备都可以通过file_operations结构所定义的函数进行了。

  (3)open()、write()和read()函数

  首先,要打开此设备。在open()函数中MODULE_INC_USE_COUNT 宏是一个关键,它起到一个计数的作用,有一个用户态程序打开一个设备,计数器就加1。例如,以模块方式加入一个驱动,若计数器不为零,就说明仍然有用户程序在使用此驱动,这时候,就不能通过rmmod命令卸载驱动模块了。

  /* increment our usage count for the module */

  MOD_INC_USE_COUNT;

  ++skel->open_count;

  /* save our object in the file's private structure */

  file->private_data = skel;

  当open完设备后,read()、write()函数就可以收、发数据了。

  read()函数首先从open()函数中保存的fi。

  Write()函数和read()函数是完成驱动对读写等操作的响应。在skel_write中,一个FILL_BULK_URB函数,就完成了urb 系统callbak和的skel_write_bulk_callback之间的联系。注意skel_write_bulkcallback是中断方式,所以要注意时间不能太久,本程序中它就只是报告一些urb的状态等。 read 函数与write 函数稍有不同在于:程序并没有用urb 将数据从设备传送到驱动程序,而是用usb_bulk_msg 函数代替,这个函数能够不需要创建urbs 和操作urb函数的情况下,来发送数据给设备,或者从设备来接收数据。调用usb_bulk_msg函数并传到一个存储空间,用来缓冲和放置驱动收到的数据,若没有收到数据表示失败并返回一个错误信息。

  usb_bulk_msg函数:当对usb设备进行一次读或者写时,usb_bulk_msg 函数是非常有用的; 然而, 当需要连续地对设备进行读/写时,应建立一个自己的urbs,同时将urbs 提交给USB子系统。

  skel_disconnect函数:当释放设备文件句柄时,这个函数会被调用。

  MOD_DEC_USE_COUNT宏也会被调用到(和MOD_INC_USE_COUNT刚好对应,它减少一个计数器),首先确认当前是否有其他的程序正在访问这个设备,如果是最后一个用户在使用,可以关闭任何正在发生的写,操作如下:

  /* decrement our usage count for the device */

  --skel->open_count;

  if (skel->open_count = 0) {

  /* shutdown any bulk writes that might be

  going on */

  usb_unlink_urb (skel->write_urb);

  skel->open_count = 0;

  }

  /* decrement our usage count for the module */

  MOD_DEC_USE_COUNT;

  USB设备可以在任何时间点从系统中取走,即使程序目前正在访问它。USB驱动程序必须要能够很好地处理解决此问题,它需要能够切断任何当前的读写,同时通知用户空间程序:USB设备已经被取走。

  2.设计实例

  下面通过介绍键盘飞梭驱动程序的实例来让读者更好的理解USB驱动程序的工作原理,实现代码如下:

  /*需要的头文件*/

  #include linux/kernel.h>

  #include linux/slab.h>

  #include linux/module.h>

  #include linux/input.h>

  #include linux/init.h>

  #include linux/usb.h>

  #include linux/kbd_ll.h>

  /* 驱动程序版本信息*/

  #define DRIVER_VERSION ""

  #define DRIVER_AUTHOR " TGE HOTKEY "

  #define DRIVER_DESC "USB HID Tge hotkey driver"

  #define USB_HOTKEY_VENDOR_ID 0x07e4

  #define USB_HOTKEY_PRODUCT_ID 0x9473

  /*厂商和产品ID信息就是/proc/bus/usb/devices中看到的值,通过cat/proc/bus/usb/devices得到当前系统探测到的USB总线上的设备信息。它包括Vendor、ProdID、Product等*/

  MODULE_AUTHOR( DRIVER_AUTHOR );

  MODULE_DESCRIPTION( DRIVER_DESC );

  /*此结构来自内核中drivers/usb/usbkbd.c*/

  struct usb_kbd {

  struct input_dev dev;

  struct usb_device *usbdev;

  unsigned char new[8];

  unsigned char old[8];

  struct urb irq, led;

  struct usb_ctrlrequest dr;

  unsigned char leds, newleds;

  char name[128];

  int open;

  };

  static void usb_kbd_irq(struct urb *urb) /*urb为USB请求块*/

  {

  struct usb_kbd *kbd = urb->context;

  int *new;

  new = (int *) kbd->new;

  if(kbd->new[0] == (char)0x01)

  {

  if(((kbd->new[1]>>4)0x0f)!=0x7)

  {

  handle_scancode(0xe0,1);

  handle_scancode(0x4b,1);

  handle_scancode(0xe0,0);

  handle_scancode(0x4b,0);

  }

linux操作系统文章专题:linux操作系统详解(linux不再难懂)

linux相关文章:linux教程




评论


相关推荐

技术专区

关闭