diff options
author | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2009-01-08 13:22:55 +1100 |
---|---|---|
committer | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2009-01-08 13:22:55 +1100 |
commit | 6206aa8b2b9a45b4cf3ee31b7209b014be349fd9 (patch) | |
tree | 72c4223a2cc21bf055948eadb3b314ed0568ae9d /drivers/input/misc | |
parent | 95f8e302c04c0b0c6de35ab399a5551605eeb006 (diff) | |
parent | 9e42d0cf5020aaf217433cad1a224745241d212a (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/input/misc')
-rw-r--r-- | drivers/input/misc/apanel.c | 81 | ||||
-rw-r--r-- | drivers/input/misc/pcspkr.c | 4 | ||||
-rw-r--r-- | drivers/input/misc/uinput.c | 172 |
3 files changed, 174 insertions, 83 deletions
diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c index d82f7f727f7..71b82434264 100644 --- a/drivers/input/misc/apanel.c +++ b/drivers/input/misc/apanel.c @@ -57,7 +57,7 @@ static enum apanel_chip device_chip[APANEL_DEV_MAX]; struct apanel { struct input_polled_dev *ipdev; - struct i2c_client client; + struct i2c_client *client; unsigned short keymap[MAX_PANEL_KEYS]; u16 nkeys; u16 led_bits; @@ -66,16 +66,7 @@ struct apanel { }; -static int apanel_probe(struct i2c_adapter *, int, int); - -/* for now, we only support one address */ -static unsigned short normal_i2c[] = {0, I2C_CLIENT_END}; -static unsigned short ignore = I2C_CLIENT_END; -static struct i2c_client_address_data addr_data = { - .normal_i2c = normal_i2c, - .probe = &ignore, - .ignore = &ignore, -}; +static int apanel_probe(struct i2c_client *, const struct i2c_device_id *); static void report_key(struct input_dev *input, unsigned keycode) { @@ -103,12 +94,12 @@ static void apanel_poll(struct input_polled_dev *ipdev) s32 data; int i; - data = i2c_smbus_read_word_data(&ap->client, cmd); + data = i2c_smbus_read_word_data(ap->client, cmd); if (data < 0) return; /* ignore errors (due to ACPI??) */ /* write back to clear latch */ - i2c_smbus_write_word_data(&ap->client, cmd, 0); + i2c_smbus_write_word_data(ap->client, cmd, 0); if (!data) return; @@ -124,7 +115,7 @@ static void led_update(struct work_struct *work) { struct apanel *ap = container_of(work, struct apanel, led_work); - i2c_smbus_write_word_data(&ap->client, 0x10, ap->led_bits); + i2c_smbus_write_word_data(ap->client, 0x10, ap->led_bits); } static void mail_led_set(struct led_classdev *led, @@ -140,7 +131,7 @@ static void mail_led_set(struct led_classdev *led, schedule_work(&ap->led_work); } -static int apanel_detach_client(struct i2c_client *client) +static int apanel_remove(struct i2c_client *client) { struct apanel *ap = i2c_get_clientdata(client); @@ -148,43 +139,33 @@ static int apanel_detach_client(struct i2c_client *client) led_classdev_unregister(&ap->mail_led); input_unregister_polled_device(ap->ipdev); - i2c_detach_client(&ap->client); input_free_polled_device(ap->ipdev); return 0; } -/* Function is invoked for every i2c adapter. */ -static int apanel_attach_adapter(struct i2c_adapter *adap) -{ - dev_dbg(&adap->dev, APANEL ": attach adapter id=%d\n", adap->id); - - /* Our device is connected only to i801 on laptop */ - if (adap->id != I2C_HW_SMBUS_I801) - return -ENODEV; - - return i2c_probe(adap, &addr_data, apanel_probe); -} - static void apanel_shutdown(struct i2c_client *client) { - apanel_detach_client(client); + apanel_remove(client); } +static struct i2c_device_id apanel_id[] = { + { "fujitsu_apanel", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, apanel_id); + static struct i2c_driver apanel_driver = { .driver = { .name = APANEL, }, - .attach_adapter = &apanel_attach_adapter, - .detach_client = &apanel_detach_client, + .probe = &apanel_probe, + .remove = &apanel_remove, .shutdown = &apanel_shutdown, + .id_table = apanel_id, }; static struct apanel apanel = { - .client = { - .driver = &apanel_driver, - .name = APANEL, - }, .keymap = { [0] = KEY_MAIL, [1] = KEY_WWW, @@ -204,7 +185,8 @@ static struct apanel apanel = { }; /* NB: Only one panel on the i2c. */ -static int apanel_probe(struct i2c_adapter *bus, int address, int kind) +static int apanel_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct apanel *ap; struct input_polled_dev *ipdev; @@ -212,9 +194,6 @@ static int apanel_probe(struct i2c_adapter *bus, int address, int kind) u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8; int i, err = -ENOMEM; - dev_dbg(&bus->dev, APANEL ": probe adapter %p addr %d kind %d\n", - bus, address, kind); - ap = &apanel; ipdev = input_allocate_polled_device(); @@ -222,18 +201,13 @@ static int apanel_probe(struct i2c_adapter *bus, int address, int kind) goto out1; ap->ipdev = ipdev; - ap->client.adapter = bus; - ap->client.addr = address; - - i2c_set_clientdata(&ap->client, ap); + ap->client = client; - err = i2c_attach_client(&ap->client); - if (err) - goto out2; + i2c_set_clientdata(client, ap); - err = i2c_smbus_write_word_data(&ap->client, cmd, 0); + err = i2c_smbus_write_word_data(client, cmd, 0); if (err) { - dev_warn(&ap->client.dev, APANEL ": smbus write error %d\n", + dev_warn(&client->dev, APANEL ": smbus write error %d\n", err); goto out3; } @@ -246,7 +220,7 @@ static int apanel_probe(struct i2c_adapter *bus, int address, int kind) idev->name = APANEL_NAME " buttons"; idev->phys = "apanel/input0"; idev->id.bustype = BUS_HOST; - idev->dev.parent = &ap->client.dev; + idev->dev.parent = &client->dev; set_bit(EV_KEY, idev->evbit); @@ -264,7 +238,7 @@ static int apanel_probe(struct i2c_adapter *bus, int address, int kind) INIT_WORK(&ap->led_work, led_update); if (device_chip[APANEL_DEV_LED] != CHIP_NONE) { - err = led_classdev_register(&ap->client.dev, &ap->mail_led); + err = led_classdev_register(&client->dev, &ap->mail_led); if (err) goto out4; } @@ -273,8 +247,6 @@ static int apanel_probe(struct i2c_adapter *bus, int address, int kind) out4: input_unregister_polled_device(ipdev); out3: - i2c_detach_client(&ap->client); -out2: input_free_polled_device(ipdev); out1: return err; @@ -301,6 +273,7 @@ static int __init apanel_init(void) void __iomem *bios; const void __iomem *p; u8 devno; + unsigned char i2c_addr; int found = 0; bios = ioremap(0xF0000, 0x10000); /* Can't fail */ @@ -313,7 +286,7 @@ static int __init apanel_init(void) /* just use the first address */ p += 8; - normal_i2c[0] = readb(p+3) >> 1; + i2c_addr = readb(p + 3) >> 1; for ( ; (devno = readb(p)) & 0x7f; p += 4) { unsigned char method, slave, chip; @@ -322,7 +295,7 @@ static int __init apanel_init(void) chip = readb(p + 2); slave = readb(p + 3) >> 1; - if (slave != normal_i2c[0]) { + if (slave != i2c_addr) { pr_notice(APANEL ": only one SMBus slave " "address supported, skiping device...\n"); continue; diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 43aaa5cebd1..d6a30cee7bc 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c @@ -52,13 +52,13 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c spin_lock_irqsave(&i8253_lock, flags); if (count) { - /* enable counter 2 */ - outb_p(inb_p(0x61) | 3, 0x61); /* set command for counter 2, 2 byte write */ outb_p(0xB6, 0x43); /* select desired HZ */ outb_p(count & 0xff, 0x42); outb((count >> 8) & 0xff, 0x42); + /* enable counter 2 */ + outb_p(inb_p(0x61) | 3, 0x61); } else { /* disable counter 2 */ outb(inb_p(0x61) & 0xFC, 0x61); diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 223d56d5555..46b7caeb281 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -37,6 +37,7 @@ #include <linux/fs.h> #include <linux/miscdevice.h> #include <linux/uinput.h> +#include "../input-compat.h" static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { @@ -78,6 +79,7 @@ static struct uinput_request* uinput_request_find(struct uinput_device *udev, in /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ if (id >= UINPUT_NUM_REQUESTS || id < 0) return NULL; + return udev->requests[id]; } @@ -127,6 +129,17 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff struct uinput_request request; int retval; + /* + * uinput driver does not currently support periodic effects with + * custom waveform since it does not have a way to pass buffer of + * samples (custom_data) to userspace. If ever there is a device + * supporting custom waveforms we would need to define an additional + * ioctl (UI_UPLOAD_SAMPLES) but for now we just bail out. + */ + if (effect->type == FF_PERIODIC && + effect->u.periodic.waveform == FF_CUSTOM) + return -EINVAL; + request.id = -1; init_completion(&request.done); request.code = UI_FF_UPLOAD; @@ -353,15 +366,15 @@ static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char { struct input_event ev; - if (count != sizeof(struct input_event)) + if (count < input_event_size()) return -EINVAL; - if (copy_from_user(&ev, buffer, sizeof(struct input_event))) + if (input_event_from_user(buffer, &ev)) return -EFAULT; input_event(udev->dev, ev.type, ev.code, ev.value); - return sizeof(struct input_event); + return input_event_size(); } static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) @@ -407,13 +420,13 @@ static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, goto out; } - while (udev->head != udev->tail && retval + sizeof(struct input_event) <= count) { - if (copy_to_user(buffer + retval, &udev->buff[udev->tail], sizeof(struct input_event))) { + while (udev->head != udev->tail && retval + input_event_size() <= count) { + if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) { retval = -EFAULT; goto out; } udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE; - retval += sizeof(struct input_event); + retval += input_event_size(); } out: @@ -444,6 +457,93 @@ static int uinput_release(struct inode *inode, struct file *file) return 0; } +#ifdef CONFIG_COMPAT +struct uinput_ff_upload_compat { + int request_id; + int retval; + struct ff_effect_compat effect; + struct ff_effect_compat old; +}; + +static int uinput_ff_upload_to_user(char __user *buffer, + const struct uinput_ff_upload *ff_up) +{ + if (INPUT_COMPAT_TEST) { + struct uinput_ff_upload_compat ff_up_compat; + + ff_up_compat.request_id = ff_up->request_id; + ff_up_compat.retval = ff_up->retval; + /* + * It so happens that the pointer that gives us the trouble + * is the last field in the structure. Since we don't support + * custom waveforms in uinput anyway we can just copy the whole + * thing (to the compat size) and ignore the pointer. + */ + memcpy(&ff_up_compat.effect, &ff_up->effect, + sizeof(struct ff_effect_compat)); + memcpy(&ff_up_compat.old, &ff_up->old, + sizeof(struct ff_effect_compat)); + + if (copy_to_user(buffer, &ff_up_compat, + sizeof(struct uinput_ff_upload_compat))) + return -EFAULT; + } else { + if (copy_to_user(buffer, ff_up, + sizeof(struct uinput_ff_upload))) + return -EFAULT; + } + + return 0; +} + +static int uinput_ff_upload_from_user(const char __user *buffer, + struct uinput_ff_upload *ff_up) +{ + if (INPUT_COMPAT_TEST) { + struct uinput_ff_upload_compat ff_up_compat; + + if (copy_from_user(&ff_up_compat, buffer, + sizeof(struct uinput_ff_upload_compat))) + return -EFAULT; + + ff_up->request_id = ff_up_compat.request_id; + ff_up->retval = ff_up_compat.retval; + memcpy(&ff_up->effect, &ff_up_compat.effect, + sizeof(struct ff_effect_compat)); + memcpy(&ff_up->old, &ff_up_compat.old, + sizeof(struct ff_effect_compat)); + + } else { + if (copy_from_user(ff_up, buffer, + sizeof(struct uinput_ff_upload))) + return -EFAULT; + } + + return 0; +} + +#else + +static int uinput_ff_upload_to_user(char __user *buffer, + const struct uinput_ff_upload *ff_up) +{ + if (copy_to_user(buffer, ff_up, sizeof(struct uinput_ff_upload))) + return -EFAULT; + + return 0; +} + +static int uinput_ff_upload_from_user(const char __user *buffer, + struct uinput_ff_upload *ff_up) +{ + if (copy_from_user(ff_up, buffer, sizeof(struct uinput_ff_upload))) + return -EFAULT; + + return 0; +} + +#endif + #define uinput_set_bit(_arg, _bit, _max) \ ({ \ int __ret = 0; \ @@ -455,19 +555,17 @@ static int uinput_release(struct inode *inode, struct file *file) __ret; \ }) -static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long uinput_ioctl_handler(struct file *file, unsigned int cmd, + unsigned long arg, void __user *p) { int retval; - struct uinput_device *udev; - void __user *p = (void __user *)arg; + struct uinput_device *udev = file->private_data; struct uinput_ff_upload ff_up; struct uinput_ff_erase ff_erase; struct uinput_request *req; int length; char *phys; - udev = file->private_data; - retval = mutex_lock_interruptible(&udev->mutex); if (retval) return retval; @@ -549,26 +647,24 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case UI_BEGIN_FF_UPLOAD: - if (copy_from_user(&ff_up, p, sizeof(ff_up))) { - retval = -EFAULT; + retval = uinput_ff_upload_from_user(p, &ff_up); + if (retval) break; - } + req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { + if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) { retval = -EINVAL; break; } + ff_up.retval = 0; - memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect)); + ff_up.effect = *req->u.upload.effect; if (req->u.upload.old) - memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect)); + ff_up.old = *req->u.upload.old; else memset(&ff_up.old, 0, sizeof(struct ff_effect)); - if (copy_to_user(p, &ff_up, sizeof(ff_up))) { - retval = -EFAULT; - break; - } + retval = uinput_ff_upload_to_user(p, &ff_up); break; case UI_BEGIN_FF_ERASE: @@ -576,29 +672,34 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + req = uinput_request_find(udev, ff_erase.request_id); - if (!(req && req->code == UI_FF_ERASE)) { + if (!req || req->code != UI_FF_ERASE) { retval = -EINVAL; break; } + ff_erase.retval = 0; ff_erase.effect_id = req->u.effect_id; if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) { retval = -EFAULT; break; } + break; case UI_END_FF_UPLOAD: - if (copy_from_user(&ff_up, p, sizeof(ff_up))) { - retval = -EFAULT; + retval = uinput_ff_upload_from_user(p, &ff_up); + if (retval) break; - } + req = uinput_request_find(udev, ff_up.request_id); - if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) { + if (!req || req->code != UI_FF_UPLOAD || + !req->u.upload.effect) { retval = -EINVAL; break; } + req->retval = ff_up.retval; uinput_request_done(udev, req); break; @@ -608,11 +709,13 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } + req = uinput_request_find(udev, ff_erase.request_id); - if (!(req && req->code == UI_FF_ERASE)) { + if (!req || req->code != UI_FF_ERASE) { retval = -EINVAL; break; } + req->retval = ff_erase.retval; uinput_request_done(udev, req); break; @@ -626,6 +729,18 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return retval; } +static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return uinput_ioctl_handler(file, cmd, arg, (void __user *)arg); +} + +#ifdef CONFIG_COMPAT +static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg)); +} +#endif + static const struct file_operations uinput_fops = { .owner = THIS_MODULE, .open = uinput_open, @@ -634,6 +749,9 @@ static const struct file_operations uinput_fops = { .write = uinput_write, .poll = uinput_poll, .unlocked_ioctl = uinput_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = uinput_compat_ioctl, +#endif }; static struct miscdevice uinput_misc = { |