# MultiTouchPanel(MTP) driver 框架 ``` #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/err.h> #include <linux/regmap.h> #include <linux/slab.h> #define MTP_ADDR 0x70 #define MTP_MAX_X 800 #define MTP_MAX_Y 480 #define MTP_IRQ 123 #define MTP_NAME "xxxx" #define MTP_MAX_ID 1000 /* 由硬體決定 */ struct input_dev *ts_dev; static struct work_struct mtp_work; static irqreturn_t mtp_interrupt(int irq, void *dev_id) { /* 本該: * 獲取觸點資料, 並上報 * 但是I2C是慢速裝置, 不該放在中斷服務程式中操作 */ /* 使用工作佇列, 讓核心執行緒來操作 */ schedule_work(&mtp_work); return IRQ_HANDLED; } static void mtp_work_func(struct work_struct *work) { /* 讀取I2C裝置, 獲得觸點資料, 並上報 */ /* 讀取 */ /* 上報 */ if (/* 沒有觸點 */) { input_mt_sync(ts_dev); input_sync(ts_dev); return; } for (/* 每一個點 */) { input_report_abs(ts_dev, ABS_MT_POSITION_X, x); input_report_abs(ts_dev, ABS_MT_POSITION_Y, y); input_report_abs(ts_dev, ABS_MT_TRACKING_ID, id); input_mt_sync(ts_dev); } input_sync(ts_dev); } static int __devinit mtp_probe(struct i2c_client *client, const struct i2c_device_id *id) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); /* 終於進入了輸入子系統 */ /* 分配input_dev */ ts_dev = input_allocate_device(); /* 設定 */ /* 2.1 能產生哪類事件 */ set_bit(EV_SYN, ts_dev->evbit); set_bit(EV_ABS, ts_dev->evbit); /* 2.2 能產生這類事件中的哪些 */ set_bit(ABS_MT_TRACKING_ID, ts_dev->absbit); set_bit(ABS_MT_POSITION_X, ts_dev->absbit); set_bit(ABS_MT_POSITION_Y, ts_dev->absbit); /* 2.3 這些事件的範圍 */ input_set_abs_params(ts_dev, ABS_MT_TRACKING_ID, 0, MTP_MAX_ID, 0, 0); input_set_abs_params(ts_dev, ABS_MT_POSITION_X, 0, MTP_MAX_X, 0, 0); input_set_abs_params(ts_dev, ABS_MT_POSITION_Y, 0, MTP_MAX_Y, 0, 0); ts_dev->name = MTP_NAME; /* android會根據它找到配置檔案 */ /* 註冊 */ input_register_device(ts_dev); /* 硬體相關操作 */ INIT_WORK(&mtp_work, mtp_work_func); request_irq(MTP_IRQ, mtp_interrupt, IRQ_TYPE_EDGE_FALLING /*IRQF_TRIGGER_FALLING*/, "my_mtp", ts_dev); return 0; } static int __devexit mtp_remove(struct i2c_client *client) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); free_irq(MTP_IRQ, ts_dev); cancel_work_sync(&mtp_work); input_unregister_device(ts_dev); input_free_device(ts_dev); return 0; } static const struct i2c_device_id mtp_id_table[] = { { "my_mtp", 0 }, {} }; static int mtp_detect(struct i2c_client *client, struct i2c_board_info *info) { /* 能執行到這裡, 表示該addr的裝置是存在的 * 但是有些裝置單憑地址無法分辨(A晶片的地址是0x50, B晶片的地址也是0x50) * 還需要進一步讀寫I2C裝置來分辨是哪款晶片 * detect就是用來進一步分辨這個晶片是哪一款,並且設定info->type */ printk("mtp_detect : addr = 0x%x\n", client->addr); /* 進一步判斷是哪一款 */ strlcpy(info->type, "my_mtp", I2C_NAME_SIZE); return 0; /* 返回0之後, 會建立一個新的I2C裝置 * i2c_new_device(adapter, &info), 其中的info->type = "my_mtp" */ } static const unsigned short addr_list[] = { MTP_ADDR, I2C_CLIENT_END }; /* 1. 分配/設定i2c_driver */ static struct i2c_driver mtp_driver = { .class = I2C_CLASS_HWMON, /* 表示去哪些介面卡上找裝置 */ .driver = { .name = "myMTP", .owner = THIS_MODULE, }, .probe = mtp_probe, .remove = __devexit_p(mtp_remove), .id_table = mtp_id_table, .detect = mtp_detect, /* 用這個函式來檢測裝置確實存在 */ .address_list = addr_list, /* 這些裝置的地址 */ }; static int mtp_drv_init(void) { /* 2. 註冊i2c_driver */ i2c_add_driver(&mtp_driver); return 0; } static void mtp_drv_exit(void) { i2c_del_driver(&mtp_driver); } module_init(mtp_drv_init); module_exit(mtp_drv_exit); MODULE_LICENSE("GPL"); ```