linux内核usb驱动开发,【记录】ARM-Linux开发之USB驱动鼠标控制

【记录】ARM-Linux开发之USB驱动鼠标控制

[复制链接]

自己板子是插上鼠标后,没有反应,只有在插上鼠标,板子重新上电,鼠标才有作用,这实在是不解,好像板子是有鼠标USB驱动,而USB驱动是支持热拔插的,不应该出现这种情况的,出现了,就想着解决。首先必须的知道USB插上设备之后,内核做了哪些工作。(这一步很重要)

插上鼠标,终端打印了这些话,

new full speed USB device using xxxx

拔开鼠标,也会打印

USB disconnect

所以,这些话是在哪打印的呢? 通过全局搜索,发现在hub_port_init函数里面,再玩上找会找到hub_port_connect_change函数,这个函数就是重点了。

在这里需要先了解USB的驱动框架,这里不做过多的阐述,都是别人的话,具体可以参考别人写的Linux书,每一本都会讲到USB,USB的基础概念,框架,各个结构体......

提出其中对我有用的地方,就是USB设备一插上了之后,就会引起中断,USB总线驱动就会发现设备,给新设备分配地址(choose_address(udev)),告诉USB设备(hub_set_address),发出命令获取描述符(usb_get_device_descriptor(udev, 8),usb_get_configuration(udev)),最后device_add。把device放入usb_bus_type的dev链表从usb_bus_type的driver链表里取出usb_driver,把usb_interface和usb_driver的id_table如果能匹配,调用usb_driver的probe

所以,做这个USB开发的,就只需要分配/设置usb_driver结构体,做好.probe函数。就行了。这就是USB的驱动框架了。内核都跟你做好了准备工作了,分工明确,做驱动开发也可以很轻松。

1),开始写一个最简单的USB驱动程序

1,注册

2,分配设置usb_driver结构体

/* 1. 分配/设置usb_driver */

static struct usb_driver usbmouse_driver = {

.name                = "usbmouse_",

.probe                = usbmouse_probe,

.disconnect        = usbmouse_disconnect,

.id_table        = usbmouse_id_table,

};

static int usbmouse_init(void)

{

/* 2. 注册 */

usb_register(&usbmouse_driver);

return 0;

}

static void usbmouse_exit(void)

{

usb_deregister(&usbmouse_driver);

}

module_init(usbmouse_init);

module_exit(usbmouse_exit);

MODULE_LICENSE("GPL");复制代码

USB设备驱动的匹配之通过id_table,和platfrom平台驱动匹配方式(设备名字匹配的)不同,这里是想匹配鼠标,所以在id_table 里添加

static struct usb_device_id usbmouse_id_table [] = {

{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,

USB_INTERFACE_PROTOCOL_MOUSE) },

{ }        /* Terminating entry */

};复制代码这样,usb总线驱动识别出了鼠标,id_table匹配上了,就会调用相应的probe函数

在函数之外定义几个结构体,做全局调用

static char *usb_buf;

static dma_addr_t usb_buf_phys;

static int len;

static struct urb *uk_urb;复制代码

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

/* 数据传输3要素: 源,目的,长度 */

/* 源: USB设备的某个端点 */

pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

/* 长度: */

len = endpoint->wMaxPacketSize;

/* 目的: */

usb_buf = usb_alloc_coherent(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_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;

}复制代码当中还要对usbmouse_irq函数做处理,咋一看是中断函数,其实不是中断,因为USB通信是主从关系,从机设备是没有主动打断主机的能力,只有主机查询,而主机有USB专门的控制器,由它查询,查询到不同就会给CPU中断,这个一定要理解。

static void usbmouse_as_key_irq(struct urb *urb)

{

static unsigned char pre_val;

int i;

static int cnt = 0;

printk("data cnt %d: ", ++cnt);

for (i = 0; i < len; i++)

{

printk("%02x ", usb_buf);

}

printk("\n");

}

这样算是最简单的USB鼠标驱动程序了,把原先的鼠标驱动程序在内核里去掉,make menuconfig,就OK了

a26d678767e8b431ecd7a25f1936bdc5.gif

QQ截图20160817001830.png (68.72 KB, 下载次数: 0)

2016-8-17 11:15 上传

重新烧写或者网络升级,加载这个最简单的驱动程序,插上鼠标,移动,按下左右键

a26d678767e8b431ecd7a25f1936bdc5.gif

QQ截图20160816224944.png (66.04 KB, 下载次数: 0)

2016-8-17 11:15 上传

知道这些数值的意义,就很好办事了,这个最简单的USB驱动程序,只不过是内核的自娱自乐罢了,真正要让鼠标有意义起来就得让应用层知道啊,那就要使用输入子系统了,而输入子系统做过记录,就不在累述,输入子系统就几个步骤

1,分配一个input_dev

2,设置能产生哪类事件还有这类事件的哪些事件(有点绕口)

3,注册

4,在对应的“中断程序”里,上报事件,

在函数外定义

static struct input_dev *uk_dev;  //全局使用

在probe函数里添加

/* 分配一个input_dev */

uk_dev = input_allocate_device();

uk_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);

uk_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |

BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_MIDDLE);

uk_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);

uk_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_SIDE) |

BIT_MASK(BTN_EXTRA);

uk_dev->relbit[0] |= BIT_MASK(REL_WHEEL);

/* 注册 */

input_register_device(uk_dev);

在对应的“中断程序”里添加 上报事件

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_report_key(uk_dev, BTN_LEFT,   usb_buf[1] & 0x01);

input_report_key(uk_dev, BTN_RIGHT,  usb_buf[1] & 0x02);

input_report_key(uk_dev, BTN_MIDDLE, usb_buf[1] & 0x04);

input_report_key(uk_dev, BTN_SIDE,   usb_buf[1] & 0x08);

input_report_key(uk_dev, BTN_EXTRA,  usb_buf[1] & 0x10);

input_report_rel(uk_dev, REL_X,     usb_buf[3]);

input_report_rel(uk_dev, REL_Y,     usb_buf[4]);

input_report_rel(uk_dev, REL_WHEEL, usb_buf[2]);

input_sync(dev);复制代码重新编译,重新加载,而这里特别要注意usb_buf数组里的值与鼠标的操作一定要对应起来,这个需要自己测出来(在一张图片里可以看到)。插上鼠标,能移动,有反应,拔掉,又插上,没有问题(有问题,操作不正当,就看看数组里的值是不是对应的),这才像usb鼠标嘛

最后,官方有这个鼠标完整的例子,在/drivers/hid/usbhid/usbmouse.c,要注意,data数组里的值是不是对应的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux USB驱动开发是指在Linux操作系统中开发USB设备驱动程序的过程。USB驱动程序是用来控制USB设备与计算机之间通信的软件,它负责管理USB设备的连接、数据传输和控制等功能。在Linux系统中,USB驱动程序是以内核模块的形式存在的,开发者需要了解Linux内核的结构和USB协议的相关知识,才能编写出高效、稳定的USB驱动程序。Linux USB驱动开发需要掌握C语言、Linux内核编程、USB协议等知识,同时需要使用一些开发工具和调试工具,如gcc编译器、make工具、GDB调试器等。 ### 回答2: Linux是一种开源的操作系统,广泛应用于服务器、嵌入式设备、超级计算机等领域。在Linux中,许多设备的驱动都是以模块的形式存在于系统中的。USB设备驱动也是Linux系统中非常重要的一类驱动之一。 Linux中的USB驱动开发主要包括以下几个方面: 1. USB架构 LinuxUSB架构分为两个部分:USB核心和USB驱动USB核心主要负责管理USB系统资源,并提供USB设备驱动与用户操作的桥梁,而USB驱动则是实际负责控制USB设备的代码。 2. USB驱动注册 USB设备驱动Linux中是以模块的形式存在的,因此需要通过驱动注册函数将驱动注册到系统中。驱动注册函数会指定驱动支持的USB设备ID等信息。当系统中有匹配的USB设备插入时,USB核心会调用驱动的probe函数,初始化并注册设备。 3. USB设备操作 USB设备驱动的主要任务是通过USB接口与设备进行通信。在Linux中,一般通过调用USB核心提供的函数,访问USB设备的寄存器等信息。设备的数据传输一般使用USB核心提供的异步通信机制。 4. USB设备的断开和移除 当USB设备被拔出时,USB核心会调用驱动的disconnect函数,释放资源。其次,驱动还需响应用户层的请求,卸载驱动相关的资源等。 综上所述,Linux中的USB驱动开发包括USB架构、驱动注册、设备操作、设备断开和移除等方面。熟练掌握这些技能对于嵌入式设备的开发和服务器维护等领域非常重要。 ### 回答3: Linux USB驱动开发主要是指在Linux操作系统上,通过编写USB 驱动程序,实现与USB设备的通信。相比较于其他操作系统,Linux天然具有对USB设备的支持。对于在Linux 2.4及以上版本中,USB集线器、鼠标、键盘等一些外设设备无需单独安装驱动就可以直接使用,这源于Linux内核中已经自带了许多USB驱动,而我们开发人员需要做的就是调用这些API接口,实现自己的业务逻辑即可。而对于一些需要特殊处理的USB设备(如自己开发或第三方成功能较为特殊的设备),我们需要在Linux内核中对其进行驱动开发。 在Linux USB驱动开发中,需要特别注意以下几点: 1.了解USB规范:了解USB规范才能更好地使用设备的功能。比如,我们需要知道USB设备的通信协议、数据格式等,才能正确地编写应用程序,并与USB设备成功通信。 2.学会如何注册USB设备驱动程序:注册USB设备驱动程序也是Linux USB驱动开发的重点。我们需要了解内核的函数和原理,才能正确地注册USB设备驱动程序。通过这个注册,我们可以将设备和驱动程序关联起来,并在内核层面进行相关操作。 3.掌握如何编写USB驱动程序的初始化函数和I/O操作函数:USB驱动程序的初始化函数是模块加载成功后第一次调用的函数。通过定义初始化函数,我们可以在设备驱动程序启动时完成一些需要准备的工作,比如设备寄存器的初始化配置等。I/O操作函数则是定义了USB设备在使用时的各种操作,如读取设备数据、控制设备状态等。 4.了解内核USB的基本操作:如何进行USB请求、读写USB数据等操作是Linux USB驱动开发中必不可少的一部分。我们需要掌握USB集线器中的端口锁定、取出以及在数据缓冲区之间的数据交换等基本操作。 最后,Linux USB驱动开发需要技能深厚并有一定的底层技术基础,因此不太适合初学者。在实际应用中,我们还需要注意一些硬件和软件开发细节,以确保USB设备能正常运行,并防止一些潜在的错误发生。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值