|
@@ -97,18 +97,266 @@ MODULE_PARM_DESC(no_spic,
|
|
|
static int compat; /* = 0 */
|
|
|
module_param(compat, int, 0444);
|
|
|
MODULE_PARM_DESC(compat,
|
|
|
- "set this if you want to enable backward compatibility mode");
|
|
|
-
|
|
|
-static int force_jog; /* = 0 */
|
|
|
-module_param(force_jog, int, 0444);
|
|
|
-MODULE_PARM_DESC(force_jog,
|
|
|
- "set this if the driver doesn't detect your jogdial");
|
|
|
+ "set this if you want to enable backward compatibility mode for SPIC");
|
|
|
|
|
|
static unsigned long mask = 0xffffffff;
|
|
|
module_param(mask, ulong, 0644);
|
|
|
MODULE_PARM_DESC(mask,
|
|
|
"set this to the mask of event you want to enable (see doc)");
|
|
|
|
|
|
+/*********** Input Devices ***********/
|
|
|
+
|
|
|
+#define SONY_LAPTOP_BUF_SIZE 128
|
|
|
+struct sony_laptop_input_s {
|
|
|
+ atomic_t users;
|
|
|
+ struct input_dev *jog_dev;
|
|
|
+ struct input_dev *key_dev;
|
|
|
+ struct kfifo *fifo;
|
|
|
+ spinlock_t fifo_lock;
|
|
|
+ struct workqueue_struct *wq;
|
|
|
+};
|
|
|
+static struct sony_laptop_input_s sony_laptop_input = {
|
|
|
+ .users = ATOMIC_INIT(0),
|
|
|
+};
|
|
|
+
|
|
|
+struct sony_laptop_keypress {
|
|
|
+ struct input_dev *dev;
|
|
|
+ int key;
|
|
|
+};
|
|
|
+
|
|
|
+/* Correspondance table between sonypi events and input layer events */
|
|
|
+static struct {
|
|
|
+ int sonypiev;
|
|
|
+ int inputev;
|
|
|
+} sony_laptop_inputkeys[] = {
|
|
|
+ { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
|
|
|
+ { SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
|
|
|
+ { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
|
|
|
+ { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
|
|
|
+ { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
|
|
|
+ { SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
|
|
|
+ { SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
|
|
|
+ { SONYPI_EVENT_FNKEY_D, KEY_FN_D },
|
|
|
+ { SONYPI_EVENT_FNKEY_E, KEY_FN_E },
|
|
|
+ { SONYPI_EVENT_FNKEY_F, KEY_FN_F },
|
|
|
+ { SONYPI_EVENT_FNKEY_S, KEY_FN_S },
|
|
|
+ { SONYPI_EVENT_FNKEY_B, KEY_FN_B },
|
|
|
+ { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
|
|
|
+ { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
|
|
|
+ { SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
|
|
|
+ { SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
|
|
|
+ { SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
|
|
|
+ { SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
|
|
|
+ { SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
|
|
|
+ { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
|
|
|
+ { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
|
|
|
+ { 0, 0 },
|
|
|
+};
|
|
|
+
|
|
|
+/* release buttons after a short delay if pressed */
|
|
|
+static void do_sony_laptop_release_key(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct sony_laptop_keypress kp;
|
|
|
+
|
|
|
+ while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp,
|
|
|
+ sizeof(kp)) == sizeof(kp)) {
|
|
|
+ msleep(10);
|
|
|
+ input_report_key(kp.dev, kp.key, 0);
|
|
|
+ input_sync(kp.dev);
|
|
|
+ }
|
|
|
+}
|
|
|
+static DECLARE_WORK(sony_laptop_release_key_work,
|
|
|
+ do_sony_laptop_release_key);
|
|
|
+
|
|
|
+/* forward event to the input subsytem */
|
|
|
+static void sony_laptop_report_input_event(u8 event)
|
|
|
+{
|
|
|
+ struct input_dev *jog_dev = sony_laptop_input.jog_dev;
|
|
|
+ struct input_dev *key_dev = sony_laptop_input.key_dev;
|
|
|
+ struct sony_laptop_keypress kp = { NULL };
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (event == SONYPI_EVENT_FNKEY_RELEASED) {
|
|
|
+ /* Nothing, not all VAIOs generate this event */
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* report events */
|
|
|
+ switch (event) {
|
|
|
+ /* jog_dev events */
|
|
|
+ case SONYPI_EVENT_JOGDIAL_UP:
|
|
|
+ case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
|
|
|
+ input_report_rel(jog_dev, REL_WHEEL, 1);
|
|
|
+ input_sync(jog_dev);
|
|
|
+ return;
|
|
|
+
|
|
|
+ case SONYPI_EVENT_JOGDIAL_DOWN:
|
|
|
+ case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
|
|
|
+ input_report_rel(jog_dev, REL_WHEEL, -1);
|
|
|
+ input_sync(jog_dev);
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* key_dev events */
|
|
|
+ case SONYPI_EVENT_JOGDIAL_PRESSED:
|
|
|
+ kp.key = BTN_MIDDLE;
|
|
|
+ kp.dev = jog_dev;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
|
|
|
+ if (event == sony_laptop_inputkeys[i].sonypiev) {
|
|
|
+ kp.dev = key_dev;
|
|
|
+ kp.key = sony_laptop_inputkeys[i].inputev;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (kp.dev) {
|
|
|
+ input_report_key(kp.dev, kp.key, 1);
|
|
|
+ input_sync(kp.dev);
|
|
|
+ kfifo_put(sony_laptop_input.fifo,
|
|
|
+ (unsigned char *)&kp, sizeof(kp));
|
|
|
+
|
|
|
+ if (!work_pending(&sony_laptop_release_key_work))
|
|
|
+ queue_work(sony_laptop_input.wq,
|
|
|
+ &sony_laptop_release_key_work);
|
|
|
+ } else
|
|
|
+ dprintk("unknown input event %.2x\n", event);
|
|
|
+}
|
|
|
+
|
|
|
+static int sony_laptop_setup_input(void)
|
|
|
+{
|
|
|
+ struct input_dev *jog_dev;
|
|
|
+ struct input_dev *key_dev;
|
|
|
+ int i;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ /* don't run again if already initialized */
|
|
|
+ if (atomic_add_return(1, &sony_laptop_input.users) > 1)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* kfifo */
|
|
|
+ spin_lock_init(&sony_laptop_input.fifo_lock);
|
|
|
+ sony_laptop_input.fifo =
|
|
|
+ kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL,
|
|
|
+ &sony_laptop_input.fifo_lock);
|
|
|
+ if (IS_ERR(sony_laptop_input.fifo)) {
|
|
|
+ printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
|
|
|
+ error = PTR_ERR(sony_laptop_input.fifo);
|
|
|
+ goto err_dec_users;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* init workqueue */
|
|
|
+ sony_laptop_input.wq = create_singlethread_workqueue("sony-laptop");
|
|
|
+ if (!sony_laptop_input.wq) {
|
|
|
+ printk(KERN_ERR DRV_PFX
|
|
|
+ "Unabe to create workqueue.\n");
|
|
|
+ error = -ENXIO;
|
|
|
+ goto err_free_kfifo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* input keys */
|
|
|
+ key_dev = input_allocate_device();
|
|
|
+ if (!key_dev) {
|
|
|
+ error = -ENOMEM;
|
|
|
+ goto err_destroy_wq;
|
|
|
+ }
|
|
|
+
|
|
|
+ key_dev->name = "Sony Vaio Keys";
|
|
|
+ key_dev->id.bustype = BUS_ISA;
|
|
|
+ key_dev->id.vendor = PCI_VENDOR_ID_SONY;
|
|
|
+
|
|
|
+ /* Initialize the Input Drivers: special keys */
|
|
|
+ key_dev->evbit[0] = BIT(EV_KEY);
|
|
|
+ for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
|
|
|
+ if (sony_laptop_inputkeys[i].inputev)
|
|
|
+ set_bit(sony_laptop_inputkeys[i].inputev,
|
|
|
+ key_dev->keybit);
|
|
|
+
|
|
|
+ error = input_register_device(key_dev);
|
|
|
+ if (error)
|
|
|
+ goto err_free_keydev;
|
|
|
+
|
|
|
+ sony_laptop_input.key_dev = key_dev;
|
|
|
+
|
|
|
+ /* jogdial */
|
|
|
+ jog_dev = input_allocate_device();
|
|
|
+ if (!jog_dev) {
|
|
|
+ error = -ENOMEM;
|
|
|
+ goto err_unregister_keydev;
|
|
|
+ }
|
|
|
+
|
|
|
+ jog_dev->name = "Sony Vaio Jogdial";
|
|
|
+ jog_dev->id.bustype = BUS_ISA;
|
|
|
+ jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
|
|
|
+
|
|
|
+ jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
|
|
+ jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
|
|
|
+ jog_dev->relbit[0] = BIT(REL_WHEEL);
|
|
|
+
|
|
|
+ error = input_register_device(jog_dev);
|
|
|
+ if (error)
|
|
|
+ goto err_free_jogdev;
|
|
|
+
|
|
|
+ sony_laptop_input.jog_dev = jog_dev;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err_free_jogdev:
|
|
|
+ input_free_device(jog_dev);
|
|
|
+
|
|
|
+err_unregister_keydev:
|
|
|
+ input_unregister_device(key_dev);
|
|
|
+ /* to avoid kref underflow below at input_free_device */
|
|
|
+ key_dev = NULL;
|
|
|
+
|
|
|
+err_free_keydev:
|
|
|
+ input_free_device(key_dev);
|
|
|
+
|
|
|
+err_destroy_wq:
|
|
|
+ destroy_workqueue(sony_laptop_input.wq);
|
|
|
+
|
|
|
+err_free_kfifo:
|
|
|
+ kfifo_free(sony_laptop_input.fifo);
|
|
|
+
|
|
|
+err_dec_users:
|
|
|
+ atomic_dec(&sony_laptop_input.users);
|
|
|
+ return error;
|
|
|
+}
|
|
|
+
|
|
|
+static void sony_laptop_remove_input(void)
|
|
|
+{
|
|
|
+ /* cleanup only after the last user has gone */
|
|
|
+ if (!atomic_dec_and_test(&sony_laptop_input.users))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* flush workqueue first */
|
|
|
+ flush_workqueue(sony_laptop_input.wq);
|
|
|
+
|
|
|
+ /* destroy input devs */
|
|
|
+ input_unregister_device(sony_laptop_input.key_dev);
|
|
|
+ sony_laptop_input.key_dev = NULL;
|
|
|
+
|
|
|
+ if (sony_laptop_input.jog_dev) {
|
|
|
+ input_unregister_device(sony_laptop_input.jog_dev);
|
|
|
+ sony_laptop_input.jog_dev = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ destroy_workqueue(sony_laptop_input.wq);
|
|
|
+ kfifo_free(sony_laptop_input.fifo);
|
|
|
+}
|
|
|
+
|
|
|
/*********** Platform Device ***********/
|
|
|
|
|
|
static atomic_t sony_pf_users = ATOMIC_INIT(0);
|
|
@@ -428,6 +676,7 @@ static struct backlight_ops sony_backlight_ops = {
|
|
|
static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
|
|
|
{
|
|
|
dprintk("sony_acpi_notify, event: %d\n", event);
|
|
|
+ sony_laptop_report_input_event(event);
|
|
|
acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
|
|
|
}
|
|
|
|
|
@@ -490,13 +739,21 @@ static int sony_nc_add(struct acpi_device *device)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /* setup input devices and helper fifo */
|
|
|
+ result = sony_laptop_setup_input();
|
|
|
+ if (result) {
|
|
|
+ printk(KERN_ERR DRV_PFX
|
|
|
+ "Unabe to create input devices.\n");
|
|
|
+ goto outwalk;
|
|
|
+ }
|
|
|
+
|
|
|
status = acpi_install_notify_handler(sony_nc_acpi_handle,
|
|
|
ACPI_DEVICE_NOTIFY,
|
|
|
sony_acpi_notify, NULL);
|
|
|
if (ACPI_FAILURE(status)) {
|
|
|
printk(LOG_PFX "unable to install notify handler\n");
|
|
|
result = -ENODEV;
|
|
|
- goto outwalk;
|
|
|
+ goto outinput;
|
|
|
}
|
|
|
|
|
|
if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", &handle))) {
|
|
@@ -568,6 +825,7 @@ static int sony_nc_add(struct acpi_device *device)
|
|
|
device_remove_file(&sony_pf_device->dev, &item->devattr);
|
|
|
}
|
|
|
sony_pf_remove();
|
|
|
+
|
|
|
outbacklight:
|
|
|
if (sony_backlight_device)
|
|
|
backlight_device_unregister(sony_backlight_device);
|
|
@@ -577,6 +835,10 @@ static int sony_nc_add(struct acpi_device *device)
|
|
|
sony_acpi_notify);
|
|
|
if (ACPI_FAILURE(status))
|
|
|
printk(LOG_PFX "unable to remove notify handler\n");
|
|
|
+
|
|
|
+ outinput:
|
|
|
+ sony_laptop_remove_input();
|
|
|
+
|
|
|
outwalk:
|
|
|
return result;
|
|
|
}
|
|
@@ -602,6 +864,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
|
|
|
}
|
|
|
|
|
|
sony_pf_remove();
|
|
|
+ sony_laptop_remove_input();
|
|
|
|
|
|
printk(KERN_INFO SONY_NC_DRIVER_NAME " successfully removed\n");
|
|
|
|
|
@@ -626,13 +889,8 @@ static struct acpi_driver sony_nc_driver = {
|
|
|
#define SONYPI_DEVICE_TYPE2 0x00000002
|
|
|
#define SONYPI_DEVICE_TYPE3 0x00000004
|
|
|
|
|
|
-#define SONY_EC_JOGB 0x82
|
|
|
-#define SONY_EC_JOGB_MASK 0x02
|
|
|
-
|
|
|
#define SONY_PIC_EV_MASK 0xff
|
|
|
|
|
|
-#define SONYPI_BUF_SIZE 128
|
|
|
-
|
|
|
struct sony_pic_ioport {
|
|
|
struct acpi_resource_io io;
|
|
|
struct list_head list;
|
|
@@ -650,12 +908,6 @@ struct sony_pic_dev {
|
|
|
struct sony_pic_ioport *cur_ioport;
|
|
|
struct list_head interrupts;
|
|
|
struct list_head ioports;
|
|
|
-
|
|
|
- struct input_dev *input_jog_dev;
|
|
|
- struct input_dev *input_key_dev;
|
|
|
- struct kfifo *input_fifo;
|
|
|
- spinlock_t input_fifo_lock;
|
|
|
- struct workqueue_struct *sony_pic_wq;
|
|
|
};
|
|
|
|
|
|
static struct sony_pic_dev spic_dev = {
|
|
@@ -929,250 +1181,9 @@ static u8 sony_pic_call2(u8 dev, u8 fn)
|
|
|
return v1;
|
|
|
}
|
|
|
|
|
|
-/*****************
|
|
|
- *
|
|
|
- * INPUT Device
|
|
|
- *
|
|
|
- *****************/
|
|
|
-struct sony_pic_keypress {
|
|
|
- struct input_dev *dev;
|
|
|
- int key;
|
|
|
-};
|
|
|
-
|
|
|
-/* Correspondance table between sonypi events and input layer events */
|
|
|
-static struct {
|
|
|
- int sonypiev;
|
|
|
- int inputev;
|
|
|
-} sony_pic_inputkeys[] = {
|
|
|
- { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
|
|
|
- { SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
|
|
|
- { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
|
|
|
- { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
|
|
|
- { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
|
|
|
- { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
|
|
|
- { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
|
|
|
- { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
|
|
|
- { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
|
|
|
- { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
|
|
|
- { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
|
|
|
- { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
|
|
|
- { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
|
|
|
- { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
|
|
|
- { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
|
|
|
- { SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
|
|
|
- { SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
|
|
|
- { SONYPI_EVENT_FNKEY_D, KEY_FN_D },
|
|
|
- { SONYPI_EVENT_FNKEY_E, KEY_FN_E },
|
|
|
- { SONYPI_EVENT_FNKEY_F, KEY_FN_F },
|
|
|
- { SONYPI_EVENT_FNKEY_S, KEY_FN_S },
|
|
|
- { SONYPI_EVENT_FNKEY_B, KEY_FN_B },
|
|
|
- { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
|
|
|
- { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
|
|
|
- { SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
|
|
|
- { SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
|
|
|
- { SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
|
|
|
- { SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
|
|
|
- { SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
|
|
|
- { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
|
|
|
- { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
|
|
|
- { 0, 0 },
|
|
|
-};
|
|
|
-
|
|
|
-/* release buttons after a short delay if pressed */
|
|
|
-static void do_sony_pic_release_key(struct work_struct *work)
|
|
|
-{
|
|
|
- struct sony_pic_keypress kp;
|
|
|
-
|
|
|
- while (kfifo_get(spic_dev.input_fifo, (unsigned char *)&kp,
|
|
|
- sizeof(kp)) == sizeof(kp)) {
|
|
|
- msleep(10);
|
|
|
- input_report_key(kp.dev, kp.key, 0);
|
|
|
- input_sync(kp.dev);
|
|
|
- }
|
|
|
-}
|
|
|
-static DECLARE_WORK(sony_pic_release_key_work,
|
|
|
- do_sony_pic_release_key);
|
|
|
-
|
|
|
-/* forward event to the input subsytem */
|
|
|
-static void sony_pic_report_input_event(u8 event)
|
|
|
-{
|
|
|
- struct input_dev *jog_dev = spic_dev.input_jog_dev;
|
|
|
- struct input_dev *key_dev = spic_dev.input_key_dev;
|
|
|
- struct sony_pic_keypress kp = { NULL };
|
|
|
- int i;
|
|
|
-
|
|
|
- if (event == SONYPI_EVENT_FNKEY_RELEASED) {
|
|
|
- /* Nothing, not all VAIOs generate this event */
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- /* report jog_dev events */
|
|
|
- if (jog_dev) {
|
|
|
- switch (event) {
|
|
|
- case SONYPI_EVENT_JOGDIAL_UP:
|
|
|
- case SONYPI_EVENT_JOGDIAL_UP_PRESSED:
|
|
|
- input_report_rel(jog_dev, REL_WHEEL, 1);
|
|
|
- input_sync(jog_dev);
|
|
|
- return;
|
|
|
-
|
|
|
- case SONYPI_EVENT_JOGDIAL_DOWN:
|
|
|
- case SONYPI_EVENT_JOGDIAL_DOWN_PRESSED:
|
|
|
- input_report_rel(jog_dev, REL_WHEEL, -1);
|
|
|
- input_sync(jog_dev);
|
|
|
- return;
|
|
|
-
|
|
|
- default:
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- switch (event) {
|
|
|
- case SONYPI_EVENT_JOGDIAL_PRESSED:
|
|
|
- kp.key = BTN_MIDDLE;
|
|
|
- kp.dev = jog_dev;
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- for (i = 0; sony_pic_inputkeys[i].sonypiev; i++)
|
|
|
- if (event == sony_pic_inputkeys[i].sonypiev) {
|
|
|
- kp.dev = key_dev;
|
|
|
- kp.key = sony_pic_inputkeys[i].inputev;
|
|
|
- break;
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (kp.dev) {
|
|
|
- input_report_key(kp.dev, kp.key, 1);
|
|
|
- input_sync(kp.dev);
|
|
|
- kfifo_put(spic_dev.input_fifo,
|
|
|
- (unsigned char *)&kp, sizeof(kp));
|
|
|
-
|
|
|
- if (!work_pending(&sony_pic_release_key_work))
|
|
|
- queue_work(spic_dev.sony_pic_wq,
|
|
|
- &sony_pic_release_key_work);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static int sony_pic_setup_input(void)
|
|
|
-{
|
|
|
- struct input_dev *jog_dev;
|
|
|
- struct input_dev *key_dev;
|
|
|
- int i;
|
|
|
- int error;
|
|
|
- u8 jog_present = 0;
|
|
|
-
|
|
|
- /* kfifo */
|
|
|
- spin_lock_init(&spic_dev.input_fifo_lock);
|
|
|
- spic_dev.input_fifo =
|
|
|
- kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
|
|
|
- &spic_dev.input_fifo_lock);
|
|
|
- if (IS_ERR(spic_dev.input_fifo)) {
|
|
|
- printk(KERN_ERR "sonypi: kfifo_alloc failed\n");
|
|
|
- return PTR_ERR(spic_dev.input_fifo);
|
|
|
- }
|
|
|
-
|
|
|
- /* init workqueue */
|
|
|
- spic_dev.sony_pic_wq = create_singlethread_workqueue("sony-pic");
|
|
|
- if (!spic_dev.sony_pic_wq) {
|
|
|
- printk(KERN_ERR DRV_PFX
|
|
|
- "Unabe to create workqueue.\n");
|
|
|
- error = -ENXIO;
|
|
|
- goto err_free_kfifo;
|
|
|
- }
|
|
|
-
|
|
|
- /* input keys */
|
|
|
- key_dev = input_allocate_device();
|
|
|
- if (!key_dev) {
|
|
|
- error = -ENOMEM;
|
|
|
- goto err_destroy_wq;
|
|
|
- }
|
|
|
-
|
|
|
- key_dev->name = "Sony Vaio Keys";
|
|
|
- key_dev->id.bustype = BUS_ISA;
|
|
|
- key_dev->id.vendor = PCI_VENDOR_ID_SONY;
|
|
|
-
|
|
|
- /* Initialize the Input Drivers: special keys */
|
|
|
- key_dev->evbit[0] = BIT(EV_KEY);
|
|
|
- for (i = 0; sony_pic_inputkeys[i].sonypiev; i++)
|
|
|
- if (sony_pic_inputkeys[i].inputev)
|
|
|
- set_bit(sony_pic_inputkeys[i].inputev, key_dev->keybit);
|
|
|
-
|
|
|
- error = input_register_device(key_dev);
|
|
|
- if (error)
|
|
|
- goto err_free_keydev;
|
|
|
-
|
|
|
- spic_dev.input_key_dev = key_dev;
|
|
|
-
|
|
|
- /* jogdial - really reliable ? */
|
|
|
- ec_read(SONY_EC_JOGB, &jog_present);
|
|
|
- if (jog_present & SONY_EC_JOGB_MASK || force_jog) {
|
|
|
- jog_dev = input_allocate_device();
|
|
|
- if (!jog_dev) {
|
|
|
- error = -ENOMEM;
|
|
|
- goto err_unregister_keydev;
|
|
|
- }
|
|
|
-
|
|
|
- jog_dev->name = "Sony Vaio Jogdial";
|
|
|
- jog_dev->id.bustype = BUS_ISA;
|
|
|
- jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
|
|
|
-
|
|
|
- jog_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
|
|
|
- jog_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_MIDDLE);
|
|
|
- jog_dev->relbit[0] = BIT(REL_WHEEL);
|
|
|
-
|
|
|
- error = input_register_device(jog_dev);
|
|
|
- if (error)
|
|
|
- goto err_free_jogdev;
|
|
|
-
|
|
|
- spic_dev.input_jog_dev = jog_dev;
|
|
|
- }
|
|
|
-
|
|
|
- return 0;
|
|
|
-
|
|
|
-err_free_jogdev:
|
|
|
- input_free_device(jog_dev);
|
|
|
-
|
|
|
-err_unregister_keydev:
|
|
|
- input_unregister_device(key_dev);
|
|
|
- /* to avoid kref underflow below at input_free_device */
|
|
|
- key_dev = NULL;
|
|
|
-
|
|
|
-err_free_keydev:
|
|
|
- input_free_device(key_dev);
|
|
|
-
|
|
|
-err_destroy_wq:
|
|
|
- destroy_workqueue(spic_dev.sony_pic_wq);
|
|
|
-
|
|
|
-err_free_kfifo:
|
|
|
- kfifo_free(spic_dev.input_fifo);
|
|
|
-
|
|
|
- return error;
|
|
|
-}
|
|
|
-
|
|
|
-static void sony_pic_remove_input(void)
|
|
|
-{
|
|
|
- /* flush workqueue first */
|
|
|
- flush_workqueue(spic_dev.sony_pic_wq);
|
|
|
-
|
|
|
- /* destroy input devs */
|
|
|
- input_unregister_device(spic_dev.input_key_dev);
|
|
|
- spic_dev.input_key_dev = NULL;
|
|
|
-
|
|
|
- if (spic_dev.input_jog_dev) {
|
|
|
- input_unregister_device(spic_dev.input_jog_dev);
|
|
|
- spic_dev.input_jog_dev = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- destroy_workqueue(spic_dev.sony_pic_wq);
|
|
|
- kfifo_free(spic_dev.input_fifo);
|
|
|
-}
|
|
|
-
|
|
|
-/********************
|
|
|
- *
|
|
|
+/*
|
|
|
* ACPI callbacks
|
|
|
- *
|
|
|
- ********************/
|
|
|
+ */
|
|
|
static acpi_status
|
|
|
sony_pic_read_possible_resource(struct acpi_resource *resource, void *context)
|
|
|
{
|
|
@@ -1409,7 +1420,7 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
|
|
|
return IRQ_HANDLED;
|
|
|
|
|
|
found:
|
|
|
- sony_pic_report_input_event(device_event);
|
|
|
+ sony_laptop_report_input_event(device_event);
|
|
|
acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event);
|
|
|
|
|
|
return IRQ_HANDLED;
|
|
@@ -1434,7 +1445,7 @@ static int sony_pic_remove(struct acpi_device *device, int type)
|
|
|
release_region(spic_dev.cur_ioport->io.minimum,
|
|
|
spic_dev.cur_ioport->io.address_length);
|
|
|
|
|
|
- sony_pic_remove_input();
|
|
|
+ sony_laptop_remove_input();
|
|
|
|
|
|
list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
|
|
|
list_del(&io->list);
|
|
@@ -1474,7 +1485,7 @@ static int sony_pic_add(struct acpi_device *device)
|
|
|
}
|
|
|
|
|
|
/* setup input devices and helper fifo */
|
|
|
- result = sony_pic_setup_input();
|
|
|
+ result = sony_laptop_setup_input();
|
|
|
if (result) {
|
|
|
printk(KERN_ERR DRV_PFX
|
|
|
"Unabe to create input devices.\n");
|
|
@@ -1535,7 +1546,7 @@ err_release_region:
|
|
|
spic_dev.cur_ioport->io.address_length);
|
|
|
|
|
|
err_remove_input:
|
|
|
- sony_pic_remove_input();
|
|
|
+ sony_laptop_remove_input();
|
|
|
|
|
|
err_free_resources:
|
|
|
list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
|