日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

(转载)Linux usbtouchscreen驱动分析

發(fā)布時間:2023/11/27 生活经验 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (转载)Linux usbtouchscreen驱动分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在Linux內(nèi)核中自帶USB觸摸屏驅(qū)動,以linux-2.6.33.3\drivers\input\touchscreen.c為例,進(jìn)行解析:

1.驅(qū)動加載:

static int __init usbtouch_init(void)
{
return usb_register(&usbtouch_driver);?? //驅(qū)動注冊
}

其中usbtouch_driver定義為:

?? static struct usb_driver usbtouch_driver = {
.name?? = "usbtouchscreen", //驅(qū)動名稱
.probe?? = usbtouch_probe,?? //probe 函數(shù)
.disconnect = usbtouch_disconnect,?? //disconnect時調(diào)用的函數(shù)
.id_table = usbtouch_devices,??? //usbtouch 支持的設(shè)備列表
};

static struct usb_device_id usbtouch_devices[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
/* ignore the HID capable devices, handled by usbhid */
{USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
{USB_DEVICE_HID_CLASS(0x0eef, 0x0002), .driver_info = DEVTYPE_IGNORE},

??? /* normal device IDs */
{USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
{USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
{USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},

??? ....

??? 0x0123, 0x0001分別為VID和PID,driver_info 包含驅(qū)動信息,其類型為usbtouch_device_info。

例如DEVTYPE_EGALAX]定義為:

??? static struct usbtouch_device_info usbtouch_dev_info[] = {
#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
[DEVTYPE_EGALAX] = {
.min_xc?? = 0x0,???????????????? //X軸最小坐標(biāo)
.max_xc?? = 0x07ff,??????????? //X軸最大坐標(biāo)
.min_yc?? = 0x0,??????????????? //Y軸最小坐標(biāo)
.max_yc?? = 0x07ff,?????????? //Y軸最大坐標(biāo)
.rept_size = 16,?????????????? //
.process_pkt = usbtouch_process_multi,??? //用于中斷回調(diào)函數(shù),用于上傳數(shù)據(jù)
.get_pkt_len = egalax_get_pkt_len,
.read_data = egalax_read_data,??????????????? //用于中斷回調(diào)函數(shù),用于讀取數(shù)據(jù)
},
#endif

???? 所以在注冊的時候,就注入了設(shè)備的信息,如果注冊成功(usb_device_id中包含對應(yīng)的硬件),就會調(diào)用usbtouch_probe方法。

2.probe方法:

static int usbtouch_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usbtouch_usb *usbtouch; //a usbtouch device
struct input_dev *input_dev;??? //a input device
struct usb_host_interface *interface;
/* usb 設(shè)備有一個configuration 的概念,表示配置,一個設(shè)備可以有多個配置,
但只能同時激活一個,如:一些設(shè)備可以下載固件,或可以設(shè)置不同的全局模式,
cur_altsetting 就是表示的當(dāng)前的這個setting,或者說設(shè)置??梢圆榭丛a中
usb_interface 結(jié)構(gòu)定義的說明部分。從說明中可以看到一個接口可以有多種setting*/
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev(intf); //獲取接口對應(yīng)的設(shè)備

/*struct usb_device?中有一個成員struct usb_device_descriptor,而struct usb_device_descriptor?中的成員__u16 bcdDevice,表示的是制造商指定的產(chǎn)品的版本號,制造商id?和產(chǎn)品id?來標(biāo)志一個設(shè)備.bcdDevice?一共16?位,是以bcd碼的方式保存的信息,也就是說,每4?位代表一個十進(jìn)制的數(shù),比如0011 0110 1001 0111?就代表的3697.*/


struct usbtouch_device_info *type;
int err = -ENOMEM;

/* some devices are ignored */
if (id->driver_info == DEVTYPE_IGNORE)
return -ENODEV;

interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
//端點(diǎn)0描述符,此處的0表示控制端點(diǎn)

usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL); //為設(shè)備分配內(nèi)存
input_dev = input_allocate_device();????? //申請input_dev結(jié)構(gòu)
if (!usbtouch || !input_dev)
goto out_free;

type = &usbtouch_dev_info[id->driver_info]; //提取設(shè)備對應(yīng)的Info
usbtouch->type = type;
if (!type->process_pkt)
type->process_pkt = usbtouch_process_pkt; //用于中斷回調(diào)函數(shù),上傳數(shù)據(jù)到應(yīng)用層

usbtouch->data = usb_buffer_alloc(udev, type->rept_size,
GFP_KERNEL, &usbtouch->data_dma);

/*usbtouch->data:記錄了用于普通傳輸用的內(nèi)存指針*/

/*usb_buffer_alloc(),這個函數(shù)是usbcore提供的,我們只管調(diào)用即可.從名字上就能知道它是用來申請內(nèi)存的,第一個參數(shù)就是struct usb_device結(jié)構(gòu)體的指針,所以我們要傳遞一個udev,第三個參數(shù),GFP_KERNEL,是一個內(nèi)存申請的flag,通常內(nèi)存申請都用這個flag,除非是中斷上下文,不能睡眠,那就得用GPF_ATOMIC,這里沒那么多要求.第二個參數(shù)申請的buffer的大小,第四個參數(shù),這個數(shù)據(jù)類型是Linux內(nèi)核中專門為dma傳輸而準(zhǔn)備的.為了支持dma傳輸,usb_buffer_alloc不僅僅是申請了地址,并且建立了dma映射.usb_buffer_alloc申請的內(nèi)存空間需要用它的搭檔usb_buffer_free()來釋放.*/
if (!usbtouch->data)
goto out_free;

if (type->get_pkt_len) {
usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);

/*usbtouch->buffer:記錄了用于存儲讀取到的數(shù)據(jù)的內(nèi)存指針*/


if (!usbtouch->buffer)
goto out_free_buffers;
}

usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!usbtouch->irq) {
dbg("%s - usb_alloc_urb failed: usbtouch->irq", __func__);
goto out_free_buffers;
}

usbtouch->udev = udev;
usbtouch->input = input_dev;

if (udev->manufacturer)
strlcpy(usbtouch->name, udev->manufacturer, sizeof(usbtouch->name));

if (udev->product) {
if (udev->manufacturer)
strlcat(usbtouch->name, " ", sizeof(usbtouch->name));
strlcat(usbtouch->name, udev->product, sizeof(usbtouch->name));
}

if (!strlen(usbtouch->name))
snprintf(usbtouch->name, sizeof(usbtouch->name),
"USB Touchscreen %04x:%04x",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));

usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys));

/*填充設(shè)備結(jié)構(gòu)體中的節(jié)點(diǎn)名。用來獲取 USB 設(shè)備在 Sysfs 中的路徑,格式為:usb-usb 總線號-路徑名。*/
strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys));

/* 將設(shè)備的名稱賦給設(shè)備內(nèi)嵌的輸入子系統(tǒng)結(jié)構(gòu)體 */

input_dev->name = usbtouch->name;

/* 將設(shè)備的設(shè)備節(jié)點(diǎn)名賦給設(shè)備內(nèi)嵌的輸入子系統(tǒng)結(jié)構(gòu)體 */
input_dev->phys = usbtouch->phys;

/*
* input_dev 中的 input_id 結(jié)構(gòu)體,用來存儲廠商、設(shè)備類型和設(shè)備的編號,這個函數(shù)是將設(shè)備描述符
* 中的編號賦給內(nèi)嵌的輸入子系統(tǒng)結(jié)構(gòu)體
*/
usb_to_input_id(udev, &input_dev->id);


input_dev->dev.parent = &intf->dev;

input_set_drvdata(input_dev, usbtouch);

/* 填充輸入設(shè)備打開函數(shù)指針 */

input_dev->open = usbtouch_open;

/* 填充輸入設(shè)備關(guān)閉函數(shù)指針 */
input_dev->close = usbtouch_close;

/* evbit 用來描述事件,EV_KEY 是按鍵事件,EV_ABS是絕對坐標(biāo)事件,EV_REL 是相對坐標(biāo)事件 */
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);

/* keybit 表示鍵值 */
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X, type->min_xc, type->max_xc, 0, 0);
input_set_abs_params(input_dev, ABS_Y, type->min_yc, type->max_yc, 0, 0);
if (type->max_press)
input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
type->max_press, 0, 0);

/*
* 填充構(gòu)建 urb,將剛才填充好的input_dev結(jié)構(gòu)體的數(shù)據(jù)填充進(jìn)urb 結(jié)構(gòu)體中,在 open 中遞交urb。
* 當(dāng) urb 包含一個即將傳輸?shù)?DMA 緩沖區(qū)時應(yīng)該設(shè)置 URB_NO_TRANSFER_DMA_MAP。USB核心使用
* transfer_dma變量所指向的緩沖區(qū),而不是transfer_buffer變量所指向的。
* URB_NO_SETUP_DMA_MAP 用于 Setup 包,URB_NO_TRANSFER_DMA_MAP 用于所有 Data 包。
*/

?? usb_fill_int_urb(usbtouch->irq, usbtouch->udev,
usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress),
usbtouch->data, type->rept_size,
usbtouch_irq, usbtouch, endpoint->bInterval);

usbtouch->irq->dev = usbtouch->udev;
usbtouch->irq->transfer_dma = usbtouch->data_dma;
usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

/* device specific init */
if (type->init) {
err = type->init(usbtouch);
if (err) {
dbg("%s - type->init() failed, err: %d", __func__, err);
goto out_free_buffers;
}
}

err = input_register_device(usbtouch->input);
if (err) {
dbg("%s - input_register_device failed, err: %d", __func__, err);
goto out_free_buffers;
}

/*
* 一般在 probe 函數(shù)中,都需要將設(shè)備相關(guān)信息保存在一個 usb_interface 結(jié)構(gòu)體中,以便以后通過
* usb_get_intfdata 獲取使用。這里設(shè)備結(jié)構(gòu)體信息將保存在 intf 接口結(jié)構(gòu)體內(nèi)嵌的設(shè)備結(jié)構(gòu)體中
* 的 driver_data 數(shù)據(jù)成員中,即 intf->dev->dirver_data = ...。
*/
usb_set_intfdata(intf, usbtouch);

if (usbtouch->type->irq_always)
usb_submit_urb(usbtouch->irq, GFP_KERNEL);

return 0;

out_free_buffers:
usbtouch_free_buffers(udev, usbtouch);
out_free:
input_free_device(input_dev);
kfree(usbtouch);
return err;
}

3.回調(diào)函數(shù):

/*
* urb 回調(diào)函數(shù),在完成提交 urb 后,urb 回調(diào)函數(shù)將被調(diào)用。
* 此函數(shù)作為 usb_fill_int_urb 函數(shù)的形參,為構(gòu)建的 urb 制定的回調(diào)函數(shù)。
*/
static void usbtouch_irq(struct urb *urb)
{
struct usbtouch_usb *usbtouch = urb->context;
int retval;

switch (urb->status) {
case 0:
/* success */
break;
case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__func__);
return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
__func__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d",
__func__, urb->status);
goto exit;
}

usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);

exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
err("%s - usb_submit_urb failed with result: %d",
__func__, retval);
}

?

4. input_sync

用于事件同步,它告知事件的接收者驅(qū)動已經(jīng)發(fā)出了一個完整的報告

轉(zhuǎn)載于:https://www.cnblogs.com/hello2mhb/articles/3366372.html

總結(jié)

以上是生活随笔為你收集整理的(转载)Linux usbtouchscreen驱动分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。