HID: hid-motorola: whisper HID driver
authorRamesh Sudini <ramesh.sudini@motorola.com>
Thu, 19 Aug 2010 18:21:37 +0000 (13:21 -0500)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:33:38 +0000 (16:33 -0700)
Signed-off-by: Ramesh Sudini <ramesh.sudini@motorola.com>
Signed-off-by: Nick Pelly <npelly@google.com>
Change-Id: I63a1c5358f8536916e29d18e298ea495deddcbae

drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-motorola.c [new file with mode: 0644]

index 6369ba7f96f8c0cb2bce6ae0301fd2962027f914..874851a2bcfd698fca5a8edd53913c47d86ec184 100644 (file)
@@ -264,6 +264,13 @@ config HID_MONTEREY
        ---help---
        Support for Monterey Genius KB29E.
 
+config HID_MOTOROLA
+       tristate "Motorola" if EMBEDDED
+       depends on USB_HID
+       default !EMBEDDED
+       ---help---
+       Support for Motorola HID devices
+
 config HID_NTRIG
        tristate "NTrig"
        depends on USB_HID
index 46f037f3df80ae4eefc30b64df583ff48b894534..cbd9b40dfd120aab617f2291ce0a8f12a1db425e 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_HID_MAGICMOUSE)    += hid-magicmouse.o
 obj-$(CONFIG_HID_MICROSOFT)    += hid-microsoft.o
 obj-$(CONFIG_HID_MONTEREY)     += hid-monterey.o
 obj-$(CONFIG_HID_MOSART)       += hid-mosart.o
+obj-$(CONFIG_HID_MOTOROLA)     += hid-motorola.o
 obj-$(CONFIG_HID_NTRIG)                += hid-ntrig.o
 obj-$(CONFIG_HID_ORTEK)                += hid-ortek.o
 obj-$(CONFIG_HID_PRODIKEYS)    += hid-prodikeys.o
index 3f7292486024b8feace0b72775c03a2ae122e8fc..1d11991e409e3241e3cdd21e21717035fc3f0cfa 100644 (file)
@@ -1346,6 +1346,7 @@ 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_MOTOROLA, USB_DEVICE_ID_HD_DOCK) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) },
index 765a4f53eb5cb663fd319d0a71386ae1a9ee0fa5..b95759a2c8275ca9da525a99a0689cf9fd9c99f5 100644 (file)
 #define USB_VENDOR_ID_MONTEREY         0x0566
 #define USB_DEVICE_ID_GENIUS_KB29E     0x3004
 
+#define USB_VENDOR_ID_MOTOROLA         0x22b8
+#define USB_DEVICE_ID_HD_DOCK          0x0938
+
 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
 #define USB_DEVICE_ID_N_S_HARMONY      0xc359
 
diff --git a/drivers/hid/hid-motorola.c b/drivers/hid/hid-motorola.c
new file mode 100644 (file)
index 0000000..e7a2c4e
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2010 Motorola, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+#include <linux/switch.h>
+#include <linux/spi/cpcap.h>
+
+#include "hid-ids.h"
+
+#define MOT_SEMU        0x0001
+#define MOT_IR_REMOTE  0x0002
+#define MOT_AUDIO_JACK 0x0004
+
+#define AUDIO_JACK_STATUS_REPORT    0x3E
+
+static struct switch_dev sdev;
+
+struct motorola_sc {
+       unsigned long quirks;
+       unsigned long audio_cable_inserted;
+       struct work_struct work;
+};
+
+static void audio_jack_status_work(struct work_struct *work)
+{
+       struct motorola_sc *sc = container_of(work, struct motorola_sc, work);
+
+       /* TODO: Action on Audio Cable insertion. */
+
+}
+
+static int mot_rawevent(struct hid_device *hdev, struct hid_report *report,
+                    u8 *data, int size)
+{
+       struct motorola_sc *sc = hid_get_drvdata(hdev);
+
+       dbg_hid("%s\n", __func__);
+
+       if (sc->quirks & MOT_AUDIO_JACK) {
+               if (data[0] == AUDIO_JACK_STATUS_REPORT) {
+                       sc->audio_cable_inserted = data[1];
+                       schedule_work(&sc->work);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int mot_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+       unsigned long quirks = id->driver_data;
+       struct motorola_sc *sc;
+       unsigned int connect_mask = 0;
+
+       dbg_hid("%s %d\n", __func__, __LINE__);
+
+       sc = kzalloc(sizeof(*sc), GFP_KERNEL);
+       if (sc == NULL) {
+               dev_err(&hdev->dev, "can't alloc motorola descriptor\n");
+               return -ENOMEM;
+       }
+
+       sc->quirks = quirks;
+       hid_set_drvdata(hdev, sc);
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               dev_err(&hdev->dev, "parse failed\n");
+               goto err_free;
+       }
+
+       if (quirks & MOT_SEMU)
+               connect_mask |= HID_CONNECT_HIDRAW;
+       if (quirks & MOT_IR_REMOTE)
+               connect_mask |= (HID_CONNECT_HIDINPUT |
+                               HID_CONNECT_HIDINPUT_FORCE);
+       if (quirks & MOT_AUDIO_JACK)
+               INIT_WORK(&sc->work, audio_jack_status_work);
+
+       ret = hid_hw_start(hdev, connect_mask);
+       if (ret) {
+               dev_err(&hdev->dev, "hw start failed\n");
+               goto err_free_cancel;
+       }
+
+       switch_set_state(&sdev, 1);
+
+       dbg_hid("%s %d\n", __func__, __LINE__);
+       return 0;
+
+err_free_cancel:
+       cancel_work_sync(&sc->work);
+err_free:
+       kfree(sc);
+       return ret;
+}
+
+static void mot_remove(struct hid_device *hdev)
+{
+       struct motorola_sc *sc = hid_get_drvdata(hdev);
+
+       dbg_hid("%s\n", __func__);
+
+       cancel_work_sync(&sc->work);
+
+       switch_set_state(&sdev, 0);
+
+       hid_hw_stop(hdev);
+       kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id mot_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_MOTOROLA, USB_DEVICE_ID_HD_DOCK),
+       .driver_data = MOT_SEMU | MOT_IR_REMOTE | MOT_AUDIO_JACK },
+       {}
+};
+MODULE_DEVICE_TABLE(hid, mot_devices);
+
+static const struct hid_report_id mot_reports[] = {
+       { HID_INPUT_REPORT },
+       { HID_TERMINATOR }
+};
+
+static struct hid_driver motorola_driver = {
+       .name = "motorola",
+       .id_table = mot_devices,
+       .probe = mot_probe,
+       .remove = mot_remove,
+       .raw_event = mot_rawevent,
+       .report_table = mot_reports,
+};
+
+static int motorola_init(void)
+{
+       int ret;
+
+       dbg_hid("Registering MOT HID driver\n");
+
+       ret = hid_register_driver(&motorola_driver);
+       if (ret)
+               printk(KERN_ERR "Can't register Motorola driver\n");
+
+       sdev.name = "whisper_hid";
+       switch_dev_register(&sdev);
+
+       return ret;
+}
+
+static void motorola_exit(void)
+{
+       switch_dev_unregister(&sdev);
+       hid_unregister_driver(&motorola_driver);
+}
+
+module_init(motorola_init);
+module_exit(motorola_exit);
+MODULE_LICENSE("GPL");