|
@@ -54,6 +54,7 @@ MODULE_LICENSE("GPL");
|
|
|
#define MT_QUIRK_NO_AREA (1 << 9)
|
|
|
#define MT_QUIRK_IGNORE_DUPLICATES (1 << 10)
|
|
|
#define MT_QUIRK_HOVERING (1 << 11)
|
|
|
+#define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12)
|
|
|
|
|
|
struct mt_slot {
|
|
|
__s32 x, y, cx, cy, p, w, h;
|
|
@@ -83,8 +84,11 @@ struct mt_device {
|
|
|
struct mt_class mtclass; /* our mt device class */
|
|
|
struct mt_fields *fields; /* temporary placeholder for storing the
|
|
|
multitouch fields */
|
|
|
+ int cc_index; /* contact count field index in the report */
|
|
|
+ int cc_value_index; /* contact count value index in the field */
|
|
|
unsigned last_field_index; /* last field index of the report */
|
|
|
unsigned last_slot_field; /* the last field of a slot */
|
|
|
+ unsigned mt_report_id; /* the report ID of the multitouch device */
|
|
|
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */
|
|
|
__s8 inputmode_index; /* InputMode HID feature index in the report */
|
|
|
__s8 maxcontact_report_id; /* Maximum Contact Number HID feature,
|
|
@@ -111,6 +115,9 @@ struct mt_device {
|
|
|
#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007
|
|
|
#define MT_CLS_DUAL_NSMU_CONTACTID 0x0008
|
|
|
#define MT_CLS_INRANGE_CONTACTNUMBER 0x0009
|
|
|
+#define MT_CLS_NSMU 0x000a
|
|
|
+#define MT_CLS_DUAL_CONTACT_NUMBER 0x0010
|
|
|
+#define MT_CLS_DUAL_CONTACT_ID 0x0011
|
|
|
|
|
|
/* vendor specific classes */
|
|
|
#define MT_CLS_3M 0x0101
|
|
@@ -144,6 +151,9 @@ static int cypress_compute_slot(struct mt_device *td)
|
|
|
|
|
|
static struct mt_class mt_classes[] = {
|
|
|
{ .name = MT_CLS_DEFAULT,
|
|
|
+ .quirks = MT_QUIRK_ALWAYS_VALID |
|
|
|
+ MT_QUIRK_CONTACT_CNT_ACCURATE },
|
|
|
+ { .name = MT_CLS_NSMU,
|
|
|
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
|
|
|
{ .name = MT_CLS_SERIAL,
|
|
|
.quirks = MT_QUIRK_ALWAYS_VALID},
|
|
@@ -170,6 +180,16 @@ static struct mt_class mt_classes[] = {
|
|
|
{ .name = MT_CLS_INRANGE_CONTACTNUMBER,
|
|
|
.quirks = MT_QUIRK_VALID_IS_INRANGE |
|
|
|
MT_QUIRK_SLOT_IS_CONTACTNUMBER },
|
|
|
+ { .name = MT_CLS_DUAL_CONTACT_NUMBER,
|
|
|
+ .quirks = MT_QUIRK_ALWAYS_VALID |
|
|
|
+ MT_QUIRK_CONTACT_CNT_ACCURATE |
|
|
|
+ MT_QUIRK_SLOT_IS_CONTACTNUMBER,
|
|
|
+ .maxcontacts = 2 },
|
|
|
+ { .name = MT_CLS_DUAL_CONTACT_ID,
|
|
|
+ .quirks = MT_QUIRK_ALWAYS_VALID |
|
|
|
+ MT_QUIRK_CONTACT_CNT_ACCURATE |
|
|
|
+ MT_QUIRK_SLOT_IS_CONTACTID,
|
|
|
+ .maxcontacts = 2 },
|
|
|
|
|
|
/*
|
|
|
* vendor specific classes
|
|
@@ -250,6 +270,9 @@ static ssize_t mt_set_quirks(struct device *dev,
|
|
|
|
|
|
td->mtclass.quirks = val;
|
|
|
|
|
|
+ if (td->cc_index < 0)
|
|
|
+ td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
|
|
|
+
|
|
|
return count;
|
|
|
}
|
|
|
|
|
@@ -301,6 +324,7 @@ static void mt_feature_mapping(struct hid_device *hdev,
|
|
|
*quirks |= MT_QUIRK_ALWAYS_VALID;
|
|
|
*quirks |= MT_QUIRK_IGNORE_DUPLICATES;
|
|
|
*quirks |= MT_QUIRK_HOVERING;
|
|
|
+ *quirks |= MT_QUIRK_CONTACT_CNT_ACCURATE;
|
|
|
*quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
|
|
|
*quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
|
|
|
*quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
|
|
@@ -428,6 +452,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
|
mt_store_field(usage, td, hi);
|
|
|
td->last_field_index = field->index;
|
|
|
td->touches_by_report++;
|
|
|
+ td->mt_report_id = field->report->id;
|
|
|
return 1;
|
|
|
case HID_DG_WIDTH:
|
|
|
hid_map_usage(hi, usage, bit, max,
|
|
@@ -459,6 +484,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|
|
td->last_field_index = field->index;
|
|
|
return 1;
|
|
|
case HID_DG_CONTACTCOUNT:
|
|
|
+ td->cc_index = field->index;
|
|
|
+ td->cc_value_index = usage->usage_index;
|
|
|
td->last_field_index = field->index;
|
|
|
return 1;
|
|
|
case HID_DG_CONTACTMAX:
|
|
@@ -523,6 +550,10 @@ static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
|
|
|
*/
|
|
|
static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
|
|
|
{
|
|
|
+ if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
|
|
|
+ td->num_received >= td->num_expected)
|
|
|
+ return;
|
|
|
+
|
|
|
if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
|
|
|
int slotnum = mt_compute_slot(td, input);
|
|
|
struct mt_slot *s = &td->curdata;
|
|
@@ -577,6 +608,16 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
|
|
|
|
|
|
static int mt_event(struct hid_device *hid, struct hid_field *field,
|
|
|
struct hid_usage *usage, __s32 value)
|
|
|
+{
|
|
|
+ /* we will handle the hidinput part later, now remains hiddev */
|
|
|
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
|
|
|
+ hid->hiddev_hid_event(hid, field, usage, value);
|
|
|
+
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
|
|
|
+ struct hid_usage *usage, __s32 value)
|
|
|
{
|
|
|
struct mt_device *td = hid_get_drvdata(hid);
|
|
|
__s32 quirks = td->mtclass.quirks;
|
|
@@ -623,20 +664,13 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
|
|
|
td->curdata.h = value;
|
|
|
break;
|
|
|
case HID_DG_CONTACTCOUNT:
|
|
|
- /*
|
|
|
- * Includes multi-packet support where subsequent
|
|
|
- * packets are sent with zero contactcount.
|
|
|
- */
|
|
|
- if (value)
|
|
|
- td->num_expected = value;
|
|
|
break;
|
|
|
case HID_DG_TOUCH:
|
|
|
/* do nothing */
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
- /* fallback to the generic hidinput handling */
|
|
|
- return 0;
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
if (usage->usage_index + 1 == field->report_count) {
|
|
@@ -650,12 +684,43 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
|
|
|
}
|
|
|
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /* we have handled the hidinput part, now remains hiddev */
|
|
|
- if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
|
|
|
- hid->hiddev_hid_event(hid, field, usage, value);
|
|
|
+static void mt_report(struct hid_device *hid, struct hid_report *report)
|
|
|
+{
|
|
|
+ struct mt_device *td = hid_get_drvdata(hid);
|
|
|
+ struct hid_field *field;
|
|
|
+ unsigned count;
|
|
|
+ int r, n;
|
|
|
|
|
|
- return 1;
|
|
|
+ if (report->id != td->mt_report_id)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!(hid->claimed & HID_CLAIMED_INPUT))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Includes multi-packet support where subsequent
|
|
|
+ * packets are sent with zero contactcount.
|
|
|
+ */
|
|
|
+ if (td->cc_index >= 0) {
|
|
|
+ struct hid_field *field = report->field[td->cc_index];
|
|
|
+ int value = field->value[td->cc_value_index];
|
|
|
+ if (value)
|
|
|
+ td->num_expected = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (r = 0; r < report->maxfield; r++) {
|
|
|
+ field = report->field[r];
|
|
|
+ count = field->report_count;
|
|
|
+
|
|
|
+ if (!(HID_MAIN_ITEM_VARIABLE & field->flags))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ for (n = 0; n < count; n++)
|
|
|
+ mt_process_mt_event(hid, field, &field->usage[n],
|
|
|
+ field->value[n]);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void mt_set_input_mode(struct hid_device *hdev)
|
|
@@ -711,6 +776,7 @@ static void mt_post_parse_default_settings(struct mt_device *td)
|
|
|
quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
|
|
|
quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
|
|
|
quirks &= ~MT_QUIRK_VALID_IS_CONFIDENCE;
|
|
|
+ quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
|
|
|
}
|
|
|
|
|
|
td->mtclass.quirks = quirks;
|
|
@@ -719,11 +785,15 @@ static void mt_post_parse_default_settings(struct mt_device *td)
|
|
|
static void mt_post_parse(struct mt_device *td)
|
|
|
{
|
|
|
struct mt_fields *f = td->fields;
|
|
|
+ struct mt_class *cls = &td->mtclass;
|
|
|
|
|
|
if (td->touches_by_report > 0) {
|
|
|
int field_count_per_touch = f->length / td->touches_by_report;
|
|
|
td->last_slot_field = f->usages[field_count_per_touch - 1];
|
|
|
}
|
|
|
+
|
|
|
+ if (td->cc_index < 0)
|
|
|
+ cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
|
|
|
}
|
|
|
|
|
|
static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
|
|
@@ -781,6 +851,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|
|
td->mtclass = *mtclass;
|
|
|
td->inputmode = -1;
|
|
|
td->maxcontact_report_id = -1;
|
|
|
+ td->cc_index = -1;
|
|
|
hid_set_drvdata(hdev, td);
|
|
|
|
|
|
td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
|
|
@@ -875,7 +946,7 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
USB_DEVICE_ID_3M3266) },
|
|
|
|
|
|
/* ActionStar panels */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
|
|
|
USB_DEVICE_ID_ACTIONSTAR_1011) },
|
|
|
|
|
@@ -888,14 +959,14 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) },
|
|
|
|
|
|
/* Baanto multitouch devices */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_BAANTO,
|
|
|
USB_DEVICE_ID_BAANTO_MT_190W2) },
|
|
|
/* Cando panels */
|
|
|
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
|
|
|
USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
|
|
|
- { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
|
|
|
+ { .driver_data = MT_CLS_DUAL_CONTACT_NUMBER,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_CANDO,
|
|
|
USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
|
|
|
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
|
|
@@ -906,12 +977,12 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
|
|
|
|
|
|
/* Chunghwa Telecom touch panels */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
|
|
|
USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
|
|
|
|
|
|
/* CVTouch panels */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
|
|
|
USB_DEVICE_ID_CVTOUCH_SCREEN) },
|
|
|
|
|
@@ -982,7 +1053,7 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) },
|
|
|
|
|
|
/* Elo TouchSystems IntelliTouch Plus panel */
|
|
|
- { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
|
|
|
+ { .driver_data = MT_CLS_DUAL_CONTACT_ID,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_ELO,
|
|
|
USB_DEVICE_ID_ELO_TS2515) },
|
|
|
|
|
@@ -1000,12 +1071,12 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS) },
|
|
|
|
|
|
/* Gametel game controller */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_BT_DEVICE(USB_VENDOR_ID_FRUCTEL,
|
|
|
USB_DEVICE_ID_GAMETEL_MT_MODE) },
|
|
|
|
|
|
/* GoodTouch panels */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
|
|
|
USB_DEVICE_ID_GOODTOUCH_000f) },
|
|
|
|
|
@@ -1023,7 +1094,7 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
USB_DEVICE_ID_IDEACOM_IDC6651) },
|
|
|
|
|
|
/* Ilitek dual touch panel */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_ILITEK,
|
|
|
USB_DEVICE_ID_ILITEK_MULTITOUCH) },
|
|
|
|
|
@@ -1056,6 +1127,11 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
|
|
|
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
|
|
|
|
|
|
+ /* Nexio panels */
|
|
|
+ { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ MT_USB_DEVICE(USB_VENDOR_ID_NEXIO,
|
|
|
+ USB_DEVICE_ID_NEXIO_MULTITOUCH_420)},
|
|
|
+
|
|
|
/* Panasonic panels */
|
|
|
{ .driver_data = MT_CLS_PANASONIC,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
|
|
@@ -1065,7 +1141,7 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
USB_DEVICE_ID_PANABOARD_UBT880) },
|
|
|
|
|
|
/* Novatek Panel */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK,
|
|
|
USB_DEVICE_ID_NOVATEK_PCT) },
|
|
|
|
|
@@ -1111,7 +1187,7 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
{ .driver_data = MT_CLS_CONFIDENCE,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
|
|
|
USB_DEVICE_ID_MTP_STM)},
|
|
|
- { .driver_data = MT_CLS_CONFIDENCE,
|
|
|
+ { .driver_data = MT_CLS_DEFAULT,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX,
|
|
|
USB_DEVICE_ID_MTP_SITRONIX)},
|
|
|
|
|
@@ -1121,48 +1197,48 @@ static const struct hid_device_id mt_devices[] = {
|
|
|
USB_DEVICE_ID_TOPSEED2_PERIPAD_701) },
|
|
|
|
|
|
/* Touch International panels */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
|
|
|
USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
|
|
|
|
|
|
/* Unitec panels */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
|
|
|
USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
|
|
|
USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
|
|
|
/* XAT */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_XAT,
|
|
|
USB_DEVICE_ID_XAT_CSR) },
|
|
|
|
|
|
/* Xiroku */
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
|
|
USB_DEVICE_ID_XIROKU_SPX) },
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
|
|
USB_DEVICE_ID_XIROKU_MPX) },
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
|
|
USB_DEVICE_ID_XIROKU_CSR) },
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
|
|
USB_DEVICE_ID_XIROKU_SPX1) },
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
|
|
USB_DEVICE_ID_XIROKU_MPX1) },
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
|
|
USB_DEVICE_ID_XIROKU_CSR1) },
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
|
|
USB_DEVICE_ID_XIROKU_SPX2) },
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
|
|
USB_DEVICE_ID_XIROKU_MPX2) },
|
|
|
- { .driver_data = MT_CLS_DEFAULT,
|
|
|
+ { .driver_data = MT_CLS_NSMU,
|
|
|
MT_USB_DEVICE(USB_VENDOR_ID_XIROKU,
|
|
|
USB_DEVICE_ID_XIROKU_CSR2) },
|
|
|
|
|
@@ -1193,21 +1269,10 @@ static struct hid_driver mt_driver = {
|
|
|
.feature_mapping = mt_feature_mapping,
|
|
|
.usage_table = mt_grabbed_usages,
|
|
|
.event = mt_event,
|
|
|
+ .report = mt_report,
|
|
|
#ifdef CONFIG_PM
|
|
|
.reset_resume = mt_reset_resume,
|
|
|
.resume = mt_resume,
|
|
|
#endif
|
|
|
};
|
|
|
-
|
|
|
-static int __init mt_init(void)
|
|
|
-{
|
|
|
- return hid_register_driver(&mt_driver);
|
|
|
-}
|
|
|
-
|
|
|
-static void __exit mt_exit(void)
|
|
|
-{
|
|
|
- hid_unregister_driver(&mt_driver);
|
|
|
-}
|
|
|
-
|
|
|
-module_init(mt_init);
|
|
|
-module_exit(mt_exit);
|
|
|
+module_hid_driver(mt_driver);
|