# 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");
```