1.usb的描述符及其之间的关系
usb常用的描述符设备描述符(device descriptor),配置描述符(configuration descriptor),接口描述符(interface descriptor),端点描述符(endpoint descriptor)。
一个usb设备只有一个设备描述符。设备描述符里决定了该设备有多少种配置,每种配置有一个配置描述符;在每个配置描述符中又定义了该配置有多少个接口,每个接口都对应一个接口描述符,在每个接口描述符中又定义了该接口有多少个端点,每一个端点对应一个端点描述符
设备描述符主要记录的信息:USB协议版本号,设备类型,端点0的最大包大小,厂商ID和产品ID,设备版本号等
配置描述符主要记录的信息有:配置所包含的接口数,配置的编号,供电方式,是否支持远程唤醒,电流需求量等。
接口描述符主要记录的信息有:接口的编号,接口的端点数,接口所使用的类,子类,协议等
端点描述符:端点号及方向,端点的传输类型,最大包长度,查询时间间隔等
struct usb_device_descriptor {
__u8 bLength; //设备描述符的长度
__u8 bDescriptorType;
__le16 bcdUSB; //usb版本
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
__u8 bMaxPacketSize0; //端点0最大包
__le16 idVendor;
__le16 idProduct;
__le16 bcdDevice;
__u8 iManufacturer;
__u8 iProduct;
__u8 iSerialNumber;
__u8 bNumConfigurations;
} __attribute__ ((packed));
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumInterfaces;
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} __attribute__ ((packed));
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} __attribute__ ((packed));
struct usb_endpoint_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress;
__u8 bmAttributes;
__le16 wMaxPacketSize;
__u8 bInterval; //查询时间间隔
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
2.设备识别(hub.c)
大致流程为:接上Usb设备后,会跳转到hub.c的hub_irq程序,唤醒khubd_wait->hub_thread->hub_events->hub_port_connnect_change->hub_port_init;
以上函数实现了给usb 分配新的端口号,并将端口告诉usb设备,获取设备的描述符,然后调用usb_new_device(device_add)向usb总线usb_bus_type注册设备。
用户利用usb_driver(usb_register)注册driver程序,当在usb总线上driver与device的id_table相同时,则相互匹配,可以用过driver实现对device的操作。
static void hub_port_connect_change(struct usb_hub *hub, int port1,
u16 portstatus, u16 portchange)
{
udev = usb_alloc_dev(hdev, hdev->bus, port1); //分配一个device
usb_set_device_state(udev, USB_STATE_POWERED); //device初始化
udev->speed = USB_SPEED_UNKNOWN;
udev->bus_mA = hub->mA_per_port;
udev->level = hdev->level + 1;
choose_address(udev); //给device分配端口号
status = hub_port_init(hub, udev, port1, i); //
status = usb_new_device(udev); }
static void choose_address(struct usb_device *udev)
{
devnum = find_next_zero_bit(bus->devmap.devicemap, 128, bus->devnum_next);
if (devnum >= 128) //从0-128寻找一个没有被占用的端口号,如果大于127,从0开始找
devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1);}
hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
int retry_counter)
{
dev_info (&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
udev->bus->controller->driver->name, udev->devnum); //刚接上usb设备时,打印处速度,usb类型以及端口号
r = usb_control_msg(udev, usb_rcvaddr0pipe(), //发送控制消息
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
USB_DT_DEVICE << 8, 0,
buf, GET_DESCRIPTOR_BUFSIZE,
USB_CTRL_GET_TIMEOUT);
retval = hub_set_address(udev); //把端口号告诉usb设备
retval = usb_get_device_descriptor(udev, 8); //读取描述符,第一次读取8字节,知道总长以后,下面再全部都出来
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);}
2440接上usb设备以后,会打印出 new full speed USB device using s3c2410-ohci and address 3
int usb_new_device(struct usb_device *udev)
{
err = usb_get_configuration(udev);
err = device_add(&udev->dev); //向usb总线注册
}
3.driver注册 (以usbmouse.c为例) 对于不同的usb设备,具体的硬件操作在此实现,hub实现设备的识别以及注册工作
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
{ } /* Terminating entry */
};
static struct usb_driver usb_mouse_driver = {
.name = "usbmouse",
.probe = usb_mouse_probe,
.disconnect = usb_mouse_disconnect,
.id_table = usb_mouse_id_table, //表示所支持的usb设备类型
};
static int __init usb_mouse_init(void)
{
int retval = usb_register(&usb_mouse_driver); //向usb总线注册driver
if (retval == 0)
info(DRIVER_VERSION ":" DRIVER_DESC);
return retval;
}
当接上driver所支持的设备(device)以后,会跳转到driver的probe函数里,在probe实现usb硬件相关的操作,用总线驱动进行usb收发。
4.usb总线(driver.c(/drivers/usb/core))
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
const char *mod_name)
{ int retval = 0;
if (usb_disabled())
return -ENODEV;
new_driver->drvwrap.for_devices = 0;
new_driver->drvwrap.driver.name = (char *) new_driver->name;
new_driver->drvwrap.driver.bus = &usb_bus_type;
new_driver->drvwrap.driver.probe = usb_probe_interface;
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
retval = driver_register(&new_driver->drvwrap.driver);
if (retval)
goto out;
usbfs_update_special();
retval = usb_create_newid_files(new_driver);
if (retval)
goto out_newid;
pr_info("%s: registered new interface driver %s\n",
usbcore_name, new_driver->name);}
int usb_register_device_driver(struct usb_device_driver *new_udriver,
struct module *owner)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
new_udriver->drvwrap.for_devices = 1;
new_udriver->drvwrap.driver.name = (char *) new_udriver->name;
new_udriver->drvwrap.driver.bus = &usb_bus_type;
new_udriver->drvwrap.driver.probe = usb_probe_device;
new_udriver->drvwrap.driver.remove = usb_unbind_device;
new_udriver->drvwrap.driver.owner = owner;
retval = driver_register(&new_udriver->drvwrap.driver);
if (!retval) {
pr_info("%s: registered new device driver %s\n",
usbcore_name, new_udriver->name);
usbfs_update_special();
} else {
printk(KERN_ERR "%s: error %d registering device "
" driver %s\n",
usbcore_name, retval, new_udriver->name);
}
return retval;
}
int usb_match_device(struct usb_device *dev, const struct usb_device_id *id)
{
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
return 0;
/* No need to test id->bcdDevice_lo != 0, since 0 is never
greater than any unsigned number. */
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
(id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
(id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
(id->bDeviceClass != dev->descriptor.bDeviceClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
(id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
return 0;
return 1;
}
具体的usb通信是通过urb(usb请求块进行的):
1.数据传输三要素:
源:pipe=usb_rcvintpipe();
长度: len = endpoint->wMaxPacketSize;
目的: usb_buf= usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys); //创建一个DMA缓冲区
2.使用三要素:
分配一个urban: usb_alloc_urb
设置urb: usb_fill_int_urb,
mouse_urb->transfer_dma = usb_buf_phys;
mouse_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;提交urb: usb_submit_urb
下面附上一个usbmouse的程序:
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
struct input_dev *input_dev;
static char *usb_buf;
static int len;
static dma_addr_t usb_buf_phys;
struct urb *mouse_urb;
static void usb_mouse_irq(struct urb *urb)
{
int i;
static unsigned char pre_val;
if ((pre_val & (1<<0)) != (usb_buf[0] & (1<<0)))
{
/* 左键发生了变化 */
input_event(input_dev, EV_KEY, KEY_L, (usb_buf[0] & (1<<0)) ? 1 : 0);
input_sync(input_dev);
}
if ((pre_val & (1<<1)) != (usb_buf[0] & (1<<1)))
{
/* 右键发生了变化 */
input_event(input_dev, EV_KEY, KEY_S, (usb_buf[0] & (1<<1)) ? 1 : 0);
input_sync(input_dev);
}
if ((pre_val & (1<<2)) != (usb_buf[0] & (1<<2)))
{
/* 中键发生了变化 */
input_event(input_dev, EV_KEY, KEY_ENTER, (usb_buf[0] & (1<<2)) ? 1 : 0);
input_sync(input_dev);
}
pre_val = usb_buf[0];
/* 重新提交urb */
usb_submit_urb(mouse_urb, GFP_KERNEL);
}
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
int pipe;
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
input_dev = input_allocate_device();
set_bit(EV_KEY, input_dev->evbit);
set_bit(EV_REP, input_dev->evbit);
set_bit(KEY_L, input_dev->keybit);
set_bit(KEY_S, input_dev->keybit);
set_bit(KEY_ENTER, input_dev->keybit);
input_register_device(input_dev);
//数据传输三要素:源,长度,目的
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); //中断IN端点
len = endpoint->wMaxPacketSize;
usb_buf= usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys); //创建一个DMA缓冲区
//适用三要素:分配urb,设置,使用
mouse_urb= usb_alloc_urb(0, GFP_KERNEL);
usb_fill_int_urb(mouse_urb, dev, pipe, usb_buf,len, usb_mouse_irq, NULL, endpoint->bInterval); //初始化urb
mouse_urb->transfer_dma = usb_buf_phys;
mouse_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_submit_urb (mouse_urb, GFP_KERNEL);
printk("find usbmose\n");
/* printk("bcdUSB = %x\n", dev->descriptor.bcdUSB);
printk("bLength = %x\n", dev->descriptor.bLength);
printk("bDescriptorType = %x\n", dev->descriptor.bDescriptorType);
printk("idVendor = %x\n", dev->descriptor.idVendor);*/
return 0;
}
static void usb_mouse_disconnect(struct usb_interface *intf)
{
printk("disconnect usbmouse\n");
struct usb_device *dev = interface_to_usbdev(intf);
usb_kill_urb(mouse_urb);
usb_free_urb(mouse_urb);
usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
input_unregister_device(input_dev);
input_free_device(input_dev);
}
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
static struct usb_driver usb_mouse_driver = {
.name = "usbmouse",
.probe = usb_mouse_probe,
.disconnect = usb_mouse_disconnect,
.id_table = usb_mouse_id_table,
};
static int __init usb_mouse_init(void)
{
int retval = usb_register(&usb_mouse_driver);
return retval;
}
static void __exit usb_mouse_exit(void)
{
usb_deregister(&usb_mouse_driver);
}
module_init(usb_mouse_init);
module_exit(usb_mouse_exit);
MODULE_LICENSE("GPL");