input_dev结构体
在输入子系统的设备驱动中,最重要的数据结构是struct input dev。需要完成的大部分工作都是围绕着而来的,是驱动的主体,每个struct input_dev代表一个输入设备。
1 如何分配一个input_dev结构体
sturct input_dev * uk_dev
uk_dev = input_allocate_device();
2 分配过后持有该指针,并完成对应的初始化(name, set_bit等)
a. 能产生哪类事件,使用set_bit(EV_KEY, uk_dev->evbit)
b. 能产生哪些事件,使用set_bit(KEY_L, uk_dev->keybit)
3 驱动初始化完成后,调用input_register_device来注册已经初始化的input_dev
这个是input_dev描述一个输入设备 input_handle是关联设备和handler的桥梁 input_handler为input设备提供接口三者关系的核心
4 硬件相关操作
A 获取三要素
首先定义一个结构体 端点描述符,描述一个USB端点
USB设备的每个端点都有自己的端点描述符,由端口描述符中的bNumberEndpoint决定其数量
typedef struct USB_ENDPOINT_DESCRIPTOR
{
BYTE bLength, //描述符的大小 固定0x07
BYTE bDescriptorType, //描述符的接口类型 固定0X05
BYTE bEndpointAddress, //USB设备的端点地址 Bit7,方向,对于控制端点可以忽略,1/0:IN/OUT.Bit6-4,保留.BIt3-0:端点号.
BYTE bmAttributes, //端点属性 Bit7-2,保留.BIt1-0:00控制,01同步,02批量,03中断.
WORD wMaxPacketSize, //本端点接收或发送的最大信息包大小
BYTE bInterval // 轮训数据传送端点的时间间隔.对于批量传送和控制传送的端点忽略.对于同步传送的端点,必须为1,对于中断传送的端点,范围为1-255.
}USB_ENDPOINT_DESCRIPTOR;
/* 数据传输3要素: 源,目的,长度 */
a.源 USB设备的某个端点
pipe的含义 int 类型 其就是将指定usb设备的指定端口设置为某一类型的端口,即是将端点的信息保存
获取办法
创建管道 pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
#define usb_sndctrlpipe(dev,endpoint) --把指定usb设备的指定端口设置为一个控制OUT端点
#define usb_rcvctrlpipe(dev,endpoint) --把指定usb设备的指定端口设置为一个控制IN端点
#define usb_sndisocpipe(dev,endpoint) --把指定usb设备的指定端口设置为一个等时OUT端点
#define usb_rcvisocpipe(dev,endpoint) --把指定usb设备的指定端口设置为一个等时IN端点
#define usb_sndbulkpipe(dev,endpoint) --把指定usb设备的指定端口设置为一个块OUT端点
#define usb_rcvbulkpipe(dev,endpoint) --把指定usb设备的指定端口设置为一个块IN端点
#define usb_sndintpipe(dev,endpoint) --把指定usb设备的指定端口设置为一个中断OUT端点
#define usb_rcvintpipe(dev,endpoint) --把指定usb设备的指定端口设置为一个中断IN端点
b.长度
len = endpoint->wMaxPacketSize;
c.目的
usb_buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_phys);
usbcore提供的,名字可以看是用来申请内存的
参数:第一个参数就是 struct usb_device 结构体的指针 ,
第二个参数申请的 buffer 的大小 ,
第三个参数 ,GFP_KERNEL, 是一个内存申请的 flag, 通常内存申请都用这个 flag, 除非是中断上下文 , 不能睡眠 , 那就得用 GPF_ATOMIC,
第四个参数 涉及到 dma 传输 .该函数不仅进行内存分配,还会进行DMA映射,这里第四个参数将被设置为DMA地址。
用 usb_buffer_alloc 申请的内存空间需要用它的搭档 usb_buffer_free() 来释放 .
B 使用三要素
首先定义一个struct urb结构体 urb USB代码和所有的USB设备通讯使用这个东西
一个urb用来发送或接受数据,或者从一个特定USB设备上的特定的USB端点
a. 创建一个urb结构体,构造一个usb request block USB请求块
struct urb * uk_urb = usb_alloc_urb(0, GFP_KERNEL);
1. 函数原型 struct urb *usb_alloc_urb(int iso_packets, int mem_flags);
2. 参数含义
第一个参数, iso_packet, 是这个 urb 应当包含的同步报文的数目. 如果你不想创建一个同步 urb, 这个变量应当被设置为 0
第二个参数,mem_flags, 是和传递给 kmalloc 函数调用来从内核分配内存的相同的标志类型
使用完过后需要释放
void usb_free_urb(struct urb *urb);
b.使用三要素设置urb
初始化内容详解
使用set_bit(EV_KEY, button_dev.evbit)告知结构体支持哪种设备类型
code 事件的代码,如果事件的类型为EV_KEY,该代码code为设备键盘代码,代码值0-127为键盘上的按键代码,0X110-0X116为鼠标上按键代码,其中0X110 左键 0X111右键 0X112中键
详细include/linux/input.h文件value事件的值。
如果事件的类型是EV_KEY,当按键按下是为1,松开时为0.
set_bit函数
//将addr的第nr(nr为0-31)位置值置为1;
//nr大于31时,把高27的值做为当前地址的偏移,低5位的值为要置为1的位数
extern __inline__ int set_bit(int nr,int * addr)
{
int mask, retval;
addr += nr >> 5; //nr大于31时,把高27的值做为当前地址的偏移,
mask = 1 << (nr & 0x1f); //获取31范围内的值,并把1向左偏移该位数
cli(); //关所有中断
retval = (mask & *addr) != 0; //位置置1
*addr |= mask;
sti(); //开所有中断
return retval; //返回置数值
}
常用结构体
struct input_dev{
const char * name; 设备名字
evbit 设备所支持的事件类型
keybit 按键类型,能产生哪些事件
}
struct 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 device dev; /* Generic device interface 常用USB接口 获得方法 struct usb_device *dev = interface_to_usbdev(intf); */
}
程序拆析
/* a. 分配一个input_dev */
uk_dev = input_allocate_device();
/* b. 设置 */
/* b.1 能产生哪类事件 */
set_bit(EV_KEY, uk_dev->evbit); //EV_KEY 按键
set_bit(EV_REP, uk_dev->evbit); //EV_REP 重复
/*
EV_RST Reset
EV_REL 相对坐标
EV_ABS绝对坐标
EV_MSC 其它
EV_LED LED
EV_SND 声音
EV_FF 力反馈
*/
/* 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);