usb驱动的分析与编写

先看一下有关usb的介绍和接入usb的流程

在这里插入图片描述

驱动和app 和usb的连接

在这里插入图片描述
在usb设备总线里,把device放入usb_bus_type的dev列表
从ubs_bus_type的driver链表里取出usb_driver
把usb_interface和usb_driver的id_table比较
如果能匹配调用driver的probe

怎么写usb_driver usb 设备驱动程序

在这里插入图片描述

如果我们使用鼠标,那就像是输入子系统

所以我们再匹配成功时候调用的probe实现我们的输入子系统函数
先写出入口和出口函数,并且加入协议

分配设置一个 usb_driver 结构体

在这里插入图片描述
打开别人写的usb鼠标文件进行参考
在这里插入图片描述
别人的id_table 是一个宏
在这里插入图片描述
在这里插入图片描述
所以推断出 usb鼠标设备 接口描述符是 USB_INTERFACE_CLASS_HID
子类是 USB_INTERFACE_SUBCLASS_BOOT
遵守协议是 USB_INTERFACE_PROTOCOL_MOUSE

写出probe函数

先看看现成的probe函数
在这里插入图片描述
里面有一个interface接口 ,interface表示着逻辑上的设备,比如一个usb音箱,逻辑上有两个(录音,放音),就对应着两个驱动程序
通过接口得到usb_device结构体

先让鼠标变成一个键盘,可以输入LS 那么就用到输入子系统

在probe函数里面实现输入子系统
a.分配一个input_dev结构体

在这里插入图片描述

b.设置

1能产生什么事件
set_bit(EV_KEY, uk_dev->evbit); // 产生按键事件
set_bit(EV_REP, uk_dev->evbit); // 产生持续事件,比如按下不放开就一直输入
2能产生这些事件里面的什么事件
按键事件里面,键盘的L,S,回车事件
在这里插入图片描述

c注册

往输入子系统里面注册
在这里插入图片描述

d硬件操作

数据传输三要素: 源,长度,目的

有usb设备插上去的地址和端点,usb_rcvintpipe()中断类型端点
在这里插入图片描述
长度 在端点描述符里找到长度在这里插入图片描述
让长度等于端点描述符的最大长度

目的 usb_buffer_alloc()
这个函数返回一个虚拟地址 参数里面需要一个物理地址
在这里插入图片描述
建立一个usb_buf 来存放返回的虚拟地址 这个地址里面调用函数
在这里插入图片描述
建立一个usb_buf_phys 作为物理地址
在这里插入图片描述

使用三要素

分配一个urb —>usb请求块
用刚刚的三要素进行urb的设置
在这里插入图片描述
最后使用urb
在这里插入图片描述

触发中断

usb控制器会不停扫描usb 当有数据时候 会给cpu发出中断
写出中断函数
在这里插入图片描述
%02X,在输出一个小于2位的数值时,前面补0,使该数总宽度为2位;%x按变量的数据类型的数据长度输出; 16进制的
写到这先进入烧到开发版上面看看有什么东西
在这里插入图片描述
所以说 我们只有usb_buf[0]发生了变化 一个 char类型的纸质指正指针是4字节32为位的在这里插入图片描述
用pre_val 保存之前的值 判断是否有按键发生
有的话触发按键中断 ,上报事件
在这里插入图片描述

测试
重新建立一个内核

由于之前的内核改的太多,现在重新用之前的

tar -xvf ./linux-2.6.22.6.tar.bz2
book@www.100ask.org:/work/system$ cd ./linux-2.6.22.6/

 patch -p1 < ../linux-2.6.22.6_jz2440_v2v3.patch
cp config_ok .config

make menuconfig //去掉原来的usb驱动程序
->driver
->HID
在这里插入图片描述
去掉
insmod 自己的驱动 就可以愉快的玩耍了

玩耍

先不插鼠标 安装驱动
ls dev/event*
在这里插入图片描述
这时候插入鼠标,就会有 event1
cat /dev/tty1
按下鼠标shell上面就有所产生的按键
在这里插入图片描述


/*
 * drivers\hid\usbhid\usbmouse.c
 */

#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>

static struct input_dev *uk_dev;
static char *usb_buf;
static dma_addr_t usb_buf_phys;
static int len;
static struct urb *uk_urb;

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) },
	//{USB_DEVICE(0x1234,0x5678)},
	{ }	/* Terminating entry */
};

static void usbmouse_as_key_irq(struct urb *urb)
{
	static unsigned char pre_val;
#if 0	
	int i;
	static int cnt = 0;
	printk("data cnt %d: ", ++cnt);
	for (i = 0; i < len; i++)
	{
		printk("%02x ", usb_buf[i]);
	}
	printk("\n");
#endif
	static int cnt = 0;

	printk("data cnt %d: ", ++cnt);
	printk("%02x ", usb_buf[0]);
	printk("%02x\n",pre_val)
	


	/* USB鼠标数据含义
	 * data[0]: bit0-左键, 1-按下, 0-松开
	 *          bit1-右键, 1-按下, 0-松开
	 *          bit2-中键, 1-按下, 0-松开 
	 *
     */
	if ((pre_val & (1<<0)) != (usb_buf[0] & (1<<0)))
	{
		/* 左键发生了变化 */
		input_event(uk_dev, EV_KEY, KEY_L, (usb_buf[0] & (1<<0)) ? 1 : 0);
		input_sync(uk_dev);
	}

	if ((pre_val & (1<<1)) != (usb_buf[0] & (1<<1)))
	{
		/* 右键发生了变化 */
		input_event(uk_dev, EV_KEY, KEY_S, (usb_buf[0] & (1<<1)) ? 1 : 0);
		input_sync(uk_dev);
	}

	if ((pre_val & (1<<2)) != (usb_buf[0] & (1<<2)))
	{
		/* 中键发生了变化 */
		input_event(uk_dev, EV_KEY, KEY_ENTER, (usb_buf[0] & (1<<2)) ? 1 : 0);
		input_sync(uk_dev);
	}
	
	pre_val = usb_buf[0];

	/* 重新提交urb */
	usb_submit_urb(uk_urb, GFP_KERNEL);
}

static int usbmouse_as_key_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;

	/* a. 分配一个input_dev */
	uk_dev = input_allocate_device();
	
	/* b. 设置 */
	/* b.1 能产生哪类事件 */
	set_bit(EV_KEY, uk_dev->evbit);
	set_bit(EV_REP, uk_dev->evbit);
	
	/* b.2 能产生哪些事件 */
	set_bit(KEY_L, uk_dev->keybit);
	set_bit(KEY_S, uk_dev->keybit);
	set_bit(KEY_ENTER, uk_dev->keybit);
	
	/* c. 注册 */
	input_register_device(uk_dev);
	
	/* d. 硬件相关操作 */
	/* 数据传输3要素: 源,目的,长度 */
	/* 源: USB设备的某个端点 */
	pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

	/* 长度: */
	len = endpoint->wMaxPacketSize;

	/* 目的: */
	usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);

	/* 使用"3要素" */
	/* 分配usb request block */
	uk_urb = usb_alloc_urb(0, GFP_KERNEL);
	/* 使用"3要素设置urb" */
	usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_as_key_irq, NULL, endpoint->bInterval);
	uk_urb->transfer_dma = usb_buf_phys;
	uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

	/* 使用URB */
	usb_submit_urb(uk_urb, GFP_KERNEL);
	
	return 0;
}

static void usbmouse_as_key_disconnect(struct usb_interface *intf)
{
	struct usb_device *dev = interface_to_usbdev(intf);

	//printk("disconnect usbmouse!\n");
	usb_kill_urb(uk_urb);
	usb_free_urb(uk_urb);

	usb_buffer_free(dev, len, usb_buf, usb_buf_phys);
	input_unregister_device(uk_dev);
	input_free_device(uk_dev);
}

/* 1. 分配/设置usb_driver */
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)
{
	/* 2. 注册 */
	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");


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值