1、ARM-Linux下USB驱动程序开发
1.1.1、linux下USB配置:
*********(MassStorage:存储设备)************************************
-> Device Drivers
-> SCSI device support(通用设备)
-> SCSI disk support (磁盘支持)
-> SCSI device support(设备支持)

-> Device Drivers
-> USB support (USB设备)
-> USB device filesystem (USB设备文件系统)
-> OHCI HCD support (主要是非PC上的USB芯片)
-> USB Mass Storage support(USB大容量设备)
-> USB Monitor (USB 主设备)

-> File systems
-> DOS/FAT/NT Filesystems
-> MSDOS fs support
-> VFAT (Windows-95) fs support

-> Partition Types (分区类型)
-> PC BIOS (MSDOS partition tables) support

-> Native Language Suppor (本地语言设置)
-> Simplified Chinese charset (CP936, GB2312)
-> NLS UTF-8

make uImage (生成uImage)
测试 mount /dev/sda1 /mnt/

*********(HID:人机接口(鼠标、键盘))********************************
-> Device Drivers
HID Devices --->
-> USB Human Interface Device (full HID) support
USB support --->
-> Support for Host-side USB
make uImage (生成uImage)
测试 cat /dev/mouse1

*********(RNDIS:网卡)********************************

-> Device Drivers x
-> USB support x
-> USB Gadget Support
<M> Support for USB Gadgets
<M> Ethernet Gadget (with CDC Et hernet support) x x
[*] RNDIS support (EXPERIMENTAL) (NEW)
编译内核模块

cp drivers/usb/gadget/_ether.ko /work/nfs_root/first_fs/
cp /arch/arm/boot/uImage /work/nfs_root/new_uImage

*********(CDC-ACM:USB虚拟串口)********************************
(未能识别USB driver)可能是没有配置USB设备

1.2.1、驱动程序编写
struct usb_driver {
const char *name; /*USB驱动名字*/
int (*probe) (struct usb_interface *intf,const struct usb_device_id *id);/*USB core发现该驱动程序能够处理USB接口时,调用*/
void (*disconnect) (struct usb_interface *intf);/*USB移除的时候调用*/
const struct usb_device_id *id_table; /*该驱动程序支持哪些设备 idVendor(制造商ID) idProduct(产品id)*/
};
1.2.2、linux提供宏来定义 一种 设备 :
USB_DEVICE(vend,prod)
vend:USB Vendor ID 制造商ID
prod:USB Product ID 设备ID

1.2.3、linux提供宏来定义 一类 设备 :
USB_INTERFACE_INFO(cl,sc,pr)
cl:类 blnterfaceClass Value
sc:子类 blnterfaceSubClass value
pr:协议 blnterfaceProtocil Value

1.2.4、USB注册:传入一个参数usb_driver
static inline int usb_register(struct usb_driver *driver)

1.2.5、usb_device结构
int devnum; /* Address on USB bus */
char devpath [16]; /* Use in messages: /port/port/... */
enum usb_device_state state; /* configured, not attached, etc */
enum usb_device_speed speed; /* high/full/low (or error) */
struct usb_device_descriptor descriptor; /* Descriptor 设备描述符号*/
struct usb_host_config *config; /* All of the configs */
struct usb_config_descriptor desc; /*usb配置描述符*/
struct usb_interface *interface[USB_MAXINTERFACES];
ruct usb_host_interface *cur_altsetting; /* the currently
/*USB 接口描述符 一个[配置]包含一个或者多个接口,一个接口包含一个或者多个[设置] */
struct usb_interface_descriptor desc;
struct usb_host_endpoint *endpoint; /*USB端点*/
struct usb_endpoint_descriptor desc;/*USB 端点描述符 */

1.3.1、URB(usb request block)请求块 ,承载USB之间的数据传输

①URB处理流程:
1、USB设备驱动程序创建并初始化一个访问特点USB设备指定的端点的URB,并提交给USB Core
2、USB core提交该URB到USB主控制驱动程序
3、USB主控制器驱动程序根据该URB的描述信息,来访问USB设备
4、当访问设备结束后,USB主控制器驱动程序通知USB设备驱动(device)程序

②创建urb的函数为:
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
参数1:iso_packets:urb所含的等时数据包个数
参数2:mem_flags:内存分配标示

③初始化urb函数为:interrupt
static inline void usb_fill_int_urb (
struct urb *urb, //要初始化urb指针
struct usb_device *dev, //usb_device设备
unsigned int pipe, //要访问的端点所对应的管道,使用usb_sndintpipe()/usb_rcvintpipe()
void *transfer_buffer, //要传输数据的缓冲区
int buffer_length, //要传输数据的长度
usb_complete_t complete_fn, //当完成urb所请求的操作时候调用的回调函数
void *context, //通常取值为DEV
int interval //URB被调度的时间间隔
);
问:何为管道?
答:管道:驱动程序的数据缓冲区与一个端点的连接,代表一个在两者之间要移动数据的能力。

批量urb:使用usb_fill_bulk_urb()
控制urb: 使用usb_control_urb()
等时urb没有像中断、控制、批量传输那样有URB初始化函数,我们只有手动初始化urb.

④提交URB
在完成urb的创建和初始化后,URB就可以通过usb_smbmit_urb函数来提交给usb core
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb:指向URB的指针
mem_flags:内存分配标示,用于告知USB core如何分配内存换成区。

⑤URB处理 以下三种情况被认为URB处理完成,调用complete_fn函数
1、URB成功发送给设备,并且设备返回正确,URB->status = 0
2、如果接收和发送发生错误时候 urb->status = error
3、urb被取消,就发生在驱动程序通过,usb_unlink_urb() / usb_kill_urb()

鼠标驱动程序:

 #include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/hid.h>
#include <linux/input.h> /*创建输入设备*/
static struct input_dev *uk_dev;
static int len;
static char *usb_buf;
static dma_addr_t usb_data_dma;
static struct urb *uk_urb; //usb支持的设备列表
static struct usb_device_id usbmouse_key_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
//{USB_DEVICE(0x1234,0x5678)},
{ } /* Terminating entry */
}; static void usb_mouse_irq(struct urb *urb)
{
static unsigned char pre_val;
#if 0
int i;
char b[];
static int cnt = ;
printk("data cnt %d: ", ++cnt);
for (i = ; i < len; i++)
{
printk("%02x ", usb_buf[i]);
}
printk("\n"); /* USB鼠标数据含义
* data[1]: bit0-左键, 1-按下, 0-松开
* bit1-右键, 1-按下, 0-松开
* bit2-中键, 1-按下, 0-松开
*
*/
// if ((pre_val & (1<<0)) != (usb_buf[1] & (1<<0)))
// {
// /* 左键发生了变化 */
// input_event(uk_dev, EV_KEY, KEY_L, (usb_buf[1] & (1<<0)) ? 1 : 0);
// input_sync(uk_dev);
// } // if ((pre_val & (1<<1)) != (usb_buf[1] & (1<<1)))
// {
// /* 右键发生了变化 */
// input_event(uk_dev, EV_KEY, KEY_S, (usb_buf[1] & (1<<1)) ? 1 : 0);
// input_sync(uk_dev);
// } // if ((pre_val & (1<<2)) != (usb_buf[1] & (1<<2)))
// {
// /* 中键发生了变化 */
// input_event(uk_dev, EV_KEY, KEY_ENTER, (usb_buf[1] & (1<<2)) ? 1 : 0);
// input_sync(uk_dev);
// } // pre_val = usb_buf[1];
/* 重新提交urb */
usb_submit_urb(uk_urb, GFP_KERNEL); #else switch (urb->status) {
case : /* 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[] & 0x01);
input_report_key(uk_dev, BTN_RIGHT, usb_buf[] & 0x02);
input_report_key(uk_dev, BTN_MIDDLE, usb_buf[] & 0x04);
input_report_key(uk_dev, BTN_SIDE, usb_buf[] & 0x08);
input_report_key(uk_dev, BTN_EXTRA, usb_buf[] & 0x10); input_report_rel(uk_dev, REL_X, usb_buf[]);
input_report_rel(uk_dev, REL_Y, usb_buf[]);
input_report_rel(uk_dev, REL_WHEEL, usb_buf[]); input_sync(uk_dev);
resubmit:
usb_submit_urb (urb, GFP_ATOMIC);
#endif } static int usbmouse_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;
/*获取当前usb接口的设置*/
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[].desc; /* a. 分配一个input_dev */
uk_dev = input_allocate_device();
/* b. 设置 */
/* b.1 能产生哪类事件 */
set_bit(EV_KEY, uk_dev->evbit);
set_bit(EV_REL, uk_dev->evbit); // /* b.2 能产生这类操作里的哪些事件: L,S,ENTER,LEFTSHIT */
// set_bit(BTN_LEFT, uk_dev->keybit);
// set_bit(BTN_RIGHT, uk_dev->keybit);
// set_bit(BTN_MIDDLE, uk_dev->keybit); // set_bit(REL_X,uk_dev->keybit);
// set_bit(REL_Y,uk_dev->keybit);
// set_bit(REL_WHEEL,uk_dev->keybit); uk_dev->evbit[] = BIT(EV_KEY) | BIT(EV_REL);
uk_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
uk_dev->relbit[] = BIT(REL_X) | BIT(REL_Y);
uk_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
uk_dev->relbit[] |= BIT(REL_WHEEL); /* 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_data_dma);
/* 使用"3要素" */
/* 分配usb request block */
uk_urb = usb_alloc_urb(, GFP_KERNEL); /* 使用"3要素设置urb" */
usb_fill_int_urb(uk_urb, dev, pipe,usb_buf,len,usb_mouse_irq, NULL, endpoint->bInterval);
uk_urb->transfer_dma = usb_data_dma;
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* 使用URB */
usb_submit_urb(uk_urb, GFP_KERNEL); printk("found usbmouse!\n"); printk("bcdUSB = %x\n", dev->descriptor.bcdUSB);
printk("VID = 0x%x\n", dev->descriptor.idVendor);
printk("PID = 0x%x\n", dev->descriptor.idProduct); return ;
} static void usbmouse_key_disconnect(struct usb_interface *interface)
{
struct usb_device *dev = interface_to_usbdev(interface); printk("usbmouse_key_disconnect\n");
input_unregister_device(uk_dev);
input_free_device(uk_dev);
usb_buffer_free(dev,len,usb_buf,usb_data_dma);
usb_kill_urb(uk_urb);
usb_free_urb(uk_urb); } MODULE_DEVICE_TABLE (usb, usbmouse_key_table); /*usbmouse_key_probe usbmouse_key_disconnect 函数指针
*当设备与在id_table 中变量信息匹配时,此函数被调用
*/
static struct usb_driver usbmouse_key_driver = {
.name = "usbmouse_key",
.probe = usbmouse_key_probe,
.disconnect = usbmouse_key_disconnect,
.id_table = usbmouse_key_table, }; /*
*USB骨架 最基本的usb驱动模板
*/
static int __init usb_usbmouse_key_init(void)
{
int result; printk("usb_usbmouse_key_init\n"); /* register this driver with the USB subsystem */
result = usb_register(&usbmouse_key_driver);
if (result)
err("usb_register failed. Error number %d", result); return result;
} static void __exit usb_usbmouse_key_exit(void)
{
printk("usb_usbmouse_key_exit\n");
/* deregister this driver with the USB subsystem */
usb_deregister(&usbmouse_key_driver);
} module_init(usb_usbmouse_key_init);
module_exit(usb_usbmouse_key_exit);
MODULE_LICENSE("GPL");

学习Linux下s3c2440的USB鼠标驱动笔记的更多相关文章

  1. Linux USB驱动学习总结(三)---- USB鼠标的加载、初始化和通信过程

    1.usbmouse的定义:usb鼠标既包含usb设备(usb_device)的属性也包含input输入设备(input_dev)的属性 struct usb_mouse { ];///USB鼠标设备 ...

  2. Linux下安装Android的adb驱动-解决不能识别的问题

    Linux下安装Android的adb驱动-解决不能识别的问题 20141011更新:      老方法对我当时使用的一款设备一直都没有出现问题,最后遇到小米手机还有Android4.4版本的系统都会 ...

  3. Linux下smi/mdio总线驱动

    Linux下smi/mdio总线驱动 韩大卫@吉林师范大学 MII(媒体独立接口), 是IEEE802.3定义的以太网行业标准接口, smi是mii中的标准管理接口, 有两跟管脚, mdio 和mdc ...

  4. 嵌入式Linux驱动学习之路(二十)USB设备驱动

    USB在接入系统的时候,以0的设备ID和主机通信,然后由主机为其分配新的ID. 在主机端,D+和D-都是下拉接地的.而设备端的D-接上拉时,表明此设备为高速设备:12M/s. D+接上拉时则是全速设备 ...

  5. Linux usb子系统(一) _写一个usb鼠标驱动

    USB总线是一种典型的热插拔的总线标准,由于其优异的性能几乎成为了当下大小设备中的标配. USB的驱动可以分为3类:SoC的USB控制器的驱动,主机端USB设备的驱动,设备上的USB Gadget驱动 ...

  6. Linux驱动之USB鼠标驱动编写

    本篇博客分以下几部分讲解 1.介绍USB四大描述 2.介绍USB鼠标驱动程序功能及框架 3.介绍程序用到的结构体 4.介绍程序用到的函数 5.编写程序 6.测试程序 1.介绍USB四大描述符 USB设 ...

  7. Linux USB驱动学习总结(二)---- USB设备驱动

    USB 设备驱动: 一.USB 描述符:(存在于USB 的E2PROM里面) 1.  设备描述符:struct usb_device_descriptor 2.  配置描述符:struct usb_c ...

  8. Linux下cutecom使用USB转串口线

    http://www.cnblogs.com/pang123hui/archive/2011/05/29/2309888.html 在Linux下的串口调试一直使用minicom,虽说Linux的精髓 ...

  9. (转)Linux下安装Android的adb驱动-解决不能识别的问题(国产板子)

    注:本文不涉及怎么安装adb等工具.本方法通用.到目前为止已经解决rk3188和展讯SC6820(波导T9500)的识别问题. 以前调试的Android板子,都是直接用的Google的usb设备id, ...

随机推荐

  1. aspnet webapi 跨域请求 405错误

    跨域,请求按要求配置完毕之后,options预请求老是报错.原因是webapi 默认的web.config有配置 <handlers> <remove name="Exte ...

  2. dnslog注入

    使用Powershell反弹Meterpreter Shell cloudeye在windows下的应用 今天突发奇想的一个姿势,算不上什么技巧,分享一下吧. 看到有人问过.http://zone.w ...

  3. MySQL Can't connect to MySQL server on 'localhost' (10061)

    run > services.msc > rightclick MySQL > properties >start 搞定

  4. nginx 软连接

    ln -s 目标地址 源地址 ln -s ../../../web-admin/etc/nginx-location.conf web-admin.conf

  5. 关于bootstrap和响应式布局

    bootstrap导入 首先需要安装好插件 然后就是在代码器写导入代码 代码如下 <html lang="zh-CN"> <head> <meta c ...

  6. gulp es7配置文件

    http://sanwen.net/a/ybsfcoo.html /** * Created by udi on 2016/11/24. */ var gulp = require('gulp'); ...

  7. madplay播放控制

    管理madplay的主程序,包括播放,暂停播放,恢复播放,停止播放system("madplay north.mp3 &");//利用system函数调用madplay播放 ...

  8. Outlook HTML渲染引擎

    OutLook始终不离不弃 是不是很讨厌为Email代码兼容Outlook? 太遗憾了!虽然光都有尽头,但Outlook始终存在. 为了应付Email的怪癖,我们花了很多时间测试,确保我们搞定了所有O ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 (43) ------ 第八章 POCO之使用POCO加载实体

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-2  使用POCO加载关联实体 问题 你想使用POCO预先加载关联实体. 解决方 ...

  10. Linux压缩命令

    Linux常见的压缩格式有.zip..gz..bz2..tar..tar.gz..tar.bz2:常用的压缩命令有zip.tar.这里列举了各压缩命令的使用示例.更多的用法请使用命令 --help查阅 ...