最近刚上的项目,一光学仪器。用的终端是海洋光学的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下创建设备文件节点,源代码如下
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();来注册字符设备!
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, 0x00, sizeof (*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驱动全部搞定。希望多初学的有点帮助