nfsd: move most of nfsfh.h to fs/nfsd
[safe/jmp/linux-2.6] / drivers / char / sonypi.c
index 6a9e23d..8c262aa 100644 (file)
@@ -1,11 +1,13 @@
 /*
  * Sony Programmable I/O Control Device driver for VAIO
  *
+ * Copyright (C) 2007 Mattia Dongili <malattia@linux.it>
+ *
  * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
  *
  * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
  *
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
+ * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
  *
  * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
  *
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/sched.h>
 #include <linux/input.h>
 #include <linux/pci.h>
-#include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/miscdevice.h>
@@ -49,6 +50,7 @@
 #include <linux/err.h>
 #include <linux/kfifo.h>
 #include <linux/platform_device.h>
+#include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -97,6 +99,11 @@ module_param(useinput, int, 0444);
 MODULE_PARM_DESC(useinput,
                 "set this if you would like sonypi to feed events to the input subsystem");
 
+static int check_ioport = 1;
+module_param(check_ioport, int, 0444);
+MODULE_PARM_DESC(check_ioport,
+                "set this to 0 if you think the automatic ioport check for sony-laptop is wrong");
+
 #define SONYPI_DEVICE_MODEL_TYPE1      1
 #define SONYPI_DEVICE_MODEL_TYPE2      2
 #define SONYPI_DEVICE_MODEL_TYPE3      3
@@ -479,7 +486,7 @@ static struct sonypi_device {
        u16 evtype_offset;
        int camera_power;
        int bluetooth_power;
-       struct semaphore lock;
+       struct mutex lock;
        struct kfifo *fifo;
        spinlock_t fifo_lock;
        wait_queue_head_t fifo_proc_list;
@@ -501,7 +508,7 @@ static struct sonypi_device {
        while (--n && (command)) \
                udelay(1); \
        if (!n && (verbose || !quiet)) \
-               printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __FUNCTION__, __LINE__); \
+               printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __func__, __LINE__); \
 }
 
 #ifdef CONFIG_ACPI
@@ -510,9 +517,14 @@ static struct sonypi_device {
 #define SONYPI_ACPI_ACTIVE 0
 #endif                         /* CONFIG_ACPI */
 
+#ifdef CONFIG_ACPI
+static struct acpi_device *sonypi_acpi_device;
+static int acpi_driver_registered;
+#endif
+
 static int sonypi_ec_write(u8 addr, u8 value)
 {
-#ifdef CONFIG_ACPI_EC
+#ifdef CONFIG_ACPI
        if (SONYPI_ACPI_ACTIVE)
                return ec_write(addr, value);
 #endif
@@ -528,7 +540,7 @@ static int sonypi_ec_write(u8 addr, u8 value)
 
 static int sonypi_ec_read(u8 addr, u8 *value)
 {
-#ifdef CONFIG_ACPI_EC
+#ifdef CONFIG_ACPI
        if (SONYPI_ACPI_ACTIVE)
                return ec_read(addr, value);
 #endif
@@ -761,7 +773,7 @@ static void sonypi_setbluetoothpower(u8 state)
        sonypi_device.bluetooth_power = state;
 }
 
-static void input_keyrelease(void *data)
+static void input_keyrelease(struct work_struct *work)
 {
        struct sonypi_keypress kp;
 
@@ -822,7 +834,7 @@ static void sonypi_report_input_event(u8 event)
 }
 
 /* Interrupt handler: some event is available */
-static irqreturn_t sonypi_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sonypi_irq(int irq, void *dev_id)
 {
        u8 v1, v2, event = 0;
        int i, j;
@@ -863,6 +875,11 @@ found:
        if (useinput)
                sonypi_report_input_event(event);
 
+#ifdef CONFIG_ACPI
+       if (sonypi_acpi_device)
+               acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event);
+#endif
+
        kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
        kill_fasync(&sonypi_device.fifo_async, SIGIO, POLL_IN);
        wake_up_interruptible(&sonypi_device.fifo_proc_list);
@@ -870,80 +887,29 @@ found:
        return IRQ_HANDLED;
 }
 
-/* External camera command (exported to the motion eye v4l driver) */
-int sonypi_camera_command(int command, u8 value)
-{
-       if (!camera)
-               return -EIO;
-
-       down(&sonypi_device.lock);
-
-       switch (command) {
-       case SONYPI_COMMAND_SETCAMERA:
-               if (value)
-                       sonypi_camera_on();
-               else
-                       sonypi_camera_off();
-               break;
-       case SONYPI_COMMAND_SETCAMERABRIGHTNESS:
-               sonypi_set(SONYPI_CAMERA_BRIGHTNESS, value);
-               break;
-       case SONYPI_COMMAND_SETCAMERACONTRAST:
-               sonypi_set(SONYPI_CAMERA_CONTRAST, value);
-               break;
-       case SONYPI_COMMAND_SETCAMERAHUE:
-               sonypi_set(SONYPI_CAMERA_HUE, value);
-               break;
-       case SONYPI_COMMAND_SETCAMERACOLOR:
-               sonypi_set(SONYPI_CAMERA_COLOR, value);
-               break;
-       case SONYPI_COMMAND_SETCAMERASHARPNESS:
-               sonypi_set(SONYPI_CAMERA_SHARPNESS, value);
-               break;
-       case SONYPI_COMMAND_SETCAMERAPICTURE:
-               sonypi_set(SONYPI_CAMERA_PICTURE, value);
-               break;
-       case SONYPI_COMMAND_SETCAMERAAGC:
-               sonypi_set(SONYPI_CAMERA_AGC, value);
-               break;
-       default:
-               printk(KERN_ERR "sonypi: sonypi_camera_command invalid: %d\n",
-                      command);
-               break;
-       }
-       up(&sonypi_device.lock);
-       return 0;
-}
-
-EXPORT_SYMBOL(sonypi_camera_command);
-
 static int sonypi_misc_fasync(int fd, struct file *filp, int on)
 {
-       int retval;
-
-       retval = fasync_helper(fd, filp, on, &sonypi_device.fifo_async);
-       if (retval < 0)
-               return retval;
-       return 0;
+       return fasync_helper(fd, filp, on, &sonypi_device.fifo_async);
 }
 
 static int sonypi_misc_release(struct inode *inode, struct file *file)
 {
-       sonypi_misc_fasync(-1, file, 0);
-       down(&sonypi_device.lock);
+       mutex_lock(&sonypi_device.lock);
        sonypi_device.open_count--;
-       up(&sonypi_device.lock);
+       mutex_unlock(&sonypi_device.lock);
        return 0;
 }
 
 static int sonypi_misc_open(struct inode *inode, struct file *file)
 {
-       down(&sonypi_device.lock);
+       lock_kernel();
+       mutex_lock(&sonypi_device.lock);
        /* Flush input queue on first open */
        if (!sonypi_device.open_count)
                kfifo_reset(sonypi_device.fifo);
        sonypi_device.open_count++;
-       up(&sonypi_device.lock);
+       mutex_unlock(&sonypi_device.lock);
+       unlock_kernel();
        return 0;
 }
 
@@ -970,7 +936,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
        }
 
        if (ret > 0) {
-               struct inode *inode = file->f_dentry->d_inode;
+               struct inode *inode = file->f_path.dentry->d_inode;
                inode->i_atime = current_fs_time(inode->i_sb);
        }
 
@@ -993,7 +959,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
        u8 val8;
        u16 val16;
 
-       down(&sonypi_device.lock);
+       mutex_lock(&sonypi_device.lock);
        switch (cmd) {
        case SONYPI_IOCGBRT:
                if (sonypi_ec_read(SONYPI_LCD_LIGHT, &val8)) {
@@ -1093,11 +1059,11 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
        default:
                ret = -EINVAL;
        }
-       up(&sonypi_device.lock);
+       mutex_unlock(&sonypi_device.lock);
        return ret;
 }
 
-static struct file_operations sonypi_misc_fops = {
+static const struct file_operations sonypi_misc_fops = {
        .owner          = THIS_MODULE,
        .read           = sonypi_misc_read,
        .poll           = sonypi_misc_poll,
@@ -1164,7 +1130,38 @@ static int sonypi_disable(void)
        return 0;
 }
 
-static int __devinit sonypi_create_input_devices(void)
+#ifdef CONFIG_ACPI
+static int sonypi_acpi_add(struct acpi_device *device)
+{
+       sonypi_acpi_device = device;
+       strcpy(acpi_device_name(device), "Sony laptop hotkeys");
+       strcpy(acpi_device_class(device), "sony/hotkey");
+       return 0;
+}
+
+static int sonypi_acpi_remove(struct acpi_device *device, int type)
+{
+       sonypi_acpi_device = NULL;
+       return 0;
+}
+
+static const struct acpi_device_id sonypi_device_ids[] = {
+       {"SNY6001", 0},
+       {"", 0},
+};
+
+static struct acpi_driver sonypi_acpi_driver = {
+       .name           = "sonypi",
+       .class          = "hkey",
+       .ids            = sonypi_device_ids,
+       .ops            = {
+                          .add = sonypi_acpi_add,
+                          .remove = sonypi_acpi_remove,
+       },
+};
+#endif
+
+static int __devinit sonypi_create_input_devices(struct platform_device *pdev)
 {
        struct input_dev *jog_dev;
        struct input_dev *key_dev;
@@ -1178,10 +1175,11 @@ static int __devinit sonypi_create_input_devices(void)
        jog_dev->name = "Sony Vaio Jogdial";
        jog_dev->id.bustype = BUS_ISA;
        jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
+       jog_dev->dev.parent = &pdev->dev;
 
-       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);
+       jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+       jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE);
+       jog_dev->relbit[0] = BIT_MASK(REL_WHEEL);
 
        sonypi_device.input_key_dev = key_dev = input_allocate_device();
        if (!key_dev) {
@@ -1192,9 +1190,10 @@ static int __devinit sonypi_create_input_devices(void)
        key_dev->name = "Sony Vaio Keys";
        key_dev->id.bustype = BUS_ISA;
        key_dev->id.vendor = PCI_VENDOR_ID_SONY;
+       key_dev->dev.parent = &pdev->dev;
 
        /* Initialize the Input Drivers: special keys */
-       key_dev->evbit[0] = BIT(EV_KEY);
+       key_dev->evbit[0] = BIT_MASK(EV_KEY);
        for (i = 0; sonypi_inputkeys[i].sonypiev; i++)
                if (sonypi_inputkeys[i].inputev)
                        set_bit(sonypi_inputkeys[i].inputev, key_dev->keybit);
@@ -1226,6 +1225,28 @@ static int __devinit sonypi_create_input_devices(void)
 static int __devinit sonypi_setup_ioports(struct sonypi_device *dev,
                                const struct sonypi_ioport_list *ioport_list)
 {
+       /* try to detect if sony-laptop is being used and thus
+        * has already requested one of the known ioports.
+        * As in the deprecated check_region this is racy has we have
+        * multiple ioports available and one of them can be requested
+        * between this check and the subsequent request. Anyway, as an
+        * attempt to be some more user-friendly as we currently are,
+        * this is enough.
+        */
+       const struct sonypi_ioport_list *check = ioport_list;
+       while (check_ioport && check->port1) {
+               if (!request_region(check->port1,
+                                  sonypi_device.region_size,
+                                  "Sony Programable I/O Device Check")) {
+                       printk(KERN_ERR "sonypi: ioport 0x%.4x busy, using sony-laptop? "
+                                       "if not use check_ioport=0\n",
+                                       check->port1);
+                       return -EBUSY;
+               }
+               release_region(check->port1, sonypi_device.region_size);
+               check++;
+       }
+
        while (ioport_list->port1) {
 
                if (request_region(ioport_list->port1,
@@ -1247,7 +1268,7 @@ static int __devinit sonypi_setup_irq(struct sonypi_device *dev,
        while (irq_list->irq) {
 
                if (!request_irq(irq_list->irq, sonypi_irq,
-                                SA_SHIRQ, "sonypi", sonypi_irq)) {
+                                IRQF_SHARED, "sonypi", sonypi_irq)) {
                        dev->irq = irq_list->irq;
                        dev->bits = irq_list->bits;
                        return 0;
@@ -1287,6 +1308,10 @@ static int __devinit sonypi_probe(struct platform_device *dev)
        struct pci_dev *pcidev;
        int error;
 
+       printk(KERN_WARNING "sonypi: please try the sony-laptop module instead "
+                       "and report failures, see also "
+                       "http://www.linux.it/~malattia/wiki/index.php/Sony_drivers\n");
+
        spin_lock_init(&sonypi_device.fifo_lock);
        sonypi_device.fifo = kfifo_alloc(SONYPI_BUF_SIZE, GFP_KERNEL,
                                         &sonypi_device.fifo_lock);
@@ -1296,7 +1321,7 @@ static int __devinit sonypi_probe(struct platform_device *dev)
        }
 
        init_waitqueue_head(&sonypi_device.fifo_proc_list);
-       init_MUTEX(&sonypi_device.lock);
+       mutex_init(&sonypi_device.lock);
        sonypi_device.bluetooth_power = -1;
 
        if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
@@ -1305,6 +1330,9 @@ static int __devinit sonypi_probe(struct platform_device *dev)
        else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
                                          PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
                sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
+       else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                         PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
+               sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE3;
        else
                sonypi_device.model = SONYPI_DEVICE_MODEL_TYPE2;
 
@@ -1357,7 +1385,7 @@ static int __devinit sonypi_probe(struct platform_device *dev)
 
        if (useinput) {
 
-               error = sonypi_create_input_devices();
+               error = sonypi_create_input_devices(dev);
                if (error) {
                        printk(KERN_ERR
                                "sonypi: failed to create input devices\n");
@@ -1374,7 +1402,7 @@ static int __devinit sonypi_probe(struct platform_device *dev)
                        goto err_inpdev_unregister;
                }
 
-               INIT_WORK(&sonypi_device.input_work, input_keyrelease, NULL);
+               INIT_WORK(&sonypi_device.input_work, input_keyrelease);
        }
 
        sonypi_enable(0);
@@ -1404,7 +1432,7 @@ static int __devexit sonypi_remove(struct platform_device *dev)
 {
        sonypi_disable();
 
-       synchronize_sched();  /* Allow sonypi interrupt to complete. */
+       synchronize_irq(sonypi_device.irq);
        flush_scheduled_work();
 
        if (useinput) {
@@ -1511,6 +1539,11 @@ static int __init sonypi_init(void)
        if (error)
                goto err_free_device;
 
+#ifdef CONFIG_ACPI
+       if (acpi_bus_register_driver(&sonypi_acpi_driver) >= 0)
+               acpi_driver_registered = 1;
+#endif
+
        return 0;
 
  err_free_device:
@@ -1522,6 +1555,10 @@ static int __init sonypi_init(void)
 
 static void __exit sonypi_exit(void)
 {
+#ifdef CONFIG_ACPI
+       if (acpi_driver_registered)
+               acpi_bus_unregister_driver(&sonypi_acpi_driver);
+#endif
        platform_device_unregister(sonypi_platform_device);
        platform_driver_unregister(&sonypi_driver);
        printk(KERN_INFO "sonypi: removed.\n");