最近完成了一个与MINI2440 USB通讯的程序, 感觉整个过程还是比较简单的,在这里记录下来. 以下过程是基于linux-2.6.32.2-mini2440-20110413来进行的.
MINI2440里的驱动程序是在论坛里有人发的zebra_mouse的基础上改进过来的, 是基于gadget的驱动程序。 不过那个程序只有读数据的:即MINI2440发送数据到主机, 不能写数据到MINI2440里.
更改起来也比较容易, 参考gadget下的printer的驱动,就可以很轻松的完成.
实际的过程就是printer里的read, zebra_mouse_ioctl两部分加到zebra_mouse里去
然后添加相关的变量及程序段就可以了.
接下来是比较关键的一步, 就是更改USB的配置.
以前看USB入门的时候, 总会要求去看USB协议. 这是个好办法, 但估计会有80%的人跟我一样,看的一头雾水,还不知道怎么回事. 这绝对是个误区.
后来通过一些实际的程序, 才知道,学习USB可以不用从那部分开始, 从一些现有的程序上去改, 反到更快, 只要知道更改哪些就好了 USB麻烦的地方也就是需要知道改哪些. 其实可以通过一些USB软件,如USBlyzer来查看就行了..
针对这个zebra_mouse程序, 我需要的实现的功能是上位机能发送/读取MINI2440中的数据. 所以要更改的只是设置到进与出就好了。
USB的数据是通过endpoint来传输的, 所以对zebra_mouse 的更改就是更改endpoint就可以了.
原程序中只有EP0, 将数据输出到上位机, 程序如下:
static struct usb_endpoint_descriptor fs_ep_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = __constant_cpu_to_le16(2),
.bInterval = 32, // frames -> 32 ms
};
关键的参数有
bEndpointAddress = USB_DIR_IN,
bmAttributes = USB_ENDPOINT_XFER_INT,
wMaxPacketSize = __constant_cpu_to_le16(2),
分别对应的是数据输入(上位机到MINI2440), 中断传输, 以及包长度.
我更改为:
static struct usb_endpoint_descriptor fs_ep_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = __constant_cpu_to_le16(64),
.bInterval = 32, // frames -> 32 ms
};
只更改了包长度. 具体为什么是64? 估计在USB协议中能找到.
另外还需要加入一个用来数据输出的(MINI2440到上位机的) EP,
static struct usb_endpoint_descriptor fs_ep_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_INT,
.wMaxPacketSize = __constant_cpu_to_le16(64),
.bInterval = 32, // frames -> 32 ms
};
这样就ok了, 是不是很简单? 不过还有两点没完成
更改完EP后, 还需要对USB接口描述进行修改. 这部分其实就是告诉上位机, 我这个USB设备是什么东西..
要改的地方也很简单. 原文是:
static struct usb_interface_descriptor intf_desc = {
.bLength = 0x09,
.bDescriptorType = 0x04,//USB_DT_INTERFACE,
.bInterfaceNumber = 0x00,//DEV_CONFIG_VALUE,
.bNumEndpoints =
0x01, .bInterfaceClass =
0x03,//USB_CLASS_HID,
.bInterfaceSubClass = 0x00, /* Printer Sub-Class */
.bInterfaceProtocol = 0x00, /* Bi-Directional */
.iInterface = 0x00
};
更改为
static struct usb_interface_descriptor intf_desc = {
.bLength = 0x09,
.bDescriptorType = 0x04,//USB_DT_INTERFACE,
.bInterfaceNumber = 0x00,//DEV_CONFIG_VALUE,
.bNumEndpoints =
0x02, .bInterfaceClass =
0x00,//USB_CLASS_HID,
.bInterfaceSubClass = 0x00, /* Printer Sub-Class */
.bInterfaceProtocol = 0x00, /* Bi-Directional */
.iInterface = 0x00
};
只改了红字部分, 不要被注释迷惑了.
更改的部分是告诉主机这次的USB设备有2个ep, 是普通设备. 不是HID.
接下来更改是PID和VID. 这两个数据有很重要的作用, 除了告诉上位机这个USB设备是谁的以外, 还关乎到了上位机的驱动程序.
原文是
#define PRINTER_VENDOR_NUM 0x8888 /* NetChip */
#define PRINTER_PRODUCT_NUM 0x7777 /* Linux-USB Printer Gadget */
我更改成了:
#define PRINTER_VENDOR_NUM 0x10c4 /* NetChip */
#define PRINTER_PRODUCT_NUM 0x0000 /* Linux-USB Printer Gadget */
0x10c4是Silicon Laboratories公司的ID号, 就是那个C8051F的单片机的那个.
改成这个原因主要是因为wndows的驱动程序是现成的. 我不用费劲的再去整什么DDK了.
多说一句, 只要Zebra_mouse里的PID, VID能跟inf文件里的pid, vid对上就行了, 不管描述的字符串是什么. 如果你发现更改了描述字符串还不行, 换个USB口或重装下驱动试下.
这样万事ok了, 编译一下, 然后发现很多错误. 原来是将printer里的代码复制过去后, 很多变量没改.
改好, 编译, 虽然还有警告, 但毕竟是编译通过了. 然后开始测试.
先加载驱动 s3c2410_udc.ko, 再加载zebra_mouse.ko, 然后运行usbmouse2,
看起来是不是和串口的调试有点类似?
至于PC端上位机的编写,可以在网上找一下这个:45785280C8051f(USB).rar, 是C8051的USB通讯例子, 用这个就行.
附件是相关的代码, 运行程序以及windows下的驱动.
zebro_mouse.rar (41 K) 下载次数:322 其他遗留问题:
编译有警告, 有机会再认真改吧.
测试程序在读写数据的时候是阻塞方式的, 不太好, 不知道有没有可能改成非阻塞的.