linux 2.4内核下自定义USB设备驱动编写

      最近刚上的项目,一光学仪器。用的终端是海洋光学的USB2000+光谱仪。他提供的只有PC上的驱动及开发包。WINCE下的还要收费。400刀!美国的JB公司太JB黑了!我打电话向他们要了个DATASHEET。一看才发现它可通过串口,I2C ,SPI接口来通讯。试了下串口,很多指令不对。没办法只得找他们。给我发一份串口操作的WORD文档。。。试了后感觉有点慢,1S才可以读一次数据,而且操作繁琐!看他说明里有USB协议。雨似乎,就想在LINUX下实现它。

     由于本人对LINUX下的USB没搞过,以前也只搞个CE下的USB鼠标,感觉无从下手。看了看内核的代码,谷哥了下。发现drivers/usb/usb-skeleton.c框架文件。2.6的和2.4的差别很大,但基本思想是一样的。我用的是2.4,没有2.6的通俗易懂!(LINUX内核http://oss.org.cn/kernel-book/比较好)

    usb-skeleton.c里的代码写得很详细了。第一眼看上去,感觉太简单,像使用串口一样!其实也就这样了!关键就是那几个数据结构!

    对于其代码分析,网上太多文章了。我这记录下我在修改过程中遇到的问题及解决办法!

 1.首先出现的问题是无法自动在/DEV下创建设备文件节点,源代码如下

 

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

devfs_register 文件的定义如下:

devfs_handle_t devfs_register(devfs_handle_t dir, const char *name,  unsigned int flags,   unsigned int major, unsigned int minor, umode_t mode, void *ops, void fo);

 

其中devfs_handle_t表示Devfs的句柄(一个结构类型),每个参数的含义如下:

   

dir : 我们要创建的文件所在的Devfs的句柄。NULL意味着这是Devfs的根,即 /dev。

flags :设备文件系统的标志,缺省值为DEVFS_FL_DEFAULT。

major : 主设备号,普通文件不需要这一参数。

minor : 次设备号, 普通文件也不需要这一参数

mode : 缺省的文件模式(包括属性和许可权)。

ops : 指向  file_operations 或 block_device_operations结构的指针

info : 任意一个指针,这个指针将被写到file结构的private_data域

 

他的作用是登记设备的入口点,我跟踪后发现返回的是0,没有起到它的作用。我直接用  register_chrdev();来注册字符设备!

register_chrdev( 181" myusb ", &skel_fops);

devfs_register的源代码在2.4.28里我找不到,有人知道为什么吗?

USB_MAJOR 是180.我的设备直接用181,这样不冲突

次设备号怎么办?如果写0,是注册不成功的。

代码里有:

#define USB_SKEL_MINOR_BASE 192 

USB_SKEL_MINOR_BASE + dev->minor

我手动:mknod myusb c  181 192

搞定!

在应用程序里可以OPEN,READ,WRITE了!

2.USB真的跟操作串口一样,直接填充你的命令到代码里就可以!在skel_probe里面把你要操作的端点提出来,记下他们的地址。在read,write里写与发命令就可以!

3 批量传进大于包的最大字节怎么办?

    明天接着解决这个问题!

下班了!

接着写。。

昨天说到大于512字个节的包这个问题。其实很简单,把申请的空间直接变大就行。用URB接收数据。代码如下:

 

/* *
 *    skel_probe
 *
 *    Called by the usb core when a new device is connected that it thinks
 *    this driver might be interested in.
 
*/
static  void * skel_probe( struct usb_device *udev, unsigned  int ifnum,  const  struct usb_device_id *id)
{
     struct usb_skel *dev = NULL;
     struct usb_interface * interface;
     struct usb_interface_descriptor *iface_desc;
     struct usb_endpoint_descriptor *endpoint;
     int minor;
     int buffer_size;
     int i;
     char name[ 10];

     printk(KERN_ALERT  " Ocean USB insert OK\n "); 
     /*  See if the device offered us matches what we can accept  */
     if ((udev->descriptor.idVendor != USB_SKEL_VENDOR_ID) ||
        (udev->descriptor.idProduct != USB_SKEL_PRODUCT_ID)) {
         return NULL;
    }

     /*  select a "subminor" number (part of a minor number)  */
    down (&minor_table_mutex);
     for (minor =  0; minor < MAX_DEVICES; ++minor) {
         if (minor_table[minor] == NULL)
             break;
    }
     if (minor >= MAX_DEVICES) {
        info ( " Too many devices plugged in, can not handle this device. ");
         goto exit;
    }

     /*  allocate memory for our device state and intialize it  */
    dev = kmalloc ( sizeof( struct usb_skel), GFP_KERNEL);
     if (dev == NULL) {
        err ( " Out of memory ");
         goto exit;
    }
    memset (dev,  0x00sizeof (*dev));
    minor_table[minor] = dev;

     interface = &udev->actconfig-> interface[ifnum];

    init_MUTEX (&dev->sem);
    dev->udev = udev;
    dev-> interface =  interface;
    dev->minor = minor;
     /*  set up the endpoint information  */
     /*  check out the endpoints  */
    iface_desc = & interface->altsetting[ 0];
     for (i =  0; i < iface_desc->bNumEndpoints; ++i) {
        endpoint = &iface_desc->endpoint[i];
         if ((endpoint->bEndpointAddress &  0x80) &&
            ((endpoint->bmAttributes &  3) ==  0x02)&&
            (endpoint->bEndpointAddress== 0x82)) {
             /*  we found a bulk in endpoint  */
            dev->read_urb = usb_alloc_urb( 0);
             if (!dev->read_urb) {
                err( " No free urbs available ");
                 goto error;
            }
            buffer_size = endpoint->wMaxPacketSize;
            dev->bulk_in_size = buffer_size* 10;//这里申请的时候直接申请最大的
            dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
         //     dev->bulk_in_buffer = usb_buffer_alloc(dev, buffer_size, GFP_ATOMIC, &dev->data_dma); // test->data   
               dev->bulk_in_buffer = kmalloc (dev->bulk_in_size, GFP_KERNEL);
             if (!dev->bulk_in_buffer){    
                printk(KERN_ALERT  " usb read OK\n "); 
                     goto error;
                }
            FILL_BULK_URB(dev->read_urb, udev, 
                      usb_rcvbulkpipe(udev, 
                              endpoint->bEndpointAddress),
                      dev->bulk_in_buffer, buffer_size,
                      skel_write_bulk_callback, dev);
        }
        
         if (((endpoint->bEndpointAddress &  0x80) ==  0x00) &&
            ((endpoint->bmAttributes &  3) ==  0x02)) {
             /*  we found a bulk out endpoint  */
            dev->write_urb = usb_alloc_urb( 0);
             if (!dev->write_urb) {
                err( " No free urbs available ");
                 goto error;
            }
            buffer_size = endpoint->wMaxPacketSize;
            dev->bulk_out_size = buffer_size;
            dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
            dev->bulk_out_buffer = kmalloc (buffer_size, GFP_KERNEL);
             if (!dev->bulk_out_buffer) {
                err( " Couldn't allocate bulk_out_buffer ");
                 goto error;
            }
            FILL_BULK_URB(dev->write_urb, udev, 
                      usb_sndbulkpipe(udev, 
                              endpoint->bEndpointAddress),
                      dev->bulk_out_buffer, buffer_size,
                      skel_write_bulk_callback, dev);
        }
    }
     /*  initialize the devfs node for this device and register it  */
     // sprintf(name, "skel%d", dev->minor);
   
//  info ("name %s ", name);
    
// register_chrdev(181, "myusb", &skel_fops);
    
// dev->devfs = devfs_register( NULL, name, DEVFS_FL_DEFAULT,181,&skel_fops, NULL);
/*
    dev->devfs =devfs_register(NULL, "myusb",
                     DEVFS_FL_DEFAULT, 181,
                     USB_SKEL_MINOR_BASE + dev->minor,
                     S_IFCHR | S_IRUSR | S_IWUSR | 
                     S_IRGRP | S_IWGRP | S_IROTH, 
                     &skel_fops, NULL);
*/
     /*  let the user know what node this device is now attached to  */
    info ( " USB device %d  ", dev->devfs);
    info ( " USB Skeleton device now attached to USBSkel%d ", dev->minor);
     goto exit;    
error:
    skel_delete (dev);
    dev = NULL;

exit:
    up (&minor_table_mutex);
     return dev;
}

 

 read :

 

/* *
 *    skel_read
 
*/
static ssize_t skel_read ( struct file *file,  char *buffer, size_t count, loff_t *ppos)
{
     struct usb_skel *dev;
     int retval =  0;
    dev = ( struct usb_skel *)file->private_data;
    printk(KERN_ALERT  " usb read OK\n "); 
     /*  lock this object  */
    down (&dev->sem);
     /*  verify that the device wasn't unplugged  */
     if (dev->udev == NULL) {
        up (&dev->sem);
         return -ENODEV;
    }    
     /*  do an immediate bulk read to get data from the device  */
//     printk(KERN_ALERT "read inPD 0x%x\n", dev->bulk_in_endpointAddr); 
     /* retval = usb_bulk_msg (dev->udev,
                   usb_rcvbulkpipe (dev->udev, 0x82),
                   dev->bulk_in_buffer, dev->bulk_in_size,
                   &count, HZ*10);
*/
       FILL_BULK_URB(dev->read_urb, dev->udev, 
                      usb_rcvbulkpipe(dev->udev, 
                               0x82),
                      dev->bulk_in_buffer, dev->bulk_in_size,
                      skel_write_bulk_callback, dev);
    
     /*  if the read was successful, copy the data to userspace  */
    retval = usb_submit_urb(dev->read_urb);
     if (!retval) {
         if (copy_to_user (buffer, dev->bulk_in_buffer, count))
            retval = -EFAULT;
         else
            retval = count;
    }
     /*  unlock the device  */
    up (&dev->sem);    
     return retval;
}

 

到这里,USB驱动全部搞定。希望多初学的有点帮助

 

 

转载于:https://www.cnblogs.com/sankye/articles/2290469.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值