usb总线

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");




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值