当前位置:   article > 正文

usb驱动开发——写一个usb驱动_usb 驱动 开发 简单实例

usb 驱动 开发 简单实例

本篇博客的内核基于linux2.6.22

先深入分析内核中自带usb鼠标驱动

入口函数注册一个usb_driver

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,
};

static int __init usb_mouse_init(void)
{
	int retval = usb_register(&usb_mouse_driver);
	if (retval == 0)
		info(DRIVER_VERSION ":" DRIVER_DESC);
	return retval;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

当driver和device匹配成功后会调用probe函数

struct usb_mouse {
	char name[128];
	char phys[64];
	struct usb_device *usbdev;
	struct input_dev *dev;
	struct urb *irq;

	signed char *data;
	dma_addr_t data_dma;
};

static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	/*根据usb_interface 来获取usb_device */
	struct usb_device *dev = interface_to_usbdev(intf);
	struct usb_host_interface *interface;
	/*端点是USB通信的最基本方式*/
	struct usb_endpoint_descriptor *endpoint;
	struct usb_mouse *mouse;
	struct input_dev *input_dev;
	int pipe, maxp;
	int error = -ENOMEM;
	/*从usb_interface 获取usb_host_interface */
	interface = intf->cur_altsetting;

	if (interface->desc.bNumEndpoints != 1)
		return -ENODEV;
	/*获取endpoint*/
	endpoint = &interface->endpoint[0].desc;
	if (!usb_endpoint_is_int_in(endpoint))
		return -ENODEV;

	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
	maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
	
	mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
	input_dev = input_allocate_device();
	if (!mouse || !input_dev)
		goto fail1;
	
	mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
	if (!mouse->data)
		goto fail1;

	mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
	if (!mouse->irq)
		goto fail2;

	mouse->usbdev = dev;
	mouse->dev = input_dev;

	if (dev->manufacturer)
		strlcpy(mouse->name, dev->manufacturer, sizeof(mouse->name));

	if (dev->product) {
		if (dev->manufacturer)
			strlcat(mouse->name, " ", sizeof(mouse->name));
		strlcat(mouse->name, dev->product, sizeof(mouse->name));
	}

	if (!strlen(mouse->name))
		snprintf(mouse->name, sizeof(mouse->name),
			 "USB HIDBP Mouse %04x:%04x",
			 le16_to_cpu(dev->descriptor.idVendor),
			 le16_to_cpu(dev->descriptor.idProduct));

	usb_make_path(dev, mouse->phys, sizeof(mouse->phys));
	strlcat(mouse->phys, "/input0", sizeof(mouse->phys));

	input_dev->name = mouse->name;
	input_dev->phys = mouse->phys;
	usb_to_input_id(dev, &input_dev->id);
	input_dev->dev.parent = &intf->dev;
	/*设置是什么类型的事件*/
	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
	input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
	input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
	input_dev->relbit[0] |= BIT(REL_WHEEL);

	input_set_drvdata(input_dev, mouse);

	input_dev->open = usb_mouse_open;
	input_dev->close = usb_mouse_close;

	usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
			 (maxp > 8 ? 8 : maxp),
			 usb_mouse_irq, mouse, endpoint->bInterval);
	mouse->irq->transfer_dma = mouse->data_dma;
	mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

	error = input_register_device(mouse->dev);
	if (error)
		goto fail3;

	usb_set_intfdata(intf, mouse);
	return 0;

fail3:	
	usb_free_urb(mouse->irq);
fail2:	
	usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
fail1:	
	input_free_device(input_dev);
	kfree(mouse);
	return error;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107

这个函数可以说是mouse驱动的主体,对于这个函数中,我们重点关注两个内容
1、usb_fill_int_urb 函数
2、在这里并没有定义全局变量,那是如何在不同函数中实现信息传递的呢?可以深入地分析并学习一下

/**
	不必去分析这个函数底层是如何实现的,我也做不到,主要是分析如何使用这个函数
	这个函数很像request_irq,向内核注册一个中断函数 看下这个函数的英文注释
 * usb_fill_int_urb - macro to help initialize a interrupt urb 
 * @urb: pointer to the urb to initialize.
 * 第一个参数是urb usb request block 
 * @dev: pointer to the struct usb_device for this urb.
 * the endpoint pipe信息源res
 * @pipe: the endpoint pipe
 * transfer_buffer信息dest
 * @transfer_buffer: pointer to the transfer buffer
 * @buffer_length: length of the transfer buffer
 * @complete_fn: pointer to the usb_complete_t function
 * @context: what to set the urb context to.
 * @interval: what to set the urb interval to, encoded like
 *	the endpoint descriptor's bInterval value.
 *
 * Initializes a interrupt urb with the proper information needed to submit
 * it to a device.
 *
 * Note that High Speed and SuperSpeed interrupt endpoints use a logarithmic
 * encoding of the endpoint interval, and express polling intervals in
 * microframes (eight per millisecond) rather than in frames (one per
 * millisecond).
 *
 * Wireless USB also uses the logarithmic encoding, but specifies it in units of
 * 128us instead of 125us.  For Wireless USB devices, the interval is passed
 * through to the host controller, rather than being translated into microframe
 * units.
 */
static inline void usb_fill_int_urb(struct urb *urb,
				    struct usb_device *dev,
				    unsigned int pipe,
				    void *transfer_buffer,
				    int buffer_length,
				    usb_complete_t complete_fn,
				    void *context,
				    int interval)
struct urb *urb的设置
mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
struct usb_device *dev
struct usb_device *dev = interface_to_usbdev(intf);
unsigned int pipe
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
void *transfer_buffer
mouse->data = usb_alloc_coherent(dev, 8, GFP_ATOMIC, &mouse->data_dma);
void *context
mouse
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

现在来分析第二个问题
可以想象得到在irq函数中,也就是complete_fn中,必然会用mouse,因为input_dev和装有信息的data都在mouse中,而mouse又不是全局变量,那我们是不是要以传参的方式传递给complete_fn函数呢?显然不行,complete_fn属于内核已经存在的一个通用型接口,它的传参是urb结构体,而mouse是我们自己定义的,肯定不可以用参数传递的方式。
所以我们可以根据以往从file的private_data获得启示,看下urb有没有void *成员
发现有两个

struct urb {

	void *transfer_buffer;		/* (in) associated data buffer */

	void *context;			/* (in) context for completion */

};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

transfer_buffer我们已经用来当作dest缓冲区了,所以只能使用context
事实上也确实是这样来处理的

static inline void usb_fill_control_urb(struct urb *urb,
					struct usb_device *dev,
					unsigned int pipe,
					unsigned char *setup_packet,
					void *transfer_buffer,
					int buffer_length,
					usb_complete_t complete_fn,
					void *context)
{
	urb->dev = dev;
	urb->pipe = pipe;
	urb->setup_packet = setup_packet;
	urb->transfer_buffer = transfer_buffer;
	urb->transfer_buffer_length = buffer_length;
	urb->complete = complete_fn;
	/*在我们的mouse驱动中,context是指向mouse的指针*/
	urb->context = context;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

这是处理complete_fn函数,而对于这个驱动还有一个disconnect函数
它的传参是usb_interface,所以我们来看下它有哪些可以用来保存mouse的void *
然而我们发现并没有,这怎么办
我们可以找它的成员结构体中是否有void 指针

struct device {
	void		*platform_data;	/* Platform specific data, device
					   core doesn't touch it */
	struct device_private	*p;
};

struct device_private {
	struct klist klist_children;
	struct klist_node knode_parent;
	struct klist_node knode_driver;
	struct klist_node knode_bus;
	struct list_head deferred_probe;
	void *driver_data;
	struct device *device;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

这个并不行,因为注释已经说明了platform_data是专门给Platform specific data所使用的

usb_set_intfdata(intf, mouse);
static inline void usb_set_intfdata(struct usb_interface *intf, void *data)
{
	dev_set_drvdata(&intf->dev, data);
}
int dev_set_drvdata(struct device *dev, void *data)
{
	int error;

	if (!dev->p) {
		error = device_private_init(dev);
		if (error)
			return error;
	}
	dev->p->driver_data = data;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

现在我们来看下complete_fn

static void usb_mouse_irq(struct urb *urb)
{
	struct usb_mouse *mouse = urb->context;
	signed char *data = mouse->data;
	struct input_dev *dev = mouse->dev;
	int status;
	/*首先判断urb的状态位,如果没有设置(为0),则为成功*/
	switch (urb->status) {
	case 0:			/* success */
		break;
	case -ECONNRESET:	/* unlink */
	case -ENOENT:
	case -ESHUTDOWN:
		return;
	/* -EPIPE:  should clear the halt */
	default:		/* error */
		goto resubmit;
	}
	/*上报数据的设置,value就是我们从在probe函数中调用的usb_alloc_coherent申请到的缓冲区
	*	data[0] data[1]等和坐标点击之间的关系,这需要对usb通信做进一步分析才可以理解
	*	但是可以从这个函数中看出,一次是上传了所有相关的数据
	*/
	input_report_key(dev, BTN_LEFT,   data[0] & 0x01);
	input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);
	input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
	input_report_key(dev, BTN_SIDE,   data[0] & 0x08);
	input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);

	input_report_rel(dev, REL_X,     data[1]);
	input_report_rel(dev, REL_Y,     data[2]);
	input_report_rel(dev, REL_WHEEL, data[3]);

	input_sync(dev);
resubmit:
	status = usb_submit_urb (urb, GFP_ATOMIC);
	if (status)
		dev_err(&mouse->usbdev->dev,
			"can't resubmit intr, %s-%s/input0, status %d\n",
			mouse->usbdev->bus->bus_name,
			mouse->usbdev->devpath, status);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

现在看下我们自己写的程序,我这里仅仅只列出probe函数和complete函数

struct usbmouse_as_key {
	struct usb_device *usbdev;
	struct input_dev *dev;
	struct urb *irq;
	int len;

	signed char *data;
	dma_addr_t data_dma;
};


static void usbmouse_as_key_irq(struct urb *urb)
{
	struct usbmouse_as_key *usbmouse_as_key_t = urb->context;
	signed char *data = usbmouse_as_key_t->data;
	struct input_dev input_dev = usbmouse_as_key_t->dev;
	int status;
	
	switch (urb->status) {
	case 0:			/* success */
		break;
	case -ECONNRESET:	/* unlink */
	case -ENOENT:
	case -ESHUTDOWN:
		return;
	/* -EPIPE:  should clear the halt */
	default:		/* error */
		goto resubmit;
	}

	input_event(input_dev, EV_KEY, KEY_L, (data[0] & (1<<0)) ? 1 : 0);
	input_event(input_dev, EV_KEY, KEY_S, (data[0] & (1<<1)) ? 1 : 0);
	input_event(input_dev, EV_KEY, KEY_ENTER, (data[0] & (1<<2)) ? 1 : 0);
	input_sync(input_dev);

resubmit:
	status = usb_submit_urb(urb, GFP_KERNEL);	
	
}

static int usbmouse_as_key_probe(struct usb_interface *iface, const struct usb_device_id *id)
{
	struct usb_device *dev = interface_to_usbdev(iface);
	struct usb_host_interface *interface;
	struct usb_endpoint_descriptor *endpoint;
	struct input_dev *input_dev;
	struct usbmouse_as_key *usbmouse_as_key_t;
	int pipe, len;

	interface = iface->cur_altsetting;
	endpoint = &interface->endpoint[0].desc;
	
	/*分配input_dev*/
	input_dev = input_allocate_device();

	usbmouse_as_key_t = kzalloc(sizeof(struct usbmouse_as_key), GFP_KERNEL);

	usbmouse_as_key_t->usbdev = dev;
	usbmouse_as_key_t->dev = input_dev;

	/*事件类型为按键事件和可重复按键事件*/
	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(usbmouse_as_key_t->dev);

	usbmouse_as_key_t->irq = usb_alloc_urb(0, GFP_KERNEL);
	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
	
	usbmouse_as_key_t->len = endpoint->wMaxPacketSize;
	usbmouse_as_key_t->data = usb_buffer_alloc(dev, usbmouse_as_key_t->len, GFP_ATOMIC, &usbmouse_as_key_t->data_dma);

	usb_fill_int_urb(usbmouse_as_key_t->irq, dev, pipe, usbmouse_as_key_t->data, usbmouse_as_key_t->len, usbmouse_as_key_irq, usbmouse_as_key_t,endpoint->bInterval);
	usbmouse_as_key_t->irq->transfer_dma = usbmouse_as_key_t->data_dma;
	usbmouse_as_key_t->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
		
	usb_set_intfdata(iface, usbmouse_as_key_t);
	return 0;
	
}

static struct usb_device_id usbmouse_as_key_id_table [] = {
	{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
		USB_INTERFACE_PROTOCOL_MOUSE) },
	{ }						/* Terminating entry */
};

static struct usb_driver usbmouse_as_key_driver = {
	.name =			"usbmouse_as_key",
	.probe =		usbmouse_as_key_probe,
	.disconnect =	usbmouse_as_key_disconnect,
	.id_table =		usbmouse_as_key_id_table,	
};

static int usbmouse_as_key_init(void)
{
	usb_register(&usbmouse_as_key_driver);
	return 0;
}

static void usbmouse_as_key_exit(void)
{
	usb_deregister(&usbmouse_as_key_driver);
}

module_init(usbmouse_as_key_init);
module_exit(usbmouse_as_key_exit);
MODULE_LICENSE("GPL");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/246802?site
推荐阅读
相关标签
  

闽ICP备14008679号