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. 对Java初学者的忠告

    1) 适合自己的图书才是最好的,最好的书并不一定适合你,看自己的情况. 如果你是一个Java初学者一上手就捧一本Thinking in Java在手里,我想你的日子是不会好过的,那样的书给有一定基础的 ...

  2. cordova插件开发注意事项

    1. 编写插件,先创建好cordova项目之后,在项目里开发调试好在去创建插件目录 如何在cordova项目里创建呢,在android文件夹下面的res/xml/config.xml里去加入插件 例如 ...

  3. Eclipse自动生成作者、日期注释等功能设置

    我们在使用Eclipse 编写Java代码时,自动生成的注释信息都是按照预先设置好的格式生成的. 修改作者.日期注释格式:打开Windows->Preferences->Java-> ...

  4. Python Django Apache配置

    项目结构目录: Apache 安装配置目录: C:\Apache2.2\conf\httpd.conf LoadModule wsgi_module modules/mod_wsgi.soWSGISc ...

  5. Windows环境安装Linux系统及JDK部署

    前言 由于我的笔记本有点问题,所以这周系统包括所有硬盘全部重装了,原来的Linux虚拟机都没了,因此才有了这篇文章和各位朋友们分享. 由于Linux环境的优越性(开源.低成本.安全性好.网络功能强大) ...

  6. 用Powershell启用Windows Azure上的远程桌面服务

    [题外话] 某天不小心点了XX管家的自动修复,虽然及时点了取消也看到了远程桌面服务成功被关闭,但是忙完该干的事以后竟然忘记了这件事,在断开远程桌面服务之前也忘记再次打开.以至于之后几天一直以为Azur ...

  7. 关于printf错用格式化字符串导致double和long double输出错误的小随笔

    [题外话] 以前用HUSTOJ给学校搭建Online Judge,所有的评测都是在Linux下进行的.后来为了好往学校服务器上部署,所以大家重新做了一套Online Judge,Web和Judge都是 ...

  8. 深入挖掘.NET序列化机制——实现更易用的序列化方案

    .NET框架为程序员提供了“序列化和反序列化”这一有力的工具,使用它,我们能很容易的将内存中的对象图转化为字节流,并在需要的时候再将其恢复.这一技术的典型应用场景包括[1] : 应用程序运行状态的持久 ...

  9. 论HTML5 Audio 标签歌词同步的实现

    HTML5草案里面其实有原生的字幕标签(<track> Tag)的,但使用的是vtt格式的文件,非常规的字幕(.sub, .srt)或歌词文件(.lrc). 用法如下(代码来自W3Scho ...

  10. Azure PowerShell (5) 使用Azure PowerShell创建简单的Azure虚拟机和Linux虚拟机

    <Windows Azure Platform 系列文章目录> 本文介绍的是国外的Azure Global.如果是国内由世纪互联运维的Azure China,请参考这篇文档: Azure ...