一片冰心在玉壶

那时我们有梦,关于文学,关于爱情,关于穿越世界的旅行, 如今我们深夜饮酒,杯子碰到一起,都是梦破碎的声音. 交往都是初逢,爱情都在心里,往事都在梦中, 希望都带着注释,信仰都带着呻吟. 总有善意的光逃避现世的繁琐而寻找片刻的安宁, 也许,就是你凝视这里的眼睛

博客园 首页 联系 订阅 管理

      最近刚上的项目,一光学仪器。用的终端是海洋光学的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驱动全部搞定。希望多初学的有点帮助

 

 

posted on 2011-12-16 17:14  Sankye  阅读(2319)  评论(0编辑  收藏  举报