diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2007-08-30 00:22:32 -0400 |
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2007-08-30 00:22:32 -0400 |
| commit | b126207ccdfe492fbc339c18d4898b1b5353fc6b (patch) | |
| tree | 2ebc6d125d455cec87552ccd8ce2a3dc9e6e8242 /drivers/input | |
| parent | 464b241575f3700e14492e34f26bcd1794280f55 (diff) | |
Input: joydev - implement proper locking
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input')
| -rw-r--r-- | drivers/input/joydev.c | 743 |
1 files changed, 492 insertions, 251 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index a9a0180bfd46..a4272d63c4d6 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
| @@ -43,6 +43,8 @@ struct joydev { | |||
| 43 | struct input_handle handle; | 43 | struct input_handle handle; |
| 44 | wait_queue_head_t wait; | 44 | wait_queue_head_t wait; |
| 45 | struct list_head client_list; | 45 | struct list_head client_list; |
| 46 | spinlock_t client_lock; /* protects client_list */ | ||
| 47 | struct mutex mutex; | ||
| 46 | struct device dev; | 48 | struct device dev; |
| 47 | 49 | ||
| 48 | struct js_corr corr[ABS_MAX + 1]; | 50 | struct js_corr corr[ABS_MAX + 1]; |
| @@ -61,31 +63,61 @@ struct joydev_client { | |||
| 61 | int head; | 63 | int head; |
| 62 | int tail; | 64 | int tail; |
| 63 | int startup; | 65 | int startup; |
| 66 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ | ||
| 64 | struct fasync_struct *fasync; | 67 | struct fasync_struct *fasync; |
| 65 | struct joydev *joydev; | 68 | struct joydev *joydev; |
| 66 | struct list_head node; | 69 | struct list_head node; |
| 67 | }; | 70 | }; |
| 68 | 71 | ||
| 69 | static struct joydev *joydev_table[JOYDEV_MINORS]; | 72 | static struct joydev *joydev_table[JOYDEV_MINORS]; |
| 73 | static DEFINE_MUTEX(joydev_table_mutex); | ||
| 70 | 74 | ||
| 71 | static int joydev_correct(int value, struct js_corr *corr) | 75 | static int joydev_correct(int value, struct js_corr *corr) |
| 72 | { | 76 | { |
| 73 | switch (corr->type) { | 77 | switch (corr->type) { |
| 74 | case JS_CORR_NONE: | 78 | |
| 75 | break; | 79 | case JS_CORR_NONE: |
| 76 | case JS_CORR_BROKEN: | 80 | break; |
| 77 | value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : | 81 | |
| 78 | ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : | 82 | case JS_CORR_BROKEN: |
| 79 | ((corr->coef[2] * (value - corr->coef[0])) >> 14); | 83 | value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : |
| 80 | break; | 84 | ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : |
| 81 | default: | 85 | ((corr->coef[2] * (value - corr->coef[0])) >> 14); |
| 82 | return 0; | 86 | break; |
| 87 | |||
| 88 | default: | ||
| 89 | return 0; | ||
| 83 | } | 90 | } |
| 84 | 91 | ||
| 85 | return value < -32767 ? -32767 : (value > 32767 ? 32767 : value); | 92 | return value < -32767 ? -32767 : (value > 32767 ? 32767 : value); |
| 86 | } | 93 | } |
| 87 | 94 | ||
| 88 | static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | 95 | static void joydev_pass_event(struct joydev_client *client, |
| 96 | struct js_event *event) | ||
| 97 | { | ||
| 98 | struct joydev *joydev = client->joydev; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * IRQs already disabled, just acquire the lock | ||
| 102 | */ | ||
| 103 | spin_lock(&client->buffer_lock); | ||
| 104 | |||
| 105 | client->buffer[client->head] = *event; | ||
| 106 | |||
| 107 | if (client->startup == joydev->nabs + joydev->nkey) { | ||
| 108 | client->head++; | ||
| 109 | client->head &= JOYDEV_BUFFER_SIZE - 1; | ||
| 110 | if (client->tail == client->head) | ||
| 111 | client->startup = 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | spin_unlock(&client->buffer_lock); | ||
| 115 | |||
| 116 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | ||
| 117 | } | ||
| 118 | |||
| 119 | static void joydev_event(struct input_handle *handle, | ||
| 120 | unsigned int type, unsigned int code, int value) | ||
| 89 | { | 121 | { |
| 90 | struct joydev *joydev = handle->private; | 122 | struct joydev *joydev = handle->private; |
| 91 | struct joydev_client *client; | 123 | struct joydev_client *client; |
| @@ -93,39 +125,32 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne | |||
| 93 | 125 | ||
| 94 | switch (type) { | 126 | switch (type) { |
| 95 | 127 | ||
| 96 | case EV_KEY: | 128 | case EV_KEY: |
| 97 | if (code < BTN_MISC || value == 2) | 129 | if (code < BTN_MISC || value == 2) |
| 98 | return; | 130 | return; |
| 99 | event.type = JS_EVENT_BUTTON; | 131 | event.type = JS_EVENT_BUTTON; |
| 100 | event.number = joydev->keymap[code - BTN_MISC]; | 132 | event.number = joydev->keymap[code - BTN_MISC]; |
| 101 | event.value = value; | 133 | event.value = value; |
| 102 | break; | 134 | break; |
| 103 | |||
| 104 | case EV_ABS: | ||
| 105 | event.type = JS_EVENT_AXIS; | ||
| 106 | event.number = joydev->absmap[code]; | ||
| 107 | event.value = joydev_correct(value, joydev->corr + event.number); | ||
| 108 | if (event.value == joydev->abs[event.number]) | ||
| 109 | return; | ||
| 110 | joydev->abs[event.number] = event.value; | ||
| 111 | break; | ||
| 112 | 135 | ||
| 113 | default: | 136 | case EV_ABS: |
| 137 | event.type = JS_EVENT_AXIS; | ||
| 138 | event.number = joydev->absmap[code]; | ||
| 139 | event.value = joydev_correct(value, | ||
| 140 | &joydev->corr[event.number]); | ||
| 141 | if (event.value == joydev->abs[event.number]) | ||
| 114 | return; | 142 | return; |
| 143 | joydev->abs[event.number] = event.value; | ||
| 144 | break; | ||
| 145 | |||
| 146 | default: | ||
| 147 | return; | ||
| 115 | } | 148 | } |
| 116 | 149 | ||
| 117 | event.time = jiffies_to_msecs(jiffies); | 150 | event.time = jiffies_to_msecs(jiffies); |
| 118 | 151 | ||
| 119 | list_for_each_entry(client, &joydev->client_list, node) { | 152 | list_for_each_entry_rcu(client, &joydev->client_list, node) |
| 120 | 153 | joydev_pass_event(client, &event); | |
| 121 | memcpy(client->buffer + client->head, &event, sizeof(struct js_event)); | ||
| 122 | |||
| 123 | if (client->startup == joydev->nabs + joydev->nkey) | ||
| 124 | if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) | ||
| 125 | client->startup = 0; | ||
| 126 | |||
| 127 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | ||
| 128 | } | ||
| 129 | 154 | ||
| 130 | wake_up_interruptible(&joydev->wait); | 155 | wake_up_interruptible(&joydev->wait); |
| 131 | } | 156 | } |
| @@ -144,23 +169,85 @@ static void joydev_free(struct device *dev) | |||
| 144 | { | 169 | { |
| 145 | struct joydev *joydev = container_of(dev, struct joydev, dev); | 170 | struct joydev *joydev = container_of(dev, struct joydev, dev); |
| 146 | 171 | ||
| 147 | joydev_table[joydev->minor] = NULL; | ||
| 148 | kfree(joydev); | 172 | kfree(joydev); |
| 149 | } | 173 | } |
| 150 | 174 | ||
| 175 | static void joydev_attach_client(struct joydev *joydev, | ||
| 176 | struct joydev_client *client) | ||
| 177 | { | ||
| 178 | spin_lock(&joydev->client_lock); | ||
| 179 | list_add_tail_rcu(&client->node, &joydev->client_list); | ||
| 180 | spin_unlock(&joydev->client_lock); | ||
| 181 | /* | ||
| 182 | * We don't use synchronize_rcu() here because read-side | ||
| 183 | * critical section is protected by a spinlock (dev->event_lock) | ||
| 184 | * instead of rcu_read_lock(). | ||
| 185 | */ | ||
| 186 | synchronize_sched(); | ||
| 187 | } | ||
| 188 | |||
| 189 | static void joydev_detach_client(struct joydev *joydev, | ||
| 190 | struct joydev_client *client) | ||
| 191 | { | ||
| 192 | spin_lock(&joydev->client_lock); | ||
| 193 | list_del_rcu(&client->node); | ||
| 194 | spin_unlock(&joydev->client_lock); | ||
| 195 | synchronize_sched(); | ||
| 196 | } | ||
| 197 | |||
| 198 | static int joydev_open_device(struct joydev *joydev) | ||
| 199 | { | ||
| 200 | int retval; | ||
| 201 | |||
| 202 | retval = mutex_lock_interruptible(&joydev->mutex); | ||
| 203 | if (retval) | ||
| 204 | return retval; | ||
| 205 | |||
| 206 | if (!joydev->exist) | ||
| 207 | retval = -ENODEV; | ||
| 208 | else if (!joydev->open++) | ||
| 209 | retval = input_open_device(&joydev->handle); | ||
| 210 | |||
| 211 | mutex_unlock(&joydev->mutex); | ||
| 212 | return retval; | ||
| 213 | } | ||
| 214 | |||
| 215 | static void joydev_close_device(struct joydev *joydev) | ||
| 216 | { | ||
| 217 | mutex_lock(&joydev->mutex); | ||
| 218 | |||
| 219 | if (joydev->exist && !--joydev->open) | ||
| 220 | input_close_device(&joydev->handle); | ||
| 221 | |||
| 222 | mutex_unlock(&joydev->mutex); | ||
| 223 | } | ||
| 224 | |||
| 225 | /* | ||
| 226 | * Wake up users waiting for IO so they can disconnect from | ||
| 227 | * dead device. | ||
| 228 | */ | ||
| 229 | static void joydev_hangup(struct joydev *joydev) | ||
| 230 | { | ||
| 231 | struct joydev_client *client; | ||
| 232 | |||
| 233 | spin_lock(&joydev->client_lock); | ||
| 234 | list_for_each_entry(client, &joydev->client_list, node) | ||
| 235 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
| 236 | spin_unlock(&joydev->client_lock); | ||
| 237 | |||
| 238 | wake_up_interruptible(&joydev->wait); | ||
| 239 | } | ||
| 240 | |||
| 151 | static int joydev_release(struct inode *inode, struct file *file) | 241 | static int joydev_release(struct inode *inode, struct file *file) |
| 152 | { | 242 | { |
| 153 | struct joydev_client *client = file->private_data; | 243 | struct joydev_client *client = file->private_data; |
| 154 | struct joydev *joydev = client->joydev; | 244 | struct joydev *joydev = client->joydev; |
| 155 | 245 | ||
| 156 | joydev_fasync(-1, file, 0); | 246 | joydev_fasync(-1, file, 0); |
| 157 | 247 | joydev_detach_client(joydev, client); | |
| 158 | list_del(&client->node); | ||
| 159 | kfree(client); | 248 | kfree(client); |
| 160 | 249 | ||
| 161 | if (!--joydev->open && joydev->exist) | 250 | joydev_close_device(joydev); |
| 162 | input_close_device(&joydev->handle); | ||
| 163 | |||
| 164 | put_device(&joydev->dev); | 251 | put_device(&joydev->dev); |
| 165 | 252 | ||
| 166 | return 0; | 253 | return 0; |
| @@ -176,11 +263,16 @@ static int joydev_open(struct inode *inode, struct file *file) | |||
| 176 | if (i >= JOYDEV_MINORS) | 263 | if (i >= JOYDEV_MINORS) |
| 177 | return -ENODEV; | 264 | return -ENODEV; |
| 178 | 265 | ||
| 266 | error = mutex_lock_interruptible(&joydev_table_mutex); | ||
| 267 | if (error) | ||
| 268 | return error; | ||
| 179 | joydev = joydev_table[i]; | 269 | joydev = joydev_table[i]; |
| 180 | if (!joydev || !joydev->exist) | 270 | if (joydev) |
| 181 | return -ENODEV; | 271 | get_device(&joydev->dev); |
| 272 | mutex_unlock(&joydev_table_mutex); | ||
| 182 | 273 | ||
| 183 | get_device(&joydev->dev); | 274 | if (!joydev) |
| 275 | return -ENODEV; | ||
| 184 | 276 | ||
| 185 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); | 277 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); |
| 186 | if (!client) { | 278 | if (!client) { |
| @@ -188,37 +280,129 @@ static int joydev_open(struct inode *inode, struct file *file) | |||
| 188 | goto err_put_joydev; | 280 | goto err_put_joydev; |
| 189 | } | 281 | } |
| 190 | 282 | ||
| 283 | spin_lock_init(&client->buffer_lock); | ||
| 191 | client->joydev = joydev; | 284 | client->joydev = joydev; |
| 192 | list_add_tail(&client->node, &joydev->client_list); | 285 | joydev_attach_client(joydev, client); |
| 193 | 286 | ||
| 194 | if (!joydev->open++ && joydev->exist) { | 287 | error = joydev_open_device(joydev); |
| 195 | error = input_open_device(&joydev->handle); | 288 | if (error) |
| 196 | if (error) | 289 | goto err_free_client; |
| 197 | goto err_free_client; | ||
| 198 | } | ||
| 199 | 290 | ||
| 200 | file->private_data = client; | 291 | file->private_data = client; |
| 201 | return 0; | 292 | return 0; |
| 202 | 293 | ||
| 203 | err_free_client: | 294 | err_free_client: |
| 204 | list_del(&client->node); | 295 | joydev_detach_client(joydev, client); |
| 205 | kfree(client); | 296 | kfree(client); |
| 206 | err_put_joydev: | 297 | err_put_joydev: |
| 207 | put_device(&joydev->dev); | 298 | put_device(&joydev->dev); |
| 208 | return error; | 299 | return error; |
| 209 | } | 300 | } |
| 210 | 301 | ||
| 211 | static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 302 | static int joydev_generate_startup_event(struct joydev_client *client, |
| 303 | struct input_dev *input, | ||
| 304 | struct js_event *event) | ||
| 212 | { | 305 | { |
| 213 | return -EINVAL; | 306 | struct joydev *joydev = client->joydev; |
| 307 | int have_event; | ||
| 308 | |||
| 309 | spin_lock_irq(&client->buffer_lock); | ||
| 310 | |||
| 311 | have_event = client->startup < joydev->nabs + joydev->nkey; | ||
| 312 | |||
| 313 | if (have_event) { | ||
| 314 | |||
| 315 | event->time = jiffies_to_msecs(jiffies); | ||
| 316 | if (client->startup < joydev->nkey) { | ||
| 317 | event->type = JS_EVENT_BUTTON | JS_EVENT_INIT; | ||
| 318 | event->number = client->startup; | ||
| 319 | event->value = !!test_bit(joydev->keypam[event->number], | ||
| 320 | input->key); | ||
| 321 | } else { | ||
| 322 | event->type = JS_EVENT_AXIS | JS_EVENT_INIT; | ||
| 323 | event->number = client->startup - joydev->nkey; | ||
| 324 | event->value = joydev->abs[event->number]; | ||
| 325 | } | ||
| 326 | client->startup++; | ||
| 327 | } | ||
| 328 | |||
| 329 | spin_unlock_irq(&client->buffer_lock); | ||
| 330 | |||
| 331 | return have_event; | ||
| 332 | } | ||
| 333 | |||
| 334 | static int joydev_fetch_next_event(struct joydev_client *client, | ||
| 335 | struct js_event *event) | ||
| 336 | { | ||
| 337 | int have_event; | ||
| 338 | |||
| 339 | spin_lock_irq(&client->buffer_lock); | ||
| 340 | |||
| 341 | have_event = client->head != client->tail; | ||
| 342 | if (have_event) { | ||
| 343 | *event = client->buffer[client->tail++]; | ||
| 344 | client->tail &= JOYDEV_BUFFER_SIZE - 1; | ||
| 345 | } | ||
| 346 | |||
| 347 | spin_unlock_irq(&client->buffer_lock); | ||
| 348 | |||
| 349 | return have_event; | ||
| 350 | } | ||
| 351 | |||
| 352 | /* | ||
| 353 | * Old joystick interface | ||
| 354 | */ | ||
| 355 | static ssize_t joydev_0x_read(struct joydev_client *client, | ||
| 356 | struct input_dev *input, | ||
| 357 | char __user *buf) | ||
| 358 | { | ||
| 359 | struct joydev *joydev = client->joydev; | ||
| 360 | struct JS_DATA_TYPE data; | ||
| 361 | int i; | ||
| 362 | |||
| 363 | spin_lock_irq(&input->event_lock); | ||
| 364 | |||
| 365 | /* | ||
| 366 | * Get device state | ||
| 367 | */ | ||
| 368 | for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) | ||
| 369 | data.buttons |= | ||
| 370 | test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; | ||
| 371 | data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; | ||
| 372 | data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; | ||
| 373 | |||
| 374 | /* | ||
| 375 | * Reset reader's event queue | ||
| 376 | */ | ||
| 377 | spin_lock(&client->buffer_lock); | ||
| 378 | client->startup = 0; | ||
| 379 | client->tail = client->head; | ||
| 380 | spin_unlock(&client->buffer_lock); | ||
| 381 | |||
| 382 | spin_unlock_irq(&input->event_lock); | ||
| 383 | |||
| 384 | if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) | ||
| 385 | return -EFAULT; | ||
| 386 | |||
| 387 | return sizeof(struct JS_DATA_TYPE); | ||
| 214 | } | 388 | } |
| 215 | 389 | ||
| 216 | static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | 390 | static inline int joydev_data_pending(struct joydev_client *client) |
| 391 | { | ||
| 392 | struct joydev *joydev = client->joydev; | ||
| 393 | |||
| 394 | return client->startup < joydev->nabs + joydev->nkey || | ||
| 395 | client->head != client->tail; | ||
| 396 | } | ||
| 397 | |||
| 398 | static ssize_t joydev_read(struct file *file, char __user *buf, | ||
| 399 | size_t count, loff_t *ppos) | ||
| 217 | { | 400 | { |
| 218 | struct joydev_client *client = file->private_data; | 401 | struct joydev_client *client = file->private_data; |
| 219 | struct joydev *joydev = client->joydev; | 402 | struct joydev *joydev = client->joydev; |
| 220 | struct input_dev *input = joydev->handle.dev; | 403 | struct input_dev *input = joydev->handle.dev; |
| 221 | int retval = 0; | 404 | struct js_event event; |
| 405 | int retval; | ||
| 222 | 406 | ||
| 223 | if (!joydev->exist) | 407 | if (!joydev->exist) |
| 224 | return -ENODEV; | 408 | return -ENODEV; |
| @@ -226,68 +410,35 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo | |||
| 226 | if (count < sizeof(struct js_event)) | 410 | if (count < sizeof(struct js_event)) |
| 227 | return -EINVAL; | 411 | return -EINVAL; |
| 228 | 412 | ||
| 229 | if (count == sizeof(struct JS_DATA_TYPE)) { | 413 | if (count == sizeof(struct JS_DATA_TYPE)) |
| 230 | 414 | return joydev_0x_read(client, input, buf); | |
| 231 | struct JS_DATA_TYPE data; | ||
| 232 | int i; | ||
| 233 | 415 | ||
| 234 | for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) | 416 | if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK)) |
| 235 | data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; | ||
| 236 | data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; | ||
| 237 | data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; | ||
| 238 | |||
| 239 | if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) | ||
| 240 | return -EFAULT; | ||
| 241 | |||
| 242 | client->startup = 0; | ||
| 243 | client->tail = client->head; | ||
| 244 | |||
| 245 | return sizeof(struct JS_DATA_TYPE); | ||
| 246 | } | ||
| 247 | |||
| 248 | if (client->startup == joydev->nabs + joydev->nkey && | ||
| 249 | client->head == client->tail && (file->f_flags & O_NONBLOCK)) | ||
| 250 | return -EAGAIN; | 417 | return -EAGAIN; |
| 251 | 418 | ||
| 252 | retval = wait_event_interruptible(joydev->wait, | 419 | retval = wait_event_interruptible(joydev->wait, |
| 253 | !joydev->exist || | 420 | !joydev->exist || joydev_data_pending(client)); |
| 254 | client->startup < joydev->nabs + joydev->nkey || | ||
| 255 | client->head != client->tail); | ||
| 256 | if (retval) | 421 | if (retval) |
| 257 | return retval; | 422 | return retval; |
| 258 | 423 | ||
| 259 | if (!joydev->exist) | 424 | if (!joydev->exist) |
| 260 | return -ENODEV; | 425 | return -ENODEV; |
| 261 | 426 | ||
| 262 | while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { | 427 | while (retval + sizeof(struct js_event) <= count && |
| 263 | 428 | joydev_generate_startup_event(client, input, &event)) { | |
| 264 | struct js_event event; | ||
| 265 | |||
| 266 | event.time = jiffies_to_msecs(jiffies); | ||
| 267 | |||
| 268 | if (client->startup < joydev->nkey) { | ||
| 269 | event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; | ||
| 270 | event.number = client->startup; | ||
| 271 | event.value = !!test_bit(joydev->keypam[event.number], input->key); | ||
| 272 | } else { | ||
| 273 | event.type = JS_EVENT_AXIS | JS_EVENT_INIT; | ||
| 274 | event.number = client->startup - joydev->nkey; | ||
| 275 | event.value = joydev->abs[event.number]; | ||
| 276 | } | ||
| 277 | 429 | ||
| 278 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) | 430 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) |
| 279 | return -EFAULT; | 431 | return -EFAULT; |
| 280 | 432 | ||
| 281 | client->startup++; | ||
| 282 | retval += sizeof(struct js_event); | 433 | retval += sizeof(struct js_event); |
| 283 | } | 434 | } |
| 284 | 435 | ||
| 285 | while (client->head != client->tail && retval + sizeof(struct js_event) <= count) { | 436 | while (retval + sizeof(struct js_event) <= count && |
| 437 | joydev_fetch_next_event(client, &event)) { | ||
| 286 | 438 | ||
| 287 | if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event))) | 439 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) |
| 288 | return -EFAULT; | 440 | return -EFAULT; |
| 289 | 441 | ||
| 290 | client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); | ||
| 291 | retval += sizeof(struct js_event); | 442 | retval += sizeof(struct js_event); |
| 292 | } | 443 | } |
| 293 | 444 | ||
| @@ -301,126 +452,144 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait) | |||
| 301 | struct joydev *joydev = client->joydev; | 452 | struct joydev *joydev = client->joydev; |
| 302 | 453 | ||
| 303 | poll_wait(file, &joydev->wait, wait); | 454 | poll_wait(file, &joydev->wait, wait); |
| 304 | return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ? | 455 | return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) | |
| 305 | (POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR)); | 456 | (joydev->exist ? 0 : (POLLHUP | POLLERR)); |
| 306 | } | 457 | } |
| 307 | 458 | ||
| 308 | static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp) | 459 | static int joydev_ioctl_common(struct joydev *joydev, |
| 460 | unsigned int cmd, void __user *argp) | ||
| 309 | { | 461 | { |
| 310 | struct input_dev *dev = joydev->handle.dev; | 462 | struct input_dev *dev = joydev->handle.dev; |
| 311 | int i, j; | 463 | int i, j; |
| 312 | 464 | ||
| 313 | switch (cmd) { | 465 | switch (cmd) { |
| 314 | 466 | ||
| 315 | case JS_SET_CAL: | 467 | case JS_SET_CAL: |
| 316 | return copy_from_user(&joydev->glue.JS_CORR, argp, | 468 | return copy_from_user(&joydev->glue.JS_CORR, argp, |
| 317 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; | 469 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; |
| 318 | 470 | ||
| 319 | case JS_GET_CAL: | 471 | case JS_GET_CAL: |
| 320 | return copy_to_user(argp, &joydev->glue.JS_CORR, | 472 | return copy_to_user(argp, &joydev->glue.JS_CORR, |
| 321 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; | 473 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; |
| 322 | 474 | ||
| 323 | case JS_SET_TIMEOUT: | 475 | case JS_SET_TIMEOUT: |
| 324 | return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); | 476 | return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); |
| 325 | 477 | ||
| 326 | case JS_GET_TIMEOUT: | 478 | case JS_GET_TIMEOUT: |
| 327 | return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); | 479 | return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); |
| 328 | 480 | ||
| 329 | case JSIOCGVERSION: | 481 | case JSIOCGVERSION: |
| 330 | return put_user(JS_VERSION, (__u32 __user *) argp); | 482 | return put_user(JS_VERSION, (__u32 __user *) argp); |
| 331 | 483 | ||
| 332 | case JSIOCGAXES: | 484 | case JSIOCGAXES: |
| 333 | return put_user(joydev->nabs, (__u8 __user *) argp); | 485 | return put_user(joydev->nabs, (__u8 __user *) argp); |
| 334 | 486 | ||
| 335 | case JSIOCGBUTTONS: | 487 | case JSIOCGBUTTONS: |
| 336 | return put_user(joydev->nkey, (__u8 __user *) argp); | 488 | return put_user(joydev->nkey, (__u8 __user *) argp); |
| 337 | 489 | ||
| 338 | case JSIOCSCORR: | 490 | case JSIOCSCORR: |
| 339 | if (copy_from_user(joydev->corr, argp, | 491 | if (copy_from_user(joydev->corr, argp, |
| 340 | sizeof(joydev->corr[0]) * joydev->nabs)) | 492 | sizeof(joydev->corr[0]) * joydev->nabs)) |
| 341 | return -EFAULT; | 493 | return -EFAULT; |
| 342 | for (i = 0; i < joydev->nabs; i++) { | ||
| 343 | j = joydev->abspam[i]; | ||
| 344 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); | ||
| 345 | } | ||
| 346 | return 0; | ||
| 347 | 494 | ||
| 348 | case JSIOCGCORR: | 495 | for (i = 0; i < joydev->nabs; i++) { |
| 349 | return copy_to_user(argp, joydev->corr, | 496 | j = joydev->abspam[i]; |
| 350 | sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; | 497 | joydev->abs[i] = joydev_correct(dev->abs[j], |
| 498 | &joydev->corr[i]); | ||
| 499 | } | ||
| 500 | return 0; | ||
| 351 | 501 | ||
| 352 | case JSIOCSAXMAP: | 502 | case JSIOCGCORR: |
| 353 | if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1))) | 503 | return copy_to_user(argp, joydev->corr, |
| 354 | return -EFAULT; | 504 | sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; |
| 355 | for (i = 0; i < joydev->nabs; i++) { | 505 | |
| 356 | if (joydev->abspam[i] > ABS_MAX) | 506 | case JSIOCSAXMAP: |
| 357 | return -EINVAL; | 507 | if (copy_from_user(joydev->abspam, argp, |
| 358 | joydev->absmap[joydev->abspam[i]] = i; | 508 | sizeof(__u8) * (ABS_MAX + 1))) |
| 359 | } | 509 | return -EFAULT; |
| 360 | return 0; | 510 | |
| 361 | 511 | for (i = 0; i < joydev->nabs; i++) { | |
| 362 | case JSIOCGAXMAP: | 512 | if (joydev->abspam[i] > ABS_MAX) |
| 363 | return copy_to_user(argp, joydev->abspam, | 513 | return -EINVAL; |
| 364 | sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; | 514 | joydev->absmap[joydev->abspam[i]] = i; |
| 365 | 515 | } | |
| 366 | case JSIOCSBTNMAP: | 516 | return 0; |
| 367 | if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) | 517 | |
| 518 | case JSIOCGAXMAP: | ||
| 519 | return copy_to_user(argp, joydev->abspam, | ||
| 520 | sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; | ||
| 521 | |||
| 522 | case JSIOCSBTNMAP: | ||
| 523 | if (copy_from_user(joydev->keypam, argp, | ||
| 524 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) | ||
| 525 | return -EFAULT; | ||
| 526 | |||
| 527 | for (i = 0; i < joydev->nkey; i++) { | ||
| 528 | if (joydev->keypam[i] > KEY_MAX || | ||
| 529 | joydev->keypam[i] < BTN_MISC) | ||
| 530 | return -EINVAL; | ||
| 531 | joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; | ||
| 532 | } | ||
| 533 | |||
| 534 | return 0; | ||
| 535 | |||
| 536 | case JSIOCGBTNMAP: | ||
| 537 | return copy_to_user(argp, joydev->keypam, | ||
| 538 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; | ||
| 539 | |||
| 540 | default: | ||
| 541 | if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) { | ||
| 542 | int len; | ||
| 543 | if (!dev->name) | ||
| 544 | return 0; | ||
| 545 | len = strlen(dev->name) + 1; | ||
| 546 | if (len > _IOC_SIZE(cmd)) | ||
| 547 | len = _IOC_SIZE(cmd); | ||
| 548 | if (copy_to_user(argp, dev->name, len)) | ||
| 368 | return -EFAULT; | 549 | return -EFAULT; |
| 369 | for (i = 0; i < joydev->nkey; i++) { | 550 | return len; |
| 370 | if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) | 551 | } |
| 371 | return -EINVAL; | ||
| 372 | joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; | ||
| 373 | } | ||
| 374 | return 0; | ||
| 375 | |||
| 376 | case JSIOCGBTNMAP: | ||
| 377 | return copy_to_user(argp, joydev->keypam, | ||
| 378 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; | ||
| 379 | |||
| 380 | default: | ||
| 381 | if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { | ||
| 382 | int len; | ||
| 383 | if (!dev->name) | ||
| 384 | return 0; | ||
| 385 | len = strlen(dev->name) + 1; | ||
| 386 | if (len > _IOC_SIZE(cmd)) | ||
| 387 | len = _IOC_SIZE(cmd); | ||
| 388 | if (copy_to_user(argp, dev->name, len)) | ||
| 389 | return -EFAULT; | ||
| 390 | return len; | ||
| 391 | } | ||
| 392 | } | 552 | } |
| 393 | return -EINVAL; | 553 | return -EINVAL; |
| 394 | } | 554 | } |
| 395 | 555 | ||
| 396 | #ifdef CONFIG_COMPAT | 556 | #ifdef CONFIG_COMPAT |
| 397 | static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 557 | static long joydev_compat_ioctl(struct file *file, |
| 558 | unsigned int cmd, unsigned long arg) | ||
| 398 | { | 559 | { |
| 399 | struct joydev_client *client = file->private_data; | 560 | struct joydev_client *client = file->private_data; |
| 400 | struct joydev *joydev = client->joydev; | 561 | struct joydev *joydev = client->joydev; |
| 401 | void __user *argp = (void __user *)arg; | 562 | void __user *argp = (void __user *)arg; |
| 402 | s32 tmp32; | 563 | s32 tmp32; |
| 403 | struct JS_DATA_SAVE_TYPE_32 ds32; | 564 | struct JS_DATA_SAVE_TYPE_32 ds32; |
| 404 | int err; | 565 | int retval; |
| 405 | 566 | ||
| 406 | if (!joydev->exist) | 567 | retval = mutex_lock_interruptible(&joydev->mutex); |
| 407 | return -ENODEV; | 568 | if (retval) |
| 569 | return retval; | ||
| 570 | |||
| 571 | if (!joydev->exist) { | ||
| 572 | retval = -ENODEV; | ||
| 573 | goto out; | ||
| 574 | } | ||
| 575 | |||
| 576 | switch (cmd) { | ||
| 408 | 577 | ||
| 409 | switch(cmd) { | ||
| 410 | case JS_SET_TIMELIMIT: | 578 | case JS_SET_TIMELIMIT: |
| 411 | err = get_user(tmp32, (s32 __user *) arg); | 579 | retval = get_user(tmp32, (s32 __user *) arg); |
| 412 | if (err == 0) | 580 | if (retval == 0) |
| 413 | joydev->glue.JS_TIMELIMIT = tmp32; | 581 | joydev->glue.JS_TIMELIMIT = tmp32; |
| 414 | break; | 582 | break; |
| 583 | |||
| 415 | case JS_GET_TIMELIMIT: | 584 | case JS_GET_TIMELIMIT: |
| 416 | tmp32 = joydev->glue.JS_TIMELIMIT; | 585 | tmp32 = joydev->glue.JS_TIMELIMIT; |
| 417 | err = put_user(tmp32, (s32 __user *) arg); | 586 | retval = put_user(tmp32, (s32 __user *) arg); |
| 418 | break; | 587 | break; |
| 419 | 588 | ||
| 420 | case JS_SET_ALL: | 589 | case JS_SET_ALL: |
| 421 | err = copy_from_user(&ds32, argp, | 590 | retval = copy_from_user(&ds32, argp, |
| 422 | sizeof(ds32)) ? -EFAULT : 0; | 591 | sizeof(ds32)) ? -EFAULT : 0; |
| 423 | if (err == 0) { | 592 | if (retval == 0) { |
| 424 | joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT; | 593 | joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT; |
| 425 | joydev->glue.BUSY = ds32.BUSY; | 594 | joydev->glue.BUSY = ds32.BUSY; |
| 426 | joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME; | 595 | joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME; |
| @@ -438,55 +607,119 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo | |||
| 438 | ds32.JS_SAVE = joydev->glue.JS_SAVE; | 607 | ds32.JS_SAVE = joydev->glue.JS_SAVE; |
| 439 | ds32.JS_CORR = joydev->glue.JS_CORR; | 608 | ds32.JS_CORR = joydev->glue.JS_CORR; |
| 440 | 609 | ||
| 441 | err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0; | 610 | retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0; |
| 442 | break; | 611 | break; |
| 443 | 612 | ||
| 444 | default: | 613 | default: |
| 445 | err = joydev_ioctl_common(joydev, cmd, argp); | 614 | retval = joydev_ioctl_common(joydev, cmd, argp); |
| 615 | break; | ||
| 446 | } | 616 | } |
| 447 | return err; | 617 | |
| 618 | out: | ||
| 619 | mutex_unlock(&joydev->mutex); | ||
| 620 | return retval; | ||
| 448 | } | 621 | } |
| 449 | #endif /* CONFIG_COMPAT */ | 622 | #endif /* CONFIG_COMPAT */ |
| 450 | 623 | ||
| 451 | static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 624 | static long joydev_ioctl(struct file *file, |
| 625 | unsigned int cmd, unsigned long arg) | ||
| 452 | { | 626 | { |
| 453 | struct joydev_client *client = file->private_data; | 627 | struct joydev_client *client = file->private_data; |
| 454 | struct joydev *joydev = client->joydev; | 628 | struct joydev *joydev = client->joydev; |
| 455 | void __user *argp = (void __user *)arg; | 629 | void __user *argp = (void __user *)arg; |
| 630 | int retval; | ||
| 456 | 631 | ||
| 457 | if (!joydev->exist) | 632 | retval = mutex_lock_interruptible(&joydev->mutex); |
| 458 | return -ENODEV; | 633 | if (retval) |
| 634 | return retval; | ||
| 459 | 635 | ||
| 460 | switch(cmd) { | 636 | if (!joydev->exist) { |
| 461 | case JS_SET_TIMELIMIT: | 637 | retval = -ENODEV; |
| 462 | return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); | 638 | goto out; |
| 463 | case JS_GET_TIMELIMIT: | ||
| 464 | return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); | ||
| 465 | case JS_SET_ALL: | ||
| 466 | return copy_from_user(&joydev->glue, argp, | ||
| 467 | sizeof(joydev->glue)) ? -EFAULT : 0; | ||
| 468 | case JS_GET_ALL: | ||
| 469 | return copy_to_user(argp, &joydev->glue, | ||
| 470 | sizeof(joydev->glue)) ? -EFAULT : 0; | ||
| 471 | default: | ||
| 472 | return joydev_ioctl_common(joydev, cmd, argp); | ||
| 473 | } | 639 | } |
| 640 | |||
| 641 | switch (cmd) { | ||
| 642 | |||
| 643 | case JS_SET_TIMELIMIT: | ||
| 644 | retval = get_user(joydev->glue.JS_TIMELIMIT, | ||
| 645 | (long __user *) arg); | ||
| 646 | break; | ||
| 647 | |||
| 648 | case JS_GET_TIMELIMIT: | ||
| 649 | retval = put_user(joydev->glue.JS_TIMELIMIT, | ||
| 650 | (long __user *) arg); | ||
| 651 | break; | ||
| 652 | |||
| 653 | case JS_SET_ALL: | ||
| 654 | retval = copy_from_user(&joydev->glue, argp, | ||
| 655 | sizeof(joydev->glue)) ? -EFAULT: 0; | ||
| 656 | break; | ||
| 657 | |||
| 658 | case JS_GET_ALL: | ||
| 659 | retval = copy_to_user(argp, &joydev->glue, | ||
| 660 | sizeof(joydev->glue)) ? -EFAULT : 0; | ||
| 661 | break; | ||
| 662 | |||
| 663 | default: | ||
| 664 | retval = joydev_ioctl_common(joydev, cmd, argp); | ||
| 665 | break; | ||
| 666 | } | ||
| 667 | out: | ||
| 668 | mutex_unlock(&joydev->mutex); | ||
| 669 | return retval; | ||
| 474 | } | 670 | } |
| 475 | 671 | ||
| 476 | static const struct file_operations joydev_fops = { | 672 | static const struct file_operations joydev_fops = { |
| 477 | .owner = THIS_MODULE, | 673 | .owner = THIS_MODULE, |
| 478 | .read = joydev_read, | 674 | .read = joydev_read, |
| 479 | .write = joydev_write, | 675 | .poll = joydev_poll, |
| 480 | .poll = joydev_poll, | 676 | .open = joydev_open, |
| 481 | .open = joydev_open, | 677 | .release = joydev_release, |
| 482 | .release = joydev_release, | 678 | .unlocked_ioctl = joydev_ioctl, |
| 483 | .ioctl = joydev_ioctl, | ||
| 484 | #ifdef CONFIG_COMPAT | 679 | #ifdef CONFIG_COMPAT |
| 485 | .compat_ioctl = joydev_compat_ioctl, | 680 | .compat_ioctl = joydev_compat_ioctl, |
| 486 | #endif | 681 | #endif |
| 487 | .fasync = joydev_fasync, | 682 | .fasync = joydev_fasync, |
| 488 | }; | 683 | }; |
| 489 | 684 | ||
| 685 | static int joydev_install_chrdev(struct joydev *joydev) | ||
| 686 | { | ||
| 687 | joydev_table[joydev->minor] = joydev; | ||
| 688 | return 0; | ||
| 689 | } | ||
| 690 | |||
| 691 | static void joydev_remove_chrdev(struct joydev *joydev) | ||
| 692 | { | ||
| 693 | mutex_lock(&joydev_table_mutex); | ||
| 694 | joydev_table[joydev->minor] = NULL; | ||
| 695 | mutex_unlock(&joydev_table_mutex); | ||
| 696 | } | ||
| 697 | |||
| 698 | /* | ||
| 699 | * Mark device non-existant. This disables writes, ioctls and | ||
| 700 | * prevents new users from opening the device. Already posted | ||
| 701 | * blocking reads will stay, however new ones will fail. | ||
| 702 | */ | ||
| 703 | static void joydev_mark_dead(struct joydev *joydev) | ||
| 704 | { | ||
| 705 | mutex_lock(&joydev->mutex); | ||
| 706 | joydev->exist = 0; | ||
| 707 | mutex_unlock(&joydev->mutex); | ||
| 708 | } | ||
| 709 | |||
| 710 | static void joydev_cleanup(struct joydev *joydev) | ||
| 711 | { | ||
| 712 | struct input_handle *handle = &joydev->handle; | ||
| 713 | |||
| 714 | joydev_mark_dead(joydev); | ||
| 715 | joydev_hangup(joydev); | ||
| 716 | joydev_remove_chrdev(joydev); | ||
| 717 | |||
| 718 | /* joydev is marked dead so noone else accesses joydev->open */ | ||
| 719 | if (joydev->open) | ||
| 720 | input_close_device(handle); | ||
| 721 | } | ||
| 722 | |||
| 490 | static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | 723 | static int joydev_connect(struct input_handler *handler, struct input_dev *dev, |
| 491 | const struct input_device_id *id) | 724 | const struct input_device_id *id) |
| 492 | { | 725 | { |
| @@ -494,7 +727,10 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 494 | int i, j, t, minor; | 727 | int i, j, t, minor; |
| 495 | int error; | 728 | int error; |
| 496 | 729 | ||
| 497 | for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); | 730 | for (minor = 0; minor < JOYDEV_MINORS; minor++) |
| 731 | if (!joydev_table[minor]) | ||
| 732 | break; | ||
| 733 | |||
| 498 | if (minor == JOYDEV_MINORS) { | 734 | if (minor == JOYDEV_MINORS) { |
| 499 | printk(KERN_ERR "joydev: no more free joydev devices\n"); | 735 | printk(KERN_ERR "joydev: no more free joydev devices\n"); |
| 500 | return -ENFILE; | 736 | return -ENFILE; |
| @@ -505,15 +741,19 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 505 | return -ENOMEM; | 741 | return -ENOMEM; |
| 506 | 742 | ||
| 507 | INIT_LIST_HEAD(&joydev->client_list); | 743 | INIT_LIST_HEAD(&joydev->client_list); |
| 744 | spin_lock_init(&joydev->client_lock); | ||
| 745 | mutex_init(&joydev->mutex); | ||
| 508 | init_waitqueue_head(&joydev->wait); | 746 | init_waitqueue_head(&joydev->wait); |
| 509 | 747 | ||
| 748 | snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); | ||
| 749 | joydev->exist = 1; | ||
| 510 | joydev->minor = minor; | 750 | joydev->minor = minor; |
| 751 | |||
| 511 | joydev->exist = 1; | 752 | joydev->exist = 1; |
| 512 | joydev->handle.dev = dev; | 753 | joydev->handle.dev = dev; |
| 513 | joydev->handle.name = joydev->name; | 754 | joydev->handle.name = joydev->name; |
| 514 | joydev->handle.handler = handler; | 755 | joydev->handle.handler = handler; |
| 515 | joydev->handle.private = joydev; | 756 | joydev->handle.private = joydev; |
| 516 | snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); | ||
| 517 | 757 | ||
| 518 | for (i = 0; i < ABS_MAX + 1; i++) | 758 | for (i = 0; i < ABS_MAX + 1; i++) |
| 519 | if (test_bit(i, dev->absbit)) { | 759 | if (test_bit(i, dev->absbit)) { |
| @@ -545,67 +785,65 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 545 | } | 785 | } |
| 546 | joydev->corr[i].type = JS_CORR_BROKEN; | 786 | joydev->corr[i].type = JS_CORR_BROKEN; |
| 547 | joydev->corr[i].prec = dev->absfuzz[j]; | 787 | joydev->corr[i].prec = dev->absfuzz[j]; |
| 548 | joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; | 788 | joydev->corr[i].coef[0] = |
| 549 | joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; | 789 | (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; |
| 550 | if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]))) | 790 | joydev->corr[i].coef[1] = |
| 551 | continue; | 791 | (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; |
| 552 | joydev->corr[i].coef[2] = (1 << 29) / t; | 792 | |
| 553 | joydev->corr[i].coef[3] = (1 << 29) / t; | 793 | t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]; |
| 554 | 794 | if (t) { | |
| 555 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); | 795 | joydev->corr[i].coef[2] = (1 << 29) / t; |
| 796 | joydev->corr[i].coef[3] = (1 << 29) / t; | ||
| 797 | |||
| 798 | joydev->abs[i] = joydev_correct(dev->abs[j], | ||
| 799 | joydev->corr + i); | ||
| 800 | } | ||
| 556 | } | 801 | } |
| 557 | 802 | ||
| 558 | snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id), | 803 | strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id)); |
| 559 | "js%d", minor); | 804 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); |
| 560 | joydev->dev.class = &input_class; | 805 | joydev->dev.class = &input_class; |
| 561 | joydev->dev.parent = &dev->dev; | 806 | joydev->dev.parent = &dev->dev; |
| 562 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); | ||
| 563 | joydev->dev.release = joydev_free; | 807 | joydev->dev.release = joydev_free; |
| 564 | device_initialize(&joydev->dev); | 808 | device_initialize(&joydev->dev); |
| 565 | 809 | ||
| 566 | joydev_table[minor] = joydev; | 810 | error = input_register_handle(&joydev->handle); |
| 567 | |||
| 568 | error = device_add(&joydev->dev); | ||
| 569 | if (error) | 811 | if (error) |
| 570 | goto err_free_joydev; | 812 | goto err_free_joydev; |
| 571 | 813 | ||
| 572 | error = input_register_handle(&joydev->handle); | 814 | error = joydev_install_chrdev(joydev); |
| 573 | if (error) | 815 | if (error) |
| 574 | goto err_delete_joydev; | 816 | goto err_unregister_handle; |
| 817 | |||
| 818 | error = device_add(&joydev->dev); | ||
| 819 | if (error) | ||
| 820 | goto err_cleanup_joydev; | ||
| 575 | 821 | ||
| 576 | return 0; | 822 | return 0; |
| 577 | 823 | ||
| 578 | err_delete_joydev: | 824 | err_cleanup_joydev: |
| 579 | device_del(&joydev->dev); | 825 | joydev_cleanup(joydev); |
| 826 | err_unregister_handle: | ||
| 827 | input_unregister_handle(&joydev->handle); | ||
| 580 | err_free_joydev: | 828 | err_free_joydev: |
| 581 | put_device(&joydev->dev); | 829 | put_device(&joydev->dev); |
| 582 | return error; | 830 | return error; |
| 583 | } | 831 | } |
| 584 | 832 | ||
| 585 | |||
| 586 | static void joydev_disconnect(struct input_handle *handle) | 833 | static void joydev_disconnect(struct input_handle *handle) |
| 587 | { | 834 | { |
| 588 | struct joydev *joydev = handle->private; | 835 | struct joydev *joydev = handle->private; |
| 589 | struct joydev_client *client; | ||
| 590 | 836 | ||
| 591 | input_unregister_handle(handle); | ||
| 592 | device_del(&joydev->dev); | 837 | device_del(&joydev->dev); |
| 593 | 838 | joydev_cleanup(joydev); | |
| 594 | joydev->exist = 0; | 839 | input_unregister_handle(handle); |
| 595 | |||
| 596 | if (joydev->open) { | ||
| 597 | input_close_device(handle); | ||
| 598 | list_for_each_entry(client, &joydev->client_list, node) | ||
| 599 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
| 600 | wake_up_interruptible(&joydev->wait); | ||
| 601 | } | ||
| 602 | |||
| 603 | put_device(&joydev->dev); | 840 | put_device(&joydev->dev); |
| 604 | } | 841 | } |
| 605 | 842 | ||
| 606 | static const struct input_device_id joydev_blacklist[] = { | 843 | static const struct input_device_id joydev_blacklist[] = { |
| 607 | { | 844 | { |
| 608 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | 845 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 846 | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
| 609 | .evbit = { BIT(EV_KEY) }, | 847 | .evbit = { BIT(EV_KEY) }, |
| 610 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | 848 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, |
| 611 | }, /* Avoid itouchpads, touchscreens and tablets */ | 849 | }, /* Avoid itouchpads, touchscreens and tablets */ |
| @@ -614,17 +852,20 @@ static const struct input_device_id joydev_blacklist[] = { | |||
| 614 | 852 | ||
| 615 | static const struct input_device_id joydev_ids[] = { | 853 | static const struct input_device_id joydev_ids[] = { |
| 616 | { | 854 | { |
| 617 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 855 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 856 | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
| 618 | .evbit = { BIT(EV_ABS) }, | 857 | .evbit = { BIT(EV_ABS) }, |
| 619 | .absbit = { BIT(ABS_X) }, | 858 | .absbit = { BIT(ABS_X) }, |
| 620 | }, | 859 | }, |
| 621 | { | 860 | { |
| 622 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 861 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 862 | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
| 623 | .evbit = { BIT(EV_ABS) }, | 863 | .evbit = { BIT(EV_ABS) }, |
| 624 | .absbit = { BIT(ABS_WHEEL) }, | 864 | .absbit = { BIT(ABS_WHEEL) }, |
| 625 | }, | 865 | }, |
| 626 | { | 866 | { |
| 627 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 867 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 868 | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
| 628 | .evbit = { BIT(EV_ABS) }, | 869 | .evbit = { BIT(EV_ABS) }, |
| 629 | .absbit = { BIT(ABS_THROTTLE) }, | 870 | .absbit = { BIT(ABS_THROTTLE) }, |
| 630 | }, | 871 | }, |
| @@ -634,14 +875,14 @@ static const struct input_device_id joydev_ids[] = { | |||
| 634 | MODULE_DEVICE_TABLE(input, joydev_ids); | 875 | MODULE_DEVICE_TABLE(input, joydev_ids); |
| 635 | 876 | ||
| 636 | static struct input_handler joydev_handler = { | 877 | static struct input_handler joydev_handler = { |
| 637 | .event = joydev_event, | 878 | .event = joydev_event, |
| 638 | .connect = joydev_connect, | 879 | .connect = joydev_connect, |
| 639 | .disconnect = joydev_disconnect, | 880 | .disconnect = joydev_disconnect, |
| 640 | .fops = &joydev_fops, | 881 | .fops = &joydev_fops, |
| 641 | .minor = JOYDEV_MINOR_BASE, | 882 | .minor = JOYDEV_MINOR_BASE, |
| 642 | .name = "joydev", | 883 | .name = "joydev", |
| 643 | .id_table = joydev_ids, | 884 | .id_table = joydev_ids, |
| 644 | .blacklist = joydev_blacklist, | 885 | .blacklist = joydev_blacklist, |
| 645 | }; | 886 | }; |
| 646 | 887 | ||
| 647 | static int __init joydev_init(void) | 888 | static int __init joydev_init(void) |
