Loading drivers/hid/hid-ids.h +3 −0 Original line number Diff line number Diff line Loading @@ -283,6 +283,9 @@ #define USB_VENDOR_ID_EMS 0x2006 #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 #define USB_VENDOR_ID_FLATFROG 0x25b5 #define USB_DEVICE_ID_MULTITOUCH_3200 0x0002 #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 Loading drivers/hid/hid-input.c +9 −2 Original line number Diff line number Diff line Loading @@ -1154,6 +1154,7 @@ static void report_features(struct hid_device *hid) int hidinput_connect(struct hid_device *hid, unsigned int force) { struct hid_driver *drv = hid->driver; struct hid_report *report; struct hid_input *hidinput = NULL; struct input_dev *input_dev; Loading Loading @@ -1228,6 +1229,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) * UGCI) cram a lot of unrelated inputs into the * same interface. */ hidinput->report = report; if (drv->input_configured) drv->input_configured(hid, hidinput); if (input_register_device(hidinput->input)) goto out_cleanup; hidinput = NULL; Loading @@ -1235,8 +1238,12 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) } } if (hidinput && input_register_device(hidinput->input)) if (hidinput) { if (drv->input_configured) drv->input_configured(hid, hidinput); if (input_register_device(hidinput->input)) goto out_cleanup; } return 0; Loading drivers/hid/hid-magicmouse.c +1 −1 Original line number Diff line number Diff line Loading @@ -392,7 +392,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd __set_bit(EV_ABS, input->evbit); error = input_mt_init_slots(input, 16); error = input_mt_init_slots(input, 16, 0); if (error) return error; input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, Loading drivers/hid/hid-multitouch.c +85 −100 Original line number Diff line number Diff line Loading @@ -51,12 +51,12 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_VALID_IS_INRANGE (1 << 5) #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6) #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8) #define MT_QUIRK_NO_AREA (1 << 9) struct mt_slot { __s32 x, y, p, w, h; __s32 contactid; /* the device ContactID assigned to this slot */ bool touch_state; /* is the touch valid? */ bool seen_in_this_frame;/* has this slot been updated */ }; struct mt_class { Loading Loading @@ -92,8 +92,9 @@ struct mt_device { __u8 touches_by_report; /* how many touches are present in one report: * 1 means we should use a serial protocol * > 1 means hybrid (multitouch) protocol */ bool serial_maybe; /* need to check for serial protocol */ bool curvalid; /* is the current contact valid? */ struct mt_slot *slots; unsigned mt_flags; /* flags to pass to input-mt */ }; /* classes of device behavior */ Loading @@ -115,6 +116,7 @@ struct mt_device { #define MT_CLS_EGALAX_SERIAL 0x0104 #define MT_CLS_TOPSEED 0x0105 #define MT_CLS_PANASONIC 0x0106 #define MT_CLS_FLATFROG 0x0107 #define MT_DEFAULT_MAXCONTACT 10 Loading @@ -134,25 +136,6 @@ static int cypress_compute_slot(struct mt_device *td) return -1; } static int find_slot_from_contactid(struct mt_device *td) { int i; for (i = 0; i < td->maxcontacts; ++i) { if (td->slots[i].contactid == td->curdata.contactid && td->slots[i].touch_state) return i; } for (i = 0; i < td->maxcontacts; ++i) { if (!td->slots[i].seen_in_this_frame && !td->slots[i].touch_state) return i; } /* should not occurs. If this happens that means * that the device sent more touches that it says * in the report descriptor. It is ignored then. */ return -1; } static struct mt_class mt_classes[] = { { .name = MT_CLS_DEFAULT, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, Loading Loading @@ -190,7 +173,9 @@ static struct mt_class mt_classes[] = { MT_QUIRK_SLOT_IS_CONTACTID, .sn_move = 2048, .sn_width = 128, .sn_height = 128 }, .sn_height = 128, .maxcontacts = 60, }, { .name = MT_CLS_CYPRESS, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | MT_QUIRK_CYPRESS, Loading @@ -216,6 +201,12 @@ static struct mt_class mt_classes[] = { .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, .maxcontacts = 4 }, { .name = MT_CLS_FLATFROG, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | MT_QUIRK_NO_AREA, .sn_move = 2048, .maxcontacts = 40, }, { } }; Loading Loading @@ -319,24 +310,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, * We need to ignore fields that belong to other collections * such as Mouse that might have the same GenericDesktop usages. */ if (field->application == HID_DG_TOUCHSCREEN) set_bit(INPUT_PROP_DIRECT, hi->input->propbit); td->mt_flags |= INPUT_MT_DIRECT; else if (field->application != HID_DG_TOUCHPAD) return 0; /* In case of an indirect device (touchpad), we need to add * specific BTN_TOOL_* to be handled by the synaptics xorg * driver. * We also consider that touchscreens providing buttons are touchpads. /* * Model touchscreens providing buttons as touchpads. */ if (field->application == HID_DG_TOUCHPAD || (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON || cls->is_indirect) { set_bit(INPUT_PROP_POINTER, hi->input->propbit); set_bit(BTN_TOOL_FINGER, hi->input->keybit); set_bit(BTN_TOOL_DOUBLETAP, hi->input->keybit); set_bit(BTN_TOOL_TRIPLETAP, hi->input->keybit); set_bit(BTN_TOOL_QUADTAP, hi->input->keybit); } (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) td->mt_flags |= INPUT_MT_POINTER; /* eGalax devices provide a Digitizer.Stylus input which overrides * the correct Digitizers.Finger X/Y ranges. Loading @@ -353,8 +336,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, EV_ABS, ABS_MT_POSITION_X); set_abs(hi->input, ABS_MT_POSITION_X, field, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_X, field, cls->sn_move); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; Loading @@ -363,8 +344,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, EV_ABS, ABS_MT_POSITION_Y); set_abs(hi->input, ABS_MT_POSITION_Y, field, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_Y, field, cls->sn_move); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; Loading @@ -388,9 +367,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, td->last_field_index = field->index; return 1; case HID_DG_CONTACTID: if (!td->maxcontacts) td->maxcontacts = MT_DEFAULT_MAXCONTACT; input_mt_init_slots(hi->input, td->maxcontacts); mt_store_field(usage, td, hi); td->last_field_index = field->index; td->touches_by_report++; Loading @@ -398,6 +374,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); if (!(cls->quirks & MT_QUIRK_NO_AREA)) set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, cls->sn_width); mt_store_field(usage, td, hi); Loading @@ -406,10 +383,12 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); if (!(cls->quirks & MT_QUIRK_NO_AREA)) { set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, cls->sn_height); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); } mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; Loading @@ -418,9 +397,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, EV_ABS, ABS_MT_PRESSURE); set_abs(hi->input, ABS_MT_PRESSURE, field, cls->sn_pressure); /* touchscreen emulation */ set_abs(hi->input, ABS_PRESSURE, field, cls->sn_pressure); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; Loading Loading @@ -464,7 +440,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } static int mt_compute_slot(struct mt_device *td) static int mt_compute_slot(struct mt_device *td, struct input_dev *input) { __s32 quirks = td->mtclass.quirks; Loading @@ -480,42 +456,23 @@ static int mt_compute_slot(struct mt_device *td) if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) return td->curdata.contactid - 1; return find_slot_from_contactid(td); return input_mt_get_slot_by_key(input, td->curdata.contactid); } /* * this function is called when a whole contact has been processed, * so that it can assign it to a slot and store the data there */ static void mt_complete_slot(struct mt_device *td) static void mt_complete_slot(struct mt_device *td, struct input_dev *input) { td->curdata.seen_in_this_frame = true; if (td->curvalid) { int slotnum = mt_compute_slot(td); if (slotnum >= 0 && slotnum < td->maxcontacts) td->slots[slotnum] = td->curdata; } td->num_received++; } /* * this function is called when a whole packet has been received and processed, * so that it can decide what to send to the input layer. */ static void mt_emit_event(struct mt_device *td, struct input_dev *input) { int i; int slotnum = mt_compute_slot(td, input); struct mt_slot *s = &td->curdata; for (i = 0; i < td->maxcontacts; ++i) { struct mt_slot *s = &(td->slots[i]); if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && !s->seen_in_this_frame) { s->touch_state = false; } if (slotnum < 0 || slotnum >= td->maxcontacts) return; input_mt_slot(input, i); input_mt_slot(input, slotnum); input_mt_report_slot_state(input, MT_TOOL_FINGER, s->touch_state); if (s->touch_state) { Loading @@ -532,24 +489,29 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); } s->seen_in_this_frame = false; } td->num_received++; } input_mt_report_pointer_emulation(input, true); /* * this function is called when a whole packet has been received and processed, * so that it can decide what to send to the input layer. */ static void mt_sync_frame(struct mt_device *td, struct input_dev *input) { input_mt_sync_frame(input); input_sync(input); td->num_received = 0; } static int 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; if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { case HID_DG_INRANGE: if (quirks & MT_QUIRK_ALWAYS_VALID) Loading Loading @@ -602,11 +564,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, } if (usage->hid == td->last_slot_field) mt_complete_slot(td); mt_complete_slot(td, field->hidinput->input); if (field->index == td->last_field_index && td->num_received >= td->num_expected) mt_emit_event(td, field->hidinput->input); mt_sync_frame(td, field->hidinput->input); } Loading Loading @@ -685,6 +647,35 @@ static void mt_post_parse(struct mt_device *td) } } static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); struct mt_class *cls = &td->mtclass; struct input_dev *input = hi->input; /* Only initialize slots for MT input devices */ if (!test_bit(ABS_MT_POSITION_X, input->absbit)) return; if (!td->maxcontacts) td->maxcontacts = MT_DEFAULT_MAXCONTACT; mt_post_parse(td); if (td->serial_maybe) mt_post_parse_default_settings(td); if (cls->is_indirect) td->mt_flags |= INPUT_MT_POINTER; if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) td->mt_flags |= INPUT_MT_DROP_UNUSED; input_mt_init_slots(input, td->maxcontacts, td->mt_flags); td->mt_flags = 0; } static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; Loading Loading @@ -722,6 +713,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) goto fail; } if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) td->serial_maybe = true; ret = hid_parse(hdev); if (ret != 0) goto fail; Loading @@ -730,20 +724,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret) goto fail; mt_post_parse(td); if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) mt_post_parse_default_settings(td); td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), GFP_KERNEL); if (!td->slots) { dev_err(&hdev->dev, "cannot allocate multitouch slots\n"); hid_hw_stop(hdev); ret = -ENOMEM; goto fail; } ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); mt_set_maxcontacts(hdev); Loading Loading @@ -774,7 +754,6 @@ static void mt_remove(struct hid_device *hdev) struct mt_device *td = hid_get_drvdata(hdev); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); hid_hw_stop(hdev); kfree(td->slots); kfree(td); hid_set_drvdata(hdev, NULL); } Loading Loading @@ -892,6 +871,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) }, /* Flatfrog Panels */ { .driver_data = MT_CLS_FLATFROG, MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, USB_DEVICE_ID_MULTITOUCH_3200) }, /* GeneralTouch panel */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, Loading Loading @@ -1087,6 +1071,7 @@ static struct hid_driver mt_driver = { .remove = mt_remove, .input_mapping = mt_input_mapping, .input_mapped = mt_input_mapped, .input_configured = mt_input_configured, .feature_mapping = mt_feature_mapping, .usage_table = mt_grabbed_usages, .event = mt_event, Loading drivers/input/evdev.c +86 −91 Original line number Diff line number Diff line Loading @@ -23,11 +23,11 @@ #include <linux/input/mt.h> #include <linux/major.h> #include <linux/device.h> #include <linux/cdev.h> #include "input-compat.h" struct evdev { int open; int minor; struct input_handle handle; wait_queue_head_t wait; struct evdev_client __rcu *grab; Loading @@ -35,6 +35,7 @@ struct evdev { spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; struct cdev cdev; bool exist; }; Loading @@ -51,19 +52,9 @@ struct evdev_client { struct input_event buffer[]; }; static struct evdev *evdev_table[EVDEV_MINORS]; static DEFINE_MUTEX(evdev_table_mutex); static void evdev_pass_event(struct evdev_client *client, struct input_event *event, ktime_t mono, ktime_t real) static void __pass_event(struct evdev_client *client, const struct input_event *event) { event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? mono : real); /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); client->buffer[client->head++] = *event; client->head &= client->bufsize - 1; Loading @@ -86,42 +77,74 @@ static void evdev_pass_event(struct evdev_client *client, client->packet_head = client->head; kill_fasync(&client->fasync, SIGIO, POLL_IN); } } static void evdev_pass_values(struct evdev_client *client, const struct input_value *vals, unsigned int count, ktime_t mono, ktime_t real) { struct evdev *evdev = client->evdev; const struct input_value *v; struct input_event event; bool wakeup = false; event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? mono : real); /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); for (v = vals; v != vals + count; v++) { event.type = v->type; event.code = v->code; event.value = v->value; __pass_event(client, &event); if (v->type == EV_SYN && v->code == SYN_REPORT) wakeup = true; } spin_unlock(&client->buffer_lock); if (wakeup) wake_up_interruptible(&evdev->wait); } /* * Pass incoming event to all connected clients. * Pass incoming events to all connected clients. */ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) static void evdev_events(struct input_handle *handle, const struct input_value *vals, unsigned int count) { struct evdev *evdev = handle->private; struct evdev_client *client; struct input_event event; ktime_t time_mono, time_real; time_mono = ktime_get(); time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); event.type = type; event.code = code; event.value = value; rcu_read_lock(); client = rcu_dereference(evdev->grab); if (client) evdev_pass_event(client, &event, time_mono, time_real); evdev_pass_values(client, vals, count, time_mono, time_real); else list_for_each_entry_rcu(client, &evdev->client_list, node) evdev_pass_event(client, &event, time_mono, time_real); evdev_pass_values(client, vals, count, time_mono, time_real); rcu_read_unlock(); } if (type == EV_SYN && code == SYN_REPORT) wake_up_interruptible(&evdev->wait); /* * Pass incoming event to all connected clients. */ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct input_value vals[] = { { type, code, value } }; evdev_events(handle, vals, 1); } static int evdev_fasync(int fd, struct file *file, int on) Loading Loading @@ -285,35 +308,16 @@ static unsigned int evdev_compute_buffer_size(struct input_dev *dev) static int evdev_open(struct inode *inode, struct file *file) { struct evdev *evdev; struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev); unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev); struct evdev_client *client; int i = iminor(inode) - EVDEV_MINOR_BASE; unsigned int bufsize; int error; if (i >= EVDEV_MINORS) return -ENODEV; error = mutex_lock_interruptible(&evdev_table_mutex); if (error) return error; evdev = evdev_table[i]; if (evdev) get_device(&evdev->dev); mutex_unlock(&evdev_table_mutex); if (!evdev) return -ENODEV; bufsize = evdev_compute_buffer_size(evdev->handle.dev); client = kzalloc(sizeof(struct evdev_client) + bufsize * sizeof(struct input_event), GFP_KERNEL); if (!client) { error = -ENOMEM; goto err_put_evdev; } if (!client) return -ENOMEM; client->bufsize = bufsize; spin_lock_init(&client->buffer_lock); Loading @@ -327,13 +331,12 @@ static int evdev_open(struct inode *inode, struct file *file) file->private_data = client; nonseekable_open(inode, file); get_device(&evdev->dev); return 0; err_free_client: evdev_detach_client(evdev, client); kfree(client); err_put_evdev: put_device(&evdev->dev); return error; } Loading Loading @@ -653,20 +656,22 @@ static int evdev_handle_mt_request(struct input_dev *dev, unsigned int size, int __user *ip) { const struct input_mt_slot *mt = dev->mt; const struct input_mt *mt = dev->mt; unsigned int code; int max_slots; int i; if (get_user(code, &ip[0])) return -EFAULT; if (!input_is_mt_value(code)) if (!mt || !input_is_mt_value(code)) return -EINVAL; max_slots = (size - sizeof(__u32)) / sizeof(__s32); for (i = 0; i < dev->mtsize && i < max_slots; i++) if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i])) for (i = 0; i < mt->num_slots && i < max_slots; i++) { int value = input_mt_get_value(&mt->slots[i], code); if (put_user(value, &ip[1 + i])) return -EFAULT; } return 0; } Loading Loading @@ -915,26 +920,6 @@ static const struct file_operations evdev_fops = { .llseek = no_llseek, }; static int evdev_install_chrdev(struct evdev *evdev) { /* * No need to do any locking here as calls to connect and * disconnect are serialized by the input core */ evdev_table[evdev->minor] = evdev; return 0; } static void evdev_remove_chrdev(struct evdev *evdev) { /* * Lock evdev table to prevent race with evdev_open() */ mutex_lock(&evdev_table_mutex); evdev_table[evdev->minor] = NULL; mutex_unlock(&evdev_table_mutex); } /* * Mark device non-existent. This disables writes, ioctls and * prevents new users from opening the device. Already posted Loading @@ -953,7 +938,8 @@ static void evdev_cleanup(struct evdev *evdev) evdev_mark_dead(evdev); evdev_hangup(evdev); evdev_remove_chrdev(evdev); cdev_del(&evdev->cdev); /* evdev is marked dead so no one else accesses evdev->open */ if (evdev->open) { Loading @@ -964,43 +950,47 @@ static void evdev_cleanup(struct evdev *evdev) /* * Create new evdev device. Note that input core serializes calls * to connect and disconnect so we don't need to lock evdev_table here. * to connect and disconnect. */ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { struct evdev *evdev; int minor; int dev_no; int error; for (minor = 0; minor < EVDEV_MINORS; minor++) if (!evdev_table[minor]) break; if (minor == EVDEV_MINORS) { pr_err("no more free evdev devices\n"); return -ENFILE; minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true); if (minor < 0) { error = minor; pr_err("failed to reserve new minor: %d\n", error); return error; } evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); if (!evdev) return -ENOMEM; if (!evdev) { error = -ENOMEM; goto err_free_minor; } INIT_LIST_HEAD(&evdev->client_list); spin_lock_init(&evdev->client_lock); mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); dev_set_name(&evdev->dev, "event%d", minor); evdev->exist = true; evdev->minor = minor; dev_no = minor; /* Normalize device number if it falls into legacy range */ if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS) dev_no -= EVDEV_MINOR_BASE; dev_set_name(&evdev->dev, "event%d", dev_no); evdev->handle.dev = input_get_device(dev); evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); evdev->dev.devt = MKDEV(INPUT_MAJOR, minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; evdev->dev.release = evdev_free; Loading @@ -1010,7 +1000,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, if (error) goto err_free_evdev; error = evdev_install_chrdev(evdev); cdev_init(&evdev->cdev, &evdev_fops); error = cdev_add(&evdev->cdev, evdev->dev.devt, 1); if (error) goto err_unregister_handle; Loading @@ -1026,6 +1017,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, input_unregister_handle(&evdev->handle); err_free_evdev: put_device(&evdev->dev); err_free_minor: input_free_minor(minor); return error; } Loading @@ -1035,6 +1028,7 @@ static void evdev_disconnect(struct input_handle *handle) device_del(&evdev->dev); evdev_cleanup(evdev); input_free_minor(MINOR(evdev->dev.devt)); input_unregister_handle(handle); put_device(&evdev->dev); } Loading @@ -1048,9 +1042,10 @@ MODULE_DEVICE_TABLE(input, evdev_ids); static struct input_handler evdev_handler = { .event = evdev_event, .events = evdev_events, .connect = evdev_connect, .disconnect = evdev_disconnect, .fops = &evdev_fops, .legacy_minors = true, .minor = EVDEV_MINOR_BASE, .name = "evdev", .id_table = evdev_ids, Loading Loading
drivers/hid/hid-ids.h +3 −0 Original line number Diff line number Diff line Loading @@ -283,6 +283,9 @@ #define USB_VENDOR_ID_EMS 0x2006 #define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 #define USB_VENDOR_ID_FLATFROG 0x25b5 #define USB_DEVICE_ID_MULTITOUCH_3200 0x0002 #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 Loading
drivers/hid/hid-input.c +9 −2 Original line number Diff line number Diff line Loading @@ -1154,6 +1154,7 @@ static void report_features(struct hid_device *hid) int hidinput_connect(struct hid_device *hid, unsigned int force) { struct hid_driver *drv = hid->driver; struct hid_report *report; struct hid_input *hidinput = NULL; struct input_dev *input_dev; Loading Loading @@ -1228,6 +1229,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) * UGCI) cram a lot of unrelated inputs into the * same interface. */ hidinput->report = report; if (drv->input_configured) drv->input_configured(hid, hidinput); if (input_register_device(hidinput->input)) goto out_cleanup; hidinput = NULL; Loading @@ -1235,8 +1238,12 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) } } if (hidinput && input_register_device(hidinput->input)) if (hidinput) { if (drv->input_configured) drv->input_configured(hid, hidinput); if (input_register_device(hidinput->input)) goto out_cleanup; } return 0; Loading
drivers/hid/hid-magicmouse.c +1 −1 Original line number Diff line number Diff line Loading @@ -392,7 +392,7 @@ static int magicmouse_setup_input(struct input_dev *input, struct hid_device *hd __set_bit(EV_ABS, input->evbit); error = input_mt_init_slots(input, 16); error = input_mt_init_slots(input, 16, 0); if (error) return error; input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255 << 2, Loading
drivers/hid/hid-multitouch.c +85 −100 Original line number Diff line number Diff line Loading @@ -51,12 +51,12 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_VALID_IS_INRANGE (1 << 5) #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6) #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8) #define MT_QUIRK_NO_AREA (1 << 9) struct mt_slot { __s32 x, y, p, w, h; __s32 contactid; /* the device ContactID assigned to this slot */ bool touch_state; /* is the touch valid? */ bool seen_in_this_frame;/* has this slot been updated */ }; struct mt_class { Loading Loading @@ -92,8 +92,9 @@ struct mt_device { __u8 touches_by_report; /* how many touches are present in one report: * 1 means we should use a serial protocol * > 1 means hybrid (multitouch) protocol */ bool serial_maybe; /* need to check for serial protocol */ bool curvalid; /* is the current contact valid? */ struct mt_slot *slots; unsigned mt_flags; /* flags to pass to input-mt */ }; /* classes of device behavior */ Loading @@ -115,6 +116,7 @@ struct mt_device { #define MT_CLS_EGALAX_SERIAL 0x0104 #define MT_CLS_TOPSEED 0x0105 #define MT_CLS_PANASONIC 0x0106 #define MT_CLS_FLATFROG 0x0107 #define MT_DEFAULT_MAXCONTACT 10 Loading @@ -134,25 +136,6 @@ static int cypress_compute_slot(struct mt_device *td) return -1; } static int find_slot_from_contactid(struct mt_device *td) { int i; for (i = 0; i < td->maxcontacts; ++i) { if (td->slots[i].contactid == td->curdata.contactid && td->slots[i].touch_state) return i; } for (i = 0; i < td->maxcontacts; ++i) { if (!td->slots[i].seen_in_this_frame && !td->slots[i].touch_state) return i; } /* should not occurs. If this happens that means * that the device sent more touches that it says * in the report descriptor. It is ignored then. */ return -1; } static struct mt_class mt_classes[] = { { .name = MT_CLS_DEFAULT, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, Loading Loading @@ -190,7 +173,9 @@ static struct mt_class mt_classes[] = { MT_QUIRK_SLOT_IS_CONTACTID, .sn_move = 2048, .sn_width = 128, .sn_height = 128 }, .sn_height = 128, .maxcontacts = 60, }, { .name = MT_CLS_CYPRESS, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | MT_QUIRK_CYPRESS, Loading @@ -216,6 +201,12 @@ static struct mt_class mt_classes[] = { .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, .maxcontacts = 4 }, { .name = MT_CLS_FLATFROG, .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | MT_QUIRK_NO_AREA, .sn_move = 2048, .maxcontacts = 40, }, { } }; Loading Loading @@ -319,24 +310,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, * We need to ignore fields that belong to other collections * such as Mouse that might have the same GenericDesktop usages. */ if (field->application == HID_DG_TOUCHSCREEN) set_bit(INPUT_PROP_DIRECT, hi->input->propbit); td->mt_flags |= INPUT_MT_DIRECT; else if (field->application != HID_DG_TOUCHPAD) return 0; /* In case of an indirect device (touchpad), we need to add * specific BTN_TOOL_* to be handled by the synaptics xorg * driver. * We also consider that touchscreens providing buttons are touchpads. /* * Model touchscreens providing buttons as touchpads. */ if (field->application == HID_DG_TOUCHPAD || (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON || cls->is_indirect) { set_bit(INPUT_PROP_POINTER, hi->input->propbit); set_bit(BTN_TOOL_FINGER, hi->input->keybit); set_bit(BTN_TOOL_DOUBLETAP, hi->input->keybit); set_bit(BTN_TOOL_TRIPLETAP, hi->input->keybit); set_bit(BTN_TOOL_QUADTAP, hi->input->keybit); } (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) td->mt_flags |= INPUT_MT_POINTER; /* eGalax devices provide a Digitizer.Stylus input which overrides * the correct Digitizers.Finger X/Y ranges. Loading @@ -353,8 +336,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, EV_ABS, ABS_MT_POSITION_X); set_abs(hi->input, ABS_MT_POSITION_X, field, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_X, field, cls->sn_move); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; Loading @@ -363,8 +344,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, EV_ABS, ABS_MT_POSITION_Y); set_abs(hi->input, ABS_MT_POSITION_Y, field, cls->sn_move); /* touchscreen emulation */ set_abs(hi->input, ABS_Y, field, cls->sn_move); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; Loading @@ -388,9 +367,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, td->last_field_index = field->index; return 1; case HID_DG_CONTACTID: if (!td->maxcontacts) td->maxcontacts = MT_DEFAULT_MAXCONTACT; input_mt_init_slots(hi->input, td->maxcontacts); mt_store_field(usage, td, hi); td->last_field_index = field->index; td->touches_by_report++; Loading @@ -398,6 +374,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_WIDTH: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MAJOR); if (!(cls->quirks & MT_QUIRK_NO_AREA)) set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, cls->sn_width); mt_store_field(usage, td, hi); Loading @@ -406,10 +383,12 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_HEIGHT: hid_map_usage(hi, usage, bit, max, EV_ABS, ABS_MT_TOUCH_MINOR); if (!(cls->quirks & MT_QUIRK_NO_AREA)) { set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, cls->sn_height); input_set_abs_params(hi->input, ABS_MT_ORIENTATION, 0, 1, 0, 0); } mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; Loading @@ -418,9 +397,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, EV_ABS, ABS_MT_PRESSURE); set_abs(hi->input, ABS_MT_PRESSURE, field, cls->sn_pressure); /* touchscreen emulation */ set_abs(hi->input, ABS_PRESSURE, field, cls->sn_pressure); mt_store_field(usage, td, hi); td->last_field_index = field->index; return 1; Loading Loading @@ -464,7 +440,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, return -1; } static int mt_compute_slot(struct mt_device *td) static int mt_compute_slot(struct mt_device *td, struct input_dev *input) { __s32 quirks = td->mtclass.quirks; Loading @@ -480,42 +456,23 @@ static int mt_compute_slot(struct mt_device *td) if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) return td->curdata.contactid - 1; return find_slot_from_contactid(td); return input_mt_get_slot_by_key(input, td->curdata.contactid); } /* * this function is called when a whole contact has been processed, * so that it can assign it to a slot and store the data there */ static void mt_complete_slot(struct mt_device *td) static void mt_complete_slot(struct mt_device *td, struct input_dev *input) { td->curdata.seen_in_this_frame = true; if (td->curvalid) { int slotnum = mt_compute_slot(td); if (slotnum >= 0 && slotnum < td->maxcontacts) td->slots[slotnum] = td->curdata; } td->num_received++; } /* * this function is called when a whole packet has been received and processed, * so that it can decide what to send to the input layer. */ static void mt_emit_event(struct mt_device *td, struct input_dev *input) { int i; int slotnum = mt_compute_slot(td, input); struct mt_slot *s = &td->curdata; for (i = 0; i < td->maxcontacts; ++i) { struct mt_slot *s = &(td->slots[i]); if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && !s->seen_in_this_frame) { s->touch_state = false; } if (slotnum < 0 || slotnum >= td->maxcontacts) return; input_mt_slot(input, i); input_mt_slot(input, slotnum); input_mt_report_slot_state(input, MT_TOOL_FINGER, s->touch_state); if (s->touch_state) { Loading @@ -532,24 +489,29 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); } s->seen_in_this_frame = false; } td->num_received++; } input_mt_report_pointer_emulation(input, true); /* * this function is called when a whole packet has been received and processed, * so that it can decide what to send to the input layer. */ static void mt_sync_frame(struct mt_device *td, struct input_dev *input) { input_mt_sync_frame(input); input_sync(input); td->num_received = 0; } static int 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; if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { if (hid->claimed & HID_CLAIMED_INPUT) { switch (usage->hid) { case HID_DG_INRANGE: if (quirks & MT_QUIRK_ALWAYS_VALID) Loading Loading @@ -602,11 +564,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, } if (usage->hid == td->last_slot_field) mt_complete_slot(td); mt_complete_slot(td, field->hidinput->input); if (field->index == td->last_field_index && td->num_received >= td->num_expected) mt_emit_event(td, field->hidinput->input); mt_sync_frame(td, field->hidinput->input); } Loading Loading @@ -685,6 +647,35 @@ static void mt_post_parse(struct mt_device *td) } } static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct mt_device *td = hid_get_drvdata(hdev); struct mt_class *cls = &td->mtclass; struct input_dev *input = hi->input; /* Only initialize slots for MT input devices */ if (!test_bit(ABS_MT_POSITION_X, input->absbit)) return; if (!td->maxcontacts) td->maxcontacts = MT_DEFAULT_MAXCONTACT; mt_post_parse(td); if (td->serial_maybe) mt_post_parse_default_settings(td); if (cls->is_indirect) td->mt_flags |= INPUT_MT_POINTER; if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) td->mt_flags |= INPUT_MT_DROP_UNUSED; input_mt_init_slots(input, td->maxcontacts, td->mt_flags); td->mt_flags = 0; } static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; Loading Loading @@ -722,6 +713,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) goto fail; } if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) td->serial_maybe = true; ret = hid_parse(hdev); if (ret != 0) goto fail; Loading @@ -730,20 +724,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret) goto fail; mt_post_parse(td); if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) mt_post_parse_default_settings(td); td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), GFP_KERNEL); if (!td->slots) { dev_err(&hdev->dev, "cannot allocate multitouch slots\n"); hid_hw_stop(hdev); ret = -ENOMEM; goto fail; } ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); mt_set_maxcontacts(hdev); Loading Loading @@ -774,7 +754,6 @@ static void mt_remove(struct hid_device *hdev) struct mt_device *td = hid_get_drvdata(hdev); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); hid_hw_stop(hdev); kfree(td->slots); kfree(td); hid_set_drvdata(hdev, NULL); } Loading Loading @@ -892,6 +871,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) }, /* Flatfrog Panels */ { .driver_data = MT_CLS_FLATFROG, MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, USB_DEVICE_ID_MULTITOUCH_3200) }, /* GeneralTouch panel */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, Loading Loading @@ -1087,6 +1071,7 @@ static struct hid_driver mt_driver = { .remove = mt_remove, .input_mapping = mt_input_mapping, .input_mapped = mt_input_mapped, .input_configured = mt_input_configured, .feature_mapping = mt_feature_mapping, .usage_table = mt_grabbed_usages, .event = mt_event, Loading
drivers/input/evdev.c +86 −91 Original line number Diff line number Diff line Loading @@ -23,11 +23,11 @@ #include <linux/input/mt.h> #include <linux/major.h> #include <linux/device.h> #include <linux/cdev.h> #include "input-compat.h" struct evdev { int open; int minor; struct input_handle handle; wait_queue_head_t wait; struct evdev_client __rcu *grab; Loading @@ -35,6 +35,7 @@ struct evdev { spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; struct cdev cdev; bool exist; }; Loading @@ -51,19 +52,9 @@ struct evdev_client { struct input_event buffer[]; }; static struct evdev *evdev_table[EVDEV_MINORS]; static DEFINE_MUTEX(evdev_table_mutex); static void evdev_pass_event(struct evdev_client *client, struct input_event *event, ktime_t mono, ktime_t real) static void __pass_event(struct evdev_client *client, const struct input_event *event) { event->time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? mono : real); /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); client->buffer[client->head++] = *event; client->head &= client->bufsize - 1; Loading @@ -86,42 +77,74 @@ static void evdev_pass_event(struct evdev_client *client, client->packet_head = client->head; kill_fasync(&client->fasync, SIGIO, POLL_IN); } } static void evdev_pass_values(struct evdev_client *client, const struct input_value *vals, unsigned int count, ktime_t mono, ktime_t real) { struct evdev *evdev = client->evdev; const struct input_value *v; struct input_event event; bool wakeup = false; event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ? mono : real); /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); for (v = vals; v != vals + count; v++) { event.type = v->type; event.code = v->code; event.value = v->value; __pass_event(client, &event); if (v->type == EV_SYN && v->code == SYN_REPORT) wakeup = true; } spin_unlock(&client->buffer_lock); if (wakeup) wake_up_interruptible(&evdev->wait); } /* * Pass incoming event to all connected clients. * Pass incoming events to all connected clients. */ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) static void evdev_events(struct input_handle *handle, const struct input_value *vals, unsigned int count) { struct evdev *evdev = handle->private; struct evdev_client *client; struct input_event event; ktime_t time_mono, time_real; time_mono = ktime_get(); time_real = ktime_sub(time_mono, ktime_get_monotonic_offset()); event.type = type; event.code = code; event.value = value; rcu_read_lock(); client = rcu_dereference(evdev->grab); if (client) evdev_pass_event(client, &event, time_mono, time_real); evdev_pass_values(client, vals, count, time_mono, time_real); else list_for_each_entry_rcu(client, &evdev->client_list, node) evdev_pass_event(client, &event, time_mono, time_real); evdev_pass_values(client, vals, count, time_mono, time_real); rcu_read_unlock(); } if (type == EV_SYN && code == SYN_REPORT) wake_up_interruptible(&evdev->wait); /* * Pass incoming event to all connected clients. */ static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct input_value vals[] = { { type, code, value } }; evdev_events(handle, vals, 1); } static int evdev_fasync(int fd, struct file *file, int on) Loading Loading @@ -285,35 +308,16 @@ static unsigned int evdev_compute_buffer_size(struct input_dev *dev) static int evdev_open(struct inode *inode, struct file *file) { struct evdev *evdev; struct evdev *evdev = container_of(inode->i_cdev, struct evdev, cdev); unsigned int bufsize = evdev_compute_buffer_size(evdev->handle.dev); struct evdev_client *client; int i = iminor(inode) - EVDEV_MINOR_BASE; unsigned int bufsize; int error; if (i >= EVDEV_MINORS) return -ENODEV; error = mutex_lock_interruptible(&evdev_table_mutex); if (error) return error; evdev = evdev_table[i]; if (evdev) get_device(&evdev->dev); mutex_unlock(&evdev_table_mutex); if (!evdev) return -ENODEV; bufsize = evdev_compute_buffer_size(evdev->handle.dev); client = kzalloc(sizeof(struct evdev_client) + bufsize * sizeof(struct input_event), GFP_KERNEL); if (!client) { error = -ENOMEM; goto err_put_evdev; } if (!client) return -ENOMEM; client->bufsize = bufsize; spin_lock_init(&client->buffer_lock); Loading @@ -327,13 +331,12 @@ static int evdev_open(struct inode *inode, struct file *file) file->private_data = client; nonseekable_open(inode, file); get_device(&evdev->dev); return 0; err_free_client: evdev_detach_client(evdev, client); kfree(client); err_put_evdev: put_device(&evdev->dev); return error; } Loading Loading @@ -653,20 +656,22 @@ static int evdev_handle_mt_request(struct input_dev *dev, unsigned int size, int __user *ip) { const struct input_mt_slot *mt = dev->mt; const struct input_mt *mt = dev->mt; unsigned int code; int max_slots; int i; if (get_user(code, &ip[0])) return -EFAULT; if (!input_is_mt_value(code)) if (!mt || !input_is_mt_value(code)) return -EINVAL; max_slots = (size - sizeof(__u32)) / sizeof(__s32); for (i = 0; i < dev->mtsize && i < max_slots; i++) if (put_user(input_mt_get_value(&mt[i], code), &ip[1 + i])) for (i = 0; i < mt->num_slots && i < max_slots; i++) { int value = input_mt_get_value(&mt->slots[i], code); if (put_user(value, &ip[1 + i])) return -EFAULT; } return 0; } Loading Loading @@ -915,26 +920,6 @@ static const struct file_operations evdev_fops = { .llseek = no_llseek, }; static int evdev_install_chrdev(struct evdev *evdev) { /* * No need to do any locking here as calls to connect and * disconnect are serialized by the input core */ evdev_table[evdev->minor] = evdev; return 0; } static void evdev_remove_chrdev(struct evdev *evdev) { /* * Lock evdev table to prevent race with evdev_open() */ mutex_lock(&evdev_table_mutex); evdev_table[evdev->minor] = NULL; mutex_unlock(&evdev_table_mutex); } /* * Mark device non-existent. This disables writes, ioctls and * prevents new users from opening the device. Already posted Loading @@ -953,7 +938,8 @@ static void evdev_cleanup(struct evdev *evdev) evdev_mark_dead(evdev); evdev_hangup(evdev); evdev_remove_chrdev(evdev); cdev_del(&evdev->cdev); /* evdev is marked dead so no one else accesses evdev->open */ if (evdev->open) { Loading @@ -964,43 +950,47 @@ static void evdev_cleanup(struct evdev *evdev) /* * Create new evdev device. Note that input core serializes calls * to connect and disconnect so we don't need to lock evdev_table here. * to connect and disconnect. */ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id) { struct evdev *evdev; int minor; int dev_no; int error; for (minor = 0; minor < EVDEV_MINORS; minor++) if (!evdev_table[minor]) break; if (minor == EVDEV_MINORS) { pr_err("no more free evdev devices\n"); return -ENFILE; minor = input_get_new_minor(EVDEV_MINOR_BASE, EVDEV_MINORS, true); if (minor < 0) { error = minor; pr_err("failed to reserve new minor: %d\n", error); return error; } evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); if (!evdev) return -ENOMEM; if (!evdev) { error = -ENOMEM; goto err_free_minor; } INIT_LIST_HEAD(&evdev->client_list); spin_lock_init(&evdev->client_lock); mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); dev_set_name(&evdev->dev, "event%d", minor); evdev->exist = true; evdev->minor = minor; dev_no = minor; /* Normalize device number if it falls into legacy range */ if (dev_no < EVDEV_MINOR_BASE + EVDEV_MINORS) dev_no -= EVDEV_MINOR_BASE; dev_set_name(&evdev->dev, "event%d", dev_no); evdev->handle.dev = input_get_device(dev); evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); evdev->dev.devt = MKDEV(INPUT_MAJOR, minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; evdev->dev.release = evdev_free; Loading @@ -1010,7 +1000,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, if (error) goto err_free_evdev; error = evdev_install_chrdev(evdev); cdev_init(&evdev->cdev, &evdev_fops); error = cdev_add(&evdev->cdev, evdev->dev.devt, 1); if (error) goto err_unregister_handle; Loading @@ -1026,6 +1017,8 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, input_unregister_handle(&evdev->handle); err_free_evdev: put_device(&evdev->dev); err_free_minor: input_free_minor(minor); return error; } Loading @@ -1035,6 +1028,7 @@ static void evdev_disconnect(struct input_handle *handle) device_del(&evdev->dev); evdev_cleanup(evdev); input_free_minor(MINOR(evdev->dev.devt)); input_unregister_handle(handle); put_device(&evdev->dev); } Loading @@ -1048,9 +1042,10 @@ MODULE_DEVICE_TABLE(input, evdev_ids); static struct input_handler evdev_handler = { .event = evdev_event, .events = evdev_events, .connect = evdev_connect, .disconnect = evdev_disconnect, .fops = &evdev_fops, .legacy_minors = true, .minor = EVDEV_MINOR_BASE, .name = "evdev", .id_table = evdev_ids, Loading