HID: move tmff and zpff devices from ignore_list to blacklist
[safe/jmp/linux-2.6] / drivers / hid / hid-core.c
index 8624a8f..1cc9674 100644 (file)
@@ -1218,6 +1218,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
 }
 EXPORT_SYMBOL_GPL(hid_connect);
 
+/* a list of devices for which there is a specialized driver on HID bus */
 static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
        { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
@@ -1265,6 +1266,7 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
@@ -1292,23 +1294,111 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
 
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
        { }
 };
 
+struct hid_dynid {
+       struct list_head list;
+       struct hid_device_id id;
+};
+
+/**
+ * store_new_id - add a new HID device ID to this driver and re-probe devices
+ * @driver: target device driver
+ * @buf: buffer for scanning device ID data
+ * @count: input size
+ *
+ * Adds a new dynamic hid device ID to this driver,
+ * and causes the driver to probe for all devices again.
+ */
+static ssize_t store_new_id(struct device_driver *drv, const char *buf,
+               size_t count)
+{
+       struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
+       struct hid_dynid *dynid;
+       __u32 bus, vendor, product;
+       unsigned long driver_data = 0;
+       int ret;
+
+       ret = sscanf(buf, "%x %x %x %lx",
+                       &bus, &vendor, &product, &driver_data);
+       if (ret < 3)
+               return -EINVAL;
+
+       dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
+       if (!dynid)
+               return -ENOMEM;
+
+       dynid->id.bus = bus;
+       dynid->id.vendor = vendor;
+       dynid->id.product = product;
+       dynid->id.driver_data = driver_data;
+
+       spin_lock(&hdrv->dyn_lock);
+       list_add_tail(&dynid->list, &hdrv->dyn_list);
+       spin_unlock(&hdrv->dyn_lock);
+
+       ret = 0;
+       if (get_driver(&hdrv->driver)) {
+               ret = driver_attach(&hdrv->driver);
+               put_driver(&hdrv->driver);
+       }
+
+       return ret ? : count;
+}
+static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
+
+static void hid_free_dynids(struct hid_driver *hdrv)
+{
+       struct hid_dynid *dynid, *n;
+
+       spin_lock(&hdrv->dyn_lock);
+       list_for_each_entry_safe(dynid, n, &hdrv->dyn_list, list) {
+               list_del(&dynid->list);
+               kfree(dynid);
+       }
+       spin_unlock(&hdrv->dyn_lock);
+}
+
+static const struct hid_device_id *hid_match_device(struct hid_device *hdev,
+               struct hid_driver *hdrv)
+{
+       struct hid_dynid *dynid;
+
+       spin_lock(&hdrv->dyn_lock);
+       list_for_each_entry(dynid, &hdrv->dyn_list, list) {
+               if (hid_match_one_id(hdev, &dynid->id)) {
+                       spin_unlock(&hdrv->dyn_lock);
+                       return &dynid->id;
+               }
+       }
+       spin_unlock(&hdrv->dyn_lock);
+
+       return hid_match_id(hdev, hdrv->id_table);
+}
+
 static int hid_bus_match(struct device *dev, struct device_driver *drv)
 {
        struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
        struct hid_device *hdev = container_of(dev, struct hid_device, dev);
 
-       if (!hid_match_id(hdev, hdrv->id_table))
+       if (!hid_match_device(hdev, hdrv))
                return 0;
 
        /* generic wants all non-blacklisted */
@@ -1327,7 +1417,7 @@ static int hid_device_probe(struct device *dev)
        int ret = 0;
 
        if (!hdev->driver) {
-               id = hid_match_id(hdev, hdrv->id_table);
+               id = hid_match_device(hdev, hdrv);
                if (id == NULL)
                        return -ENODEV;
 
@@ -1393,6 +1483,7 @@ static struct bus_type hid_bus_type = {
        .uevent         = hid_uevent,
 };
 
+/* a list of devices that shouldn't be handled by HID core at all */
 static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302) },
@@ -1415,6 +1506,7 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
        { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
@@ -1519,15 +1611,14 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD3) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD4) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD5) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
@@ -1538,8 +1629,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
        { }
 };
 
@@ -1694,18 +1783,33 @@ EXPORT_SYMBOL_GPL(hid_destroy_device);
 int __hid_register_driver(struct hid_driver *hdrv, struct module *owner,
                const char *mod_name)
 {
+       int ret;
+
        hdrv->driver.name = hdrv->name;
        hdrv->driver.bus = &hid_bus_type;
        hdrv->driver.owner = owner;
        hdrv->driver.mod_name = mod_name;
 
-       return driver_register(&hdrv->driver);
+       INIT_LIST_HEAD(&hdrv->dyn_list);
+       spin_lock_init(&hdrv->dyn_lock);
+
+       ret = driver_register(&hdrv->driver);
+       if (ret)
+               return ret;
+
+       ret = driver_create_file(&hdrv->driver, &driver_attr_new_id);
+       if (ret)
+               driver_unregister(&hdrv->driver);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(__hid_register_driver);
 
 void hid_unregister_driver(struct hid_driver *hdrv)
 {
+       driver_remove_file(&hdrv->driver, &driver_attr_new_id);
        driver_unregister(&hdrv->driver);
+       hid_free_dynids(hdrv);
 }
 EXPORT_SYMBOL_GPL(hid_unregister_driver);