我们都知道410c没有配套的触摸屏,如果有屏的话,在调试或者其他方面就方便多了,所以我们自己买了一个usb触摸屏,现在让我们看看usb触摸屏的驱动。
驱动路经:drivers/input/touchscreen/usbtouchscreen.c
(1)设备匹配
module_usb_driver(usbtouch_driver);
static struct usb_driver usbtouch_driver = {
.name = "usbtouchscreen",
..............
.id_table = usbtouch_devices,
.............
};
static const struct usb_device_id usbtouch_devices[] = {
12 #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
13 /* ignore the HID capable devices, handled by usbhid */
14 {USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
15 {USB_DEVICE_HID_CLASS(0x0eef, 0x0002), .driver_info = DEVTYPE_IGNORE},
16
17 /* normal device IDs */
18 {USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
19 {USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
20 {USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
21 {USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
22 {USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
23 {USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
24 {USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
25 #endif
26
27 #ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
28 {USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT},
29 {USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT},
30 {USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT},
31 {USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT},
32 #endif
33
......................
}
添加的支持的设备,其中(0x3823, 0x0001)分别为usb设备的厂商id(vid)和产品id(pid),DEVTYPE_EGALAX则在下面定义
24 enum {
25 DEVTYPE_IGNORE = -1,
26 DEVTYPE_EGALAX,
27 DEVTYPE_PANJIT,
28 DEVTYPE_3M,
29 DEVTYPE_ITM,
30 DEVTYPE_ETURBO,
31 DEVTYPE_GUNZE,
32 DEVTYPE_DMC_TSC10,
33 DEVTYPE_IRTOUCH,
34 DEVTYPE_IDEALTEK,
35 DEVTYPE_GENERAL_TOUCH,
36 DEVTYPE_GOTOP,
37 DEVTYPE_JASTEC,
38 DEVTYPE_E2I,
39 DEVTYPE_ZYTRONIC,
40 DEVTYPE_TC45USB,
41 DEVTYPE_NEXIO,
42 DEVTYPE_ELO,
43 DEVTYPE_ETOUCH,
44 };
一旦这些都有了,设备匹配成功就会执行probe函数
(2)
struct usb_device *udev = interface_to_usbdev(intf):获取接口对应的设备
usbtouch_get_input_endpoint:获取端点描述符指针。
input_allocate_device:申请输入设备对象内存
type = &usbtouch_dev_info[id->driver_info]:根据driver_info获取全局usbtouch_dev_info的数组项。
usbtouch_process_pkt:用于中断回调函数,上传数据到应用层
usb_alloc_coherent:分配内存
usb_alloc_urb:申请用于urb用于数据传输的内存,注意:这里将返回“usbtouch->data”
usbtouch->data记录了用于普通传输用的内存指针
usbtouch->buffer记录了用于存储读取到的数据的内存指针
usb_make_path:填充设备结构体中的节点名。用来获取 USB 设备在 Sysfs 中的路径
usb_autopm_get_interface:电源唤醒
usb_submit_urb:提交urb
usb_autopm_put_interface:关闭电源
主要来看一下usbtouch_dev_info
1074 static struct usbtouch_device_info usbtouch_dev_info[] = {
1 #ifdef CONFIG_TOUCHSCREEN_USB_ELO
2 [DEVTYPE_ELO] = {
3 .min_xc = 0x0,
4 .max_xc = 0x0fff,
5 .min_yc = 0x0,
6 .max_yc = 0x0fff,
7 .max_press = 0xff,
8 .rept_size = 8,
9 .read_data = elo_read_data,
10 },
11 #endif
12
13 #ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
14 [DEVTYPE_EGALAX] = {
15 .min_xc = 0x0,
16 .max_xc = 0x07ff,
17 .min_yc = 0x0,
18 .max_yc = 0x07ff,
19 .rept_size = 16,
20 .process_pkt = usbtouch_process_multi,
21 .get_pkt_len = egalax_get_pkt_len,
22 .read_data = egalax_read_data,
23 .init = egalax_init,
24 },
25 #endif
............................
}
以DEVTYPE_EGALAX为例:
egalax_init:初始化设备
48 static int egalax_init(struct usbtouch_usb *usbtouch)
47 {
46 int ret, i;
45 unsigned char *buf;
44 struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
//interface_to_usbdev:根据usb_interface指针intf获取usb_device的地址。
32 buf[0] = EGALAX_PKT_TYPE_DIAG;
31 buf[1] = 1; /* length */
30 buf[2] = 'A'; /* command - check active */
29
28 for (i = 0; i < 3; i++) {
27 ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
26 0,
25 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
24 0, 0, buf, 3,
23 USB_CTRL_SET_TIMEOUT);
//usb_control_msg:是没有用到urb的在USB中简单进行发送和接收的一种机制,用于少量的数据通信。
11 }
egalax_get_pkt_len:获取包的长度
357 static int egalax_get_pkt_len(unsigned char *buf, int len)
1 {
2 switch (buf[0] & EGALAX_PKT_TYPE_MASK) {
3 case EGALAX_PKT_TYPE_REPT:
4 return 5;
5
6 case EGALAX_PKT_TYPE_DIAG:
7 if (len < 2)
8 return -1;
9
10 return buf[1] + 2;
11 }
12
13 return 0;
14 }
egalax_read_data:用于中断回调函数,用于读取数据
345 static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
1 {
2 if ((pkt[0] & EGALAX_PKT_TYPE_MASK) != EGALAX_PKT_TYPE_REPT)
3 return 0;
4
5 dev->x = ((pkt[3] & 0x0F) << 7) | (pkt[4] & 0x7F);
6 dev->y = ((pkt[1] & 0x0F) << 7) | (pkt[2] & 0x7F);
7 dev->touch = pkt[0] & 0x01;
8
9 return 1;
10 }
usbtouch_process_multi:用于中断回调函数,用于上传数据
12 static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
13 unsigned char *pkt, int len)
14 {
...............
34 tmp = pkt_len - usbtouch->buf_len;
33 if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size)
32 goto out_flush_buf;
31 memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
30 usbtouch_process_pkt(usbtouch, usbtouch->buffer, pkt_len);
................
25 if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
24 usbtouch_process_pkt(usbtouch, buffer + pos, pkt_len);
23 } else {
22 /* incomplete packet: save in buffer */
21 memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
20 usbtouch->buf_len = buf_len - pos;
19 return;
18 }
................
}
1292 static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
1 unsigned char *pkt, int len)
2 {
............
8 input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
14 input_report_abs(usbtouch->input, ABS_X, usbtouch->x);
15 input_report_abs(usbtouch->input, ABS_Y, usbtouch->y);
17 if (type->max_press)
18 input_report_abs(usbtouch->input, ABS_PRESSURE, usbtouch->press);
19 input_sync(usbtouch->input);
20 }
最后,简单说一下urb,urb全称:USB request block,可以看作数据运输的工具,主要流程如下:
1.usb设备驱动程序创建并初始化一个访问特定usb设备端点的urb,并提交给usb core。
2.usb core提交该urb到usb主控制器驱动程序
3.usb主控制器驱动程序根据urb描述的信息来访问usb设备
具体流程:
(1)创建urb
struct urb* usb_alloc_urb(int isoc_packets, int mem_flags);
iso_packets:urb 所包含的等时数据包的个数,若不是等时传输则为0。
mem_flags:内存分配标志(如GFP_KERNEL)
(2)中断urb的初始化
void usb_fill_int_urb(struct urb* urb,
struct usb_device* dev,
unsigned int pipe,
void* transfer_buffer,
int buffer_length,
usb_complete_t complete,
void* context,
int interval
);
struct urb* urb:要初始化的urb指针
struct usb_device* dev:要访问的设备
transfer_buffer:收/发数据的缓冲区
buffer_length:缓冲区长度
complete:当完成urb所请求的操作后调用此函数。
context:complete函数所需的上下文,通常值为dev
interval:urb被调度的时间间隔。
pipe:要访问的端点所对应的管道,使用usb_sndintpipe()或usb_rcvintpipe()创建,如下:
pipe是一个管道号,该管道记录了目标设备的端点以及管道的类型。每个管道只有一种类型和一个方向,与他的目标设备的端点相对应,可以通过一下几个函数来获得管道号并设置管道类型:
unsigned int usb_sndctrlpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个控制out端点。
unsigned int usb_rcvctrlpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个控制in端点。
unsigned int usb_sndbulkpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个批量out端点。
unsigned int usb_rcvbulkpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个批量in端点。
unsigned int usb_sndintpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个中断out端点。
unsigned int usb_rcvintpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个中断in端点。
unsigned int usb_sndisocpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个等时out端点。
unsigned int usb_rcvisocpipe(struct usb_device* dev, unsigned int endpoint):把指定usb设备的指定端点设置为一个等时in端点。
对于批量urb和控制urb,用下面函数:
void usb_fill_bulk_urb(struct urb* urb, struct usb_device* dev, unsigned int pipe, void* transfer_buffer, int buffer_length, usb_complete_t complete, void* context);
void usb_fill_bulk_urb(struct urb* urb, struct usb_device* dev, unsigned int pipe, unsigned char* setup_packet, void* transfer_buffer, int buffer_length, usb_complete_t complete, void* context);
(3)创建和初始化完成后,urb便可以通过usb_submit_urb函数提交到usb核心:
int usb_submit_urb(struct urb* urb, gfp_t mem_flags)
urb:指向urb的指针
mem_flags:内存分配标志,用于告诉usb核心如何分配内存缓冲区。
mem_flags的几种标志:GFP_ATOMIC、GFP_NOIO、GFP_KERNEL,一般在中断上下文环境中我们会用GFP_ATOMIC
(4)提交后,urb会调用回调函数,回调函数主要检查status字段(当一个urb把数据送到设备时,这个urb会由系统返回给驱动程序,并调用驱动程序的urb完成回调函数处理,这是status记录了这次数据传输的有关状态,如是否成功,成功则返回0),以确定数据是否传输成功.
usb中的endpoint和传输模式可以参考一下:http://blog.chinaunix.net/uid-25314474-id-3040231.html