firewire: cdev: unify names of struct types and of their instances
[deliverable/linux.git] / drivers / firewire / fw-cdev.c
CommitLineData
c781c06d
KH
1/*
2 * Char device for device raw access
19a15b93 3 *
c781c06d 4 * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.net>
19a15b93
KH
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21#include <linux/module.h>
22#include <linux/kernel.h>
fb443036 23#include <linux/kref.h>
19a15b93
KH
24#include <linux/wait.h>
25#include <linux/errno.h>
26#include <linux/device.h>
27#include <linux/vmalloc.h>
d67cfb96 28#include <linux/mutex.h>
19a15b93 29#include <linux/poll.h>
a64408b9
SR
30#include <linux/preempt.h>
31#include <linux/time.h>
cf417e54 32#include <linux/spinlock.h>
19a15b93
KH
33#include <linux/delay.h>
34#include <linux/mm.h>
a3aca3da 35#include <linux/idr.h>
19a15b93 36#include <linux/compat.h>
9640d3d7 37#include <linux/firewire-cdev.h>
a64408b9 38#include <asm/system.h>
19a15b93
KH
39#include <asm/uaccess.h>
40#include "fw-transaction.h"
41#include "fw-topology.h"
42#include "fw-device.h"
19a15b93 43
19a15b93 44struct client {
344bbc4d 45 u32 version;
19a15b93 46 struct fw_device *device;
45ee3199 47
19a15b93 48 spinlock_t lock;
45ee3199
JF
49 bool in_shutdown;
50 struct idr resource_idr;
19a15b93 51 struct list_head event_list;
19a15b93 52 wait_queue_head_t wait;
da8ecffa 53 u64 bus_reset_closure;
9aad8125 54
19a15b93 55 struct fw_iso_context *iso_context;
abaa5743 56 u64 iso_closure;
9aad8125
KH
57 struct fw_iso_buffer buffer;
58 unsigned long vm_start;
97bd9efa
KH
59
60 struct list_head link;
fb443036 61 struct kref kref;
19a15b93
KH
62};
63
fb443036
SR
64static inline void client_get(struct client *client)
65{
66 kref_get(&client->kref);
67}
68
69static void client_release(struct kref *kref)
70{
71 struct client *client = container_of(kref, struct client, kref);
72
73 fw_device_put(client->device);
74 kfree(client);
75}
76
77static void client_put(struct client *client)
78{
79 kref_put(&client->kref, client_release);
80}
81
97c18b7f
SR
82struct client_resource;
83typedef void (*client_resource_release_fn_t)(struct client *,
84 struct client_resource *);
85struct client_resource {
86 client_resource_release_fn_t release;
87 int handle;
88};
89
90struct address_handler_resource {
91 struct client_resource resource;
92 struct fw_address_handler handler;
93 __u64 closure;
94 struct client *client;
95};
96
97struct outbound_transaction_resource {
98 struct client_resource resource;
99 struct fw_transaction transaction;
100};
101
102struct inbound_transaction_resource {
103 struct client_resource resource;
104 struct fw_request *request;
105 void *data;
106 size_t length;
107};
108
109struct descriptor_resource {
110 struct client_resource resource;
111 struct fw_descriptor descriptor;
112 u32 data[0];
113};
114
115/*
116 * dequeue_event() just kfree()'s the event, so the event has to be
117 * the first field in a struct XYZ_event.
118 */
119struct event {
120 struct { void *data; size_t size; } v[2];
121 struct list_head link;
122};
123
124struct bus_reset_event {
125 struct event event;
126 struct fw_cdev_event_bus_reset reset;
127};
128
129struct outbound_transaction_event {
130 struct event event;
131 struct client *client;
132 struct outbound_transaction_resource r;
133 struct fw_cdev_event_response response;
134};
135
136struct inbound_transaction_event {
137 struct event event;
138 struct fw_cdev_event_request request;
139};
140
141struct iso_interrupt_event {
142 struct event event;
143 struct fw_cdev_event_iso_interrupt interrupt;
144};
145
53dca511 146static inline void __user *u64_to_uptr(__u64 value)
19a15b93
KH
147{
148 return (void __user *)(unsigned long)value;
149}
150
53dca511 151static inline __u64 uptr_to_u64(void __user *ptr)
19a15b93
KH
152{
153 return (__u64)(unsigned long)ptr;
154}
155
156static int fw_device_op_open(struct inode *inode, struct file *file)
157{
158 struct fw_device *device;
159 struct client *client;
160
96b19062 161 device = fw_device_get_by_devt(inode->i_rdev);
a3aca3da
KH
162 if (device == NULL)
163 return -ENODEV;
19a15b93 164
551f4cb9
JF
165 if (fw_device_is_shutdown(device)) {
166 fw_device_put(device);
167 return -ENODEV;
168 }
169
2d826cc5 170 client = kzalloc(sizeof(*client), GFP_KERNEL);
96b19062
SR
171 if (client == NULL) {
172 fw_device_put(device);
19a15b93 173 return -ENOMEM;
96b19062 174 }
19a15b93 175
96b19062 176 client->device = device;
19a15b93 177 spin_lock_init(&client->lock);
45ee3199
JF
178 idr_init(&client->resource_idr);
179 INIT_LIST_HEAD(&client->event_list);
19a15b93 180 init_waitqueue_head(&client->wait);
fb443036 181 kref_init(&client->kref);
19a15b93
KH
182
183 file->private_data = client;
184
d67cfb96 185 mutex_lock(&device->client_list_mutex);
97bd9efa 186 list_add_tail(&client->link, &device->client_list);
d67cfb96 187 mutex_unlock(&device->client_list_mutex);
97bd9efa 188
19a15b93
KH
189 return 0;
190}
191
192static void queue_event(struct client *client, struct event *event,
193 void *data0, size_t size0, void *data1, size_t size1)
194{
195 unsigned long flags;
196
197 event->v[0].data = data0;
198 event->v[0].size = size0;
199 event->v[1].data = data1;
200 event->v[1].size = size1;
201
202 spin_lock_irqsave(&client->lock, flags);
45ee3199
JF
203 if (client->in_shutdown)
204 kfree(event);
205 else
206 list_add_tail(&event->link, &client->event_list);
19a15b93 207 spin_unlock_irqrestore(&client->lock, flags);
83431cba
JF
208
209 wake_up_interruptible(&client->wait);
19a15b93
KH
210}
211
53dca511
SR
212static int dequeue_event(struct client *client,
213 char __user *buffer, size_t count)
19a15b93
KH
214{
215 unsigned long flags;
216 struct event *event;
217 size_t size, total;
2dbd7d7e 218 int i, ret;
19a15b93 219
2dbd7d7e
SR
220 ret = wait_event_interruptible(client->wait,
221 !list_empty(&client->event_list) ||
222 fw_device_is_shutdown(client->device));
223 if (ret < 0)
224 return ret;
19a15b93 225
2603bf21
KH
226 if (list_empty(&client->event_list) &&
227 fw_device_is_shutdown(client->device))
228 return -ENODEV;
19a15b93 229
2603bf21 230 spin_lock_irqsave(&client->lock, flags);
a459b8ab 231 event = list_first_entry(&client->event_list, struct event, link);
19a15b93 232 list_del(&event->link);
19a15b93
KH
233 spin_unlock_irqrestore(&client->lock, flags);
234
19a15b93
KH
235 total = 0;
236 for (i = 0; i < ARRAY_SIZE(event->v) && total < count; i++) {
237 size = min(event->v[i].size, count - total);
2603bf21 238 if (copy_to_user(buffer + total, event->v[i].data, size)) {
2dbd7d7e 239 ret = -EFAULT;
19a15b93 240 goto out;
2603bf21 241 }
19a15b93
KH
242 total += size;
243 }
2dbd7d7e 244 ret = total;
19a15b93
KH
245
246 out:
247 kfree(event);
248
2dbd7d7e 249 return ret;
19a15b93
KH
250}
251
53dca511
SR
252static ssize_t fw_device_op_read(struct file *file, char __user *buffer,
253 size_t count, loff_t *offset)
19a15b93
KH
254{
255 struct client *client = file->private_data;
256
257 return dequeue_event(client, buffer, count);
258}
259
53dca511
SR
260static void fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
261 struct client *client)
344bbc4d 262{
da8ecffa 263 struct fw_card *card = client->device->card;
cf417e54
JF
264 unsigned long flags;
265
266 spin_lock_irqsave(&card->lock, flags);
344bbc4d 267
da8ecffa 268 event->closure = client->bus_reset_closure;
344bbc4d 269 event->type = FW_CDEV_EVENT_BUS_RESET;
cf5a56ac 270 event->generation = client->device->generation;
da8ecffa 271 event->node_id = client->device->node_id;
344bbc4d
KH
272 event->local_node_id = card->local_node->node_id;
273 event->bm_node_id = 0; /* FIXME: We don't track the BM. */
274 event->irm_node_id = card->irm_node->node_id;
275 event->root_node_id = card->root_node->node_id;
cf417e54
JF
276
277 spin_unlock_irqrestore(&card->lock, flags);
344bbc4d
KH
278}
279
53dca511
SR
280static void for_each_client(struct fw_device *device,
281 void (*callback)(struct client *client))
2603bf21 282{
2603bf21 283 struct client *c;
2603bf21 284
d67cfb96 285 mutex_lock(&device->client_list_mutex);
2603bf21
KH
286 list_for_each_entry(c, &device->client_list, link)
287 callback(c);
d67cfb96 288 mutex_unlock(&device->client_list_mutex);
2603bf21
KH
289}
290
53dca511 291static void queue_bus_reset_event(struct client *client)
97bd9efa 292{
97c18b7f 293 struct bus_reset_event *e;
97bd9efa 294
97c18b7f
SR
295 e = kzalloc(sizeof(*e), GFP_KERNEL);
296 if (e == NULL) {
97bd9efa
KH
297 fw_notify("Out of memory when allocating bus reset event\n");
298 return;
299 }
300
97c18b7f 301 fill_bus_reset_event(&e->reset, client);
97bd9efa 302
97c18b7f
SR
303 queue_event(client, &e->event,
304 &e->reset, sizeof(e->reset), NULL, 0);
97bd9efa
KH
305}
306
307void fw_device_cdev_update(struct fw_device *device)
308{
2603bf21
KH
309 for_each_client(device, queue_bus_reset_event);
310}
97bd9efa 311
2603bf21
KH
312static void wake_up_client(struct client *client)
313{
314 wake_up_interruptible(&client->wait);
315}
97bd9efa 316
2603bf21
KH
317void fw_device_cdev_remove(struct fw_device *device)
318{
319 for_each_client(device, wake_up_client);
97bd9efa
KH
320}
321
4f259223 322static int ioctl_get_info(struct client *client, void *buffer)
19a15b93 323{
4f259223 324 struct fw_cdev_get_info *get_info = buffer;
344bbc4d 325 struct fw_cdev_event_bus_reset bus_reset;
c9755e14 326 unsigned long ret = 0;
344bbc4d 327
4f259223
KH
328 client->version = get_info->version;
329 get_info->version = FW_CDEV_VERSION;
cf417e54 330 get_info->card = client->device->card->index;
344bbc4d 331
c9755e14
SR
332 down_read(&fw_device_rwsem);
333
4f259223
KH
334 if (get_info->rom != 0) {
335 void __user *uptr = u64_to_uptr(get_info->rom);
336 size_t want = get_info->rom_length;
d84702a5 337 size_t have = client->device->config_rom_length * 4;
344bbc4d 338
c9755e14
SR
339 ret = copy_to_user(uptr, client->device->config_rom,
340 min(want, have));
344bbc4d 341 }
4f259223 342 get_info->rom_length = client->device->config_rom_length * 4;
344bbc4d 343
c9755e14
SR
344 up_read(&fw_device_rwsem);
345
346 if (ret != 0)
347 return -EFAULT;
348
4f259223
KH
349 client->bus_reset_closure = get_info->bus_reset_closure;
350 if (get_info->bus_reset != 0) {
351 void __user *uptr = u64_to_uptr(get_info->bus_reset);
344bbc4d 352
da8ecffa 353 fill_bus_reset_event(&bus_reset, client);
2d826cc5 354 if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset)))
344bbc4d
KH
355 return -EFAULT;
356 }
19a15b93 357
19a15b93
KH
358 return 0;
359}
360
53dca511
SR
361static int add_client_resource(struct client *client,
362 struct client_resource *resource, gfp_t gfp_mask)
3964a449
KH
363{
364 unsigned long flags;
45ee3199
JF
365 int ret;
366
367 retry:
368 if (idr_pre_get(&client->resource_idr, gfp_mask) == 0)
369 return -ENOMEM;
3964a449
KH
370
371 spin_lock_irqsave(&client->lock, flags);
45ee3199
JF
372 if (client->in_shutdown)
373 ret = -ECANCELED;
374 else
375 ret = idr_get_new(&client->resource_idr, resource,
376 &resource->handle);
fb443036
SR
377 if (ret >= 0)
378 client_get(client);
3964a449 379 spin_unlock_irqrestore(&client->lock, flags);
45ee3199
JF
380
381 if (ret == -EAGAIN)
382 goto retry;
383
384 return ret < 0 ? ret : 0;
3964a449
KH
385}
386
53dca511
SR
387static int release_client_resource(struct client *client, u32 handle,
388 client_resource_release_fn_t release,
389 struct client_resource **resource)
3964a449
KH
390{
391 struct client_resource *r;
392 unsigned long flags;
393
394 spin_lock_irqsave(&client->lock, flags);
45ee3199
JF
395 if (client->in_shutdown)
396 r = NULL;
397 else
398 r = idr_find(&client->resource_idr, handle);
399 if (r && r->release == release)
400 idr_remove(&client->resource_idr, handle);
3964a449
KH
401 spin_unlock_irqrestore(&client->lock, flags);
402
45ee3199 403 if (!(r && r->release == release))
3964a449
KH
404 return -EINVAL;
405
406 if (resource)
407 *resource = r;
408 else
409 r->release(client, r);
410
fb443036
SR
411 client_put(client);
412
3964a449
KH
413 return 0;
414}
415
53dca511
SR
416static void release_transaction(struct client *client,
417 struct client_resource *resource)
3964a449 418{
97c18b7f
SR
419 struct outbound_transaction_resource *r = container_of(resource,
420 struct outbound_transaction_resource, resource);
3964a449 421
97c18b7f 422 fw_cancel_transaction(client->device->card, &r->transaction);
3964a449
KH
423}
424
53dca511
SR
425static void complete_transaction(struct fw_card *card, int rcode,
426 void *payload, size_t length, void *data)
19a15b93 427{
97c18b7f
SR
428 struct outbound_transaction_event *e = data;
429 struct fw_cdev_event_response *rsp = &e->response;
430 struct client *client = e->client;
28cf6a04 431 unsigned long flags;
19a15b93 432
97c18b7f
SR
433 if (length < rsp->length)
434 rsp->length = length;
19a15b93 435 if (rcode == RCODE_COMPLETE)
97c18b7f 436 memcpy(rsp->data, payload, rsp->length);
19a15b93 437
28cf6a04 438 spin_lock_irqsave(&client->lock, flags);
45ee3199 439 /*
fb443036
SR
440 * 1. If called while in shutdown, the idr tree must be left untouched.
441 * The idr handle will be removed and the client reference will be
442 * dropped later.
443 * 2. If the call chain was release_client_resource ->
444 * release_transaction -> complete_transaction (instead of a normal
445 * conclusion of the transaction), i.e. if this resource was already
446 * unregistered from the idr, the client reference will be dropped
447 * by release_client_resource and we must not drop it here.
45ee3199 448 */
fb443036 449 if (!client->in_shutdown &&
97c18b7f
SR
450 idr_find(&client->resource_idr, e->r.resource.handle)) {
451 idr_remove(&client->resource_idr, e->r.resource.handle);
fb443036
SR
452 /* Drop the idr's reference */
453 client_put(client);
454 }
28cf6a04
KH
455 spin_unlock_irqrestore(&client->lock, flags);
456
97c18b7f
SR
457 rsp->type = FW_CDEV_EVENT_RESPONSE;
458 rsp->rcode = rcode;
8401d92b
DM
459
460 /*
97c18b7f 461 * In the case that sizeof(*rsp) doesn't align with the position of the
8401d92b
DM
462 * data, and the read is short, preserve an extra copy of the data
463 * to stay compatible with a pre-2.6.27 bug. Since the bug is harmless
464 * for short reads and some apps depended on it, this is both safe
465 * and prudent for compatibility.
466 */
97c18b7f
SR
467 if (rsp->length <= sizeof(*rsp) - offsetof(typeof(*rsp), data))
468 queue_event(client, &e->event, rsp, sizeof(*rsp),
469 rsp->data, rsp->length);
8401d92b 470 else
97c18b7f 471 queue_event(client, &e->event, rsp, sizeof(*rsp) + rsp->length,
8401d92b 472 NULL, 0);
fb443036
SR
473
474 /* Drop the transaction callback's reference */
475 client_put(client);
19a15b93
KH
476}
477
350958f9 478static int ioctl_send_request(struct client *client, void *buffer)
19a15b93
KH
479{
480 struct fw_device *device = client->device;
4f259223 481 struct fw_cdev_send_request *request = buffer;
97c18b7f 482 struct outbound_transaction_event *e;
1f3125af 483 int ret;
19a15b93 484
19a15b93 485 /* What is the biggest size we'll accept, really? */
4f259223 486 if (request->length > 4096)
19a15b93
KH
487 return -EINVAL;
488
97c18b7f
SR
489 e = kmalloc(sizeof(*e) + request->length, GFP_KERNEL);
490 if (e == NULL)
19a15b93
KH
491 return -ENOMEM;
492
97c18b7f
SR
493 e->client = client;
494 e->response.length = request->length;
495 e->response.closure = request->closure;
19a15b93 496
4f259223 497 if (request->data &&
97c18b7f 498 copy_from_user(e->response.data,
4f259223 499 u64_to_uptr(request->data), request->length)) {
1f3125af 500 ret = -EFAULT;
45ee3199 501 goto failed;
1f3125af
SR
502 }
503
504 switch (request->tcode) {
505 case TCODE_WRITE_QUADLET_REQUEST:
506 case TCODE_WRITE_BLOCK_REQUEST:
507 case TCODE_READ_QUADLET_REQUEST:
508 case TCODE_READ_BLOCK_REQUEST:
509 case TCODE_LOCK_MASK_SWAP:
510 case TCODE_LOCK_COMPARE_SWAP:
511 case TCODE_LOCK_FETCH_ADD:
512 case TCODE_LOCK_LITTLE_ADD:
513 case TCODE_LOCK_BOUNDED_ADD:
514 case TCODE_LOCK_WRAP_ADD:
515 case TCODE_LOCK_VENDOR_DEPENDENT:
516 break;
517 default:
518 ret = -EINVAL;
45ee3199 519 goto failed;
19a15b93
KH
520 }
521
97c18b7f
SR
522 e->r.resource.release = release_transaction;
523 ret = add_client_resource(client, &e->r.resource, GFP_KERNEL);
45ee3199
JF
524 if (ret < 0)
525 goto failed;
28cf6a04 526
fb443036
SR
527 /* Get a reference for the transaction callback */
528 client_get(client);
529
97c18b7f 530 fw_send_request(device->card, &e->r.transaction,
4f259223 531 request->tcode & 0x1f,
907293d7 532 device->node->node_id,
4f259223 533 request->generation,
f1397490 534 device->max_speed,
4f259223 535 request->offset,
97c18b7f
SR
536 e->response.data, request->length,
537 complete_transaction, e);
19a15b93 538
4f259223 539 if (request->data)
2d826cc5 540 return sizeof(request) + request->length;
19a15b93 541 else
2d826cc5 542 return sizeof(request);
45ee3199 543 failed:
97c18b7f 544 kfree(e);
1f3125af
SR
545
546 return ret;
19a15b93
KH
547}
548
53dca511
SR
549static void release_request(struct client *client,
550 struct client_resource *resource)
3964a449 551{
97c18b7f
SR
552 struct inbound_transaction_resource *r = container_of(resource,
553 struct inbound_transaction_resource, resource);
3964a449 554
97c18b7f 555 fw_send_response(client->device->card, r->request,
3964a449 556 RCODE_CONFLICT_ERROR);
97c18b7f 557 kfree(r);
3964a449
KH
558}
559
97c18b7f 560static void handle_request(struct fw_card *card, struct fw_request *request,
53dca511
SR
561 int tcode, int destination, int source,
562 int generation, int speed,
563 unsigned long long offset,
564 void *payload, size_t length, void *callback_data)
19a15b93 565{
97c18b7f
SR
566 struct address_handler_resource *handler = callback_data;
567 struct inbound_transaction_resource *r;
568 struct inbound_transaction_event *e;
45ee3199 569 int ret;
19a15b93 570
97c18b7f 571 r = kmalloc(sizeof(*r), GFP_ATOMIC);
2d826cc5 572 e = kmalloc(sizeof(*e), GFP_ATOMIC);
97c18b7f 573 if (r == NULL || e == NULL)
45ee3199 574 goto failed;
19a15b93 575
97c18b7f
SR
576 r->request = request;
577 r->data = payload;
578 r->length = length;
19a15b93 579
97c18b7f
SR
580 r->resource.release = release_request;
581 ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC);
45ee3199
JF
582 if (ret < 0)
583 goto failed;
19a15b93
KH
584
585 e->request.type = FW_CDEV_EVENT_REQUEST;
586 e->request.tcode = tcode;
587 e->request.offset = offset;
588 e->request.length = length;
97c18b7f 589 e->request.handle = r->resource.handle;
19a15b93
KH
590 e->request.closure = handler->closure;
591
97c18b7f 592 queue_event(handler->client, &e->event,
2d826cc5 593 &e->request, sizeof(e->request), payload, length);
45ee3199
JF
594 return;
595
596 failed:
97c18b7f 597 kfree(r);
45ee3199 598 kfree(e);
97c18b7f 599 fw_send_response(card, request, RCODE_CONFLICT_ERROR);
19a15b93
KH
600}
601
53dca511
SR
602static void release_address_handler(struct client *client,
603 struct client_resource *resource)
3964a449 604{
97c18b7f
SR
605 struct address_handler_resource *r =
606 container_of(resource, struct address_handler_resource, resource);
3964a449 607
97c18b7f
SR
608 fw_core_remove_address_handler(&r->handler);
609 kfree(r);
3964a449
KH
610}
611
4f259223 612static int ioctl_allocate(struct client *client, void *buffer)
19a15b93 613{
4f259223 614 struct fw_cdev_allocate *request = buffer;
97c18b7f 615 struct address_handler_resource *r;
19a15b93 616 struct fw_address_region region;
45ee3199 617 int ret;
19a15b93 618
97c18b7f
SR
619 r = kmalloc(sizeof(*r), GFP_KERNEL);
620 if (r == NULL)
19a15b93
KH
621 return -ENOMEM;
622
4f259223
KH
623 region.start = request->offset;
624 region.end = request->offset + request->length;
97c18b7f
SR
625 r->handler.length = request->length;
626 r->handler.address_callback = handle_request;
627 r->handler.callback_data = r;
628 r->closure = request->closure;
629 r->client = client;
19a15b93 630
97c18b7f 631 ret = fw_core_add_address_handler(&r->handler, &region);
3e0b5f0d 632 if (ret < 0) {
97c18b7f 633 kfree(r);
3e0b5f0d 634 return ret;
19a15b93
KH
635 }
636
97c18b7f
SR
637 r->resource.release = release_address_handler;
638 ret = add_client_resource(client, &r->resource, GFP_KERNEL);
45ee3199 639 if (ret < 0) {
97c18b7f 640 release_address_handler(client, &r->resource);
45ee3199
JF
641 return ret;
642 }
97c18b7f 643 request->handle = r->resource.handle;
19a15b93
KH
644
645 return 0;
646}
647
4f259223 648static int ioctl_deallocate(struct client *client, void *buffer)
9472316b 649{
4f259223 650 struct fw_cdev_deallocate *request = buffer;
9472316b 651
45ee3199
JF
652 return release_client_resource(client, request->handle,
653 release_address_handler, NULL);
9472316b
KH
654}
655
4f259223 656static int ioctl_send_response(struct client *client, void *buffer)
19a15b93 657{
4f259223 658 struct fw_cdev_send_response *request = buffer;
3964a449 659 struct client_resource *resource;
97c18b7f 660 struct inbound_transaction_resource *r;
19a15b93 661
45ee3199
JF
662 if (release_client_resource(client, request->handle,
663 release_request, &resource) < 0)
19a15b93 664 return -EINVAL;
45ee3199 665
97c18b7f
SR
666 r = container_of(resource, struct inbound_transaction_resource,
667 resource);
4f259223
KH
668 if (request->length < r->length)
669 r->length = request->length;
670 if (copy_from_user(r->data, u64_to_uptr(request->data), r->length))
19a15b93
KH
671 return -EFAULT;
672
4f259223 673 fw_send_response(client->device->card, r->request, request->rcode);
19a15b93
KH
674 kfree(r);
675
676 return 0;
677}
678
4f259223 679static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
5371842b 680{
4f259223 681 struct fw_cdev_initiate_bus_reset *request = buffer;
5371842b
KH
682 int short_reset;
683
4f259223 684 short_reset = (request->type == FW_CDEV_SHORT_RESET);
5371842b
KH
685
686 return fw_core_initiate_bus_reset(client->device->card, short_reset);
687}
688
3964a449
KH
689static void release_descriptor(struct client *client,
690 struct client_resource *resource)
691{
97c18b7f
SR
692 struct descriptor_resource *r =
693 container_of(resource, struct descriptor_resource, resource);
3964a449 694
97c18b7f
SR
695 fw_core_remove_descriptor(&r->descriptor);
696 kfree(r);
3964a449
KH
697}
698
4f259223 699static int ioctl_add_descriptor(struct client *client, void *buffer)
66dea3e5 700{
4f259223 701 struct fw_cdev_add_descriptor *request = buffer;
97c18b7f 702 struct descriptor_resource *r;
45ee3199 703 int ret;
66dea3e5 704
4f259223 705 if (request->length > 256)
66dea3e5
KH
706 return -EINVAL;
707
97c18b7f
SR
708 r = kmalloc(sizeof(*r) + request->length * 4, GFP_KERNEL);
709 if (r == NULL)
66dea3e5
KH
710 return -ENOMEM;
711
97c18b7f 712 if (copy_from_user(r->data,
4f259223 713 u64_to_uptr(request->data), request->length * 4)) {
45ee3199
JF
714 ret = -EFAULT;
715 goto failed;
66dea3e5
KH
716 }
717
97c18b7f
SR
718 r->descriptor.length = request->length;
719 r->descriptor.immediate = request->immediate;
720 r->descriptor.key = request->key;
721 r->descriptor.data = r->data;
66dea3e5 722
97c18b7f 723 ret = fw_core_add_descriptor(&r->descriptor);
45ee3199
JF
724 if (ret < 0)
725 goto failed;
66dea3e5 726
97c18b7f
SR
727 r->resource.release = release_descriptor;
728 ret = add_client_resource(client, &r->resource, GFP_KERNEL);
45ee3199 729 if (ret < 0) {
97c18b7f 730 fw_core_remove_descriptor(&r->descriptor);
45ee3199
JF
731 goto failed;
732 }
97c18b7f 733 request->handle = r->resource.handle;
66dea3e5
KH
734
735 return 0;
45ee3199 736 failed:
97c18b7f 737 kfree(r);
45ee3199
JF
738
739 return ret;
66dea3e5
KH
740}
741
4f259223 742static int ioctl_remove_descriptor(struct client *client, void *buffer)
66dea3e5 743{
4f259223 744 struct fw_cdev_remove_descriptor *request = buffer;
66dea3e5 745
45ee3199
JF
746 return release_client_resource(client, request->handle,
747 release_descriptor, NULL);
66dea3e5
KH
748}
749
53dca511
SR
750static void iso_callback(struct fw_iso_context *context, u32 cycle,
751 size_t header_length, void *header, void *data)
19a15b93
KH
752{
753 struct client *client = data;
97c18b7f 754 struct iso_interrupt_event *e;
19a15b93 755
97c18b7f
SR
756 e = kzalloc(sizeof(*e) + header_length, GFP_ATOMIC);
757 if (e == NULL)
19a15b93
KH
758 return;
759
97c18b7f
SR
760 e->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
761 e->interrupt.closure = client->iso_closure;
762 e->interrupt.cycle = cycle;
763 e->interrupt.header_length = header_length;
764 memcpy(e->interrupt.header, header, header_length);
765 queue_event(client, &e->event, &e->interrupt,
766 sizeof(e->interrupt) + header_length, NULL, 0);
19a15b93
KH
767}
768
4f259223 769static int ioctl_create_iso_context(struct client *client, void *buffer)
19a15b93 770{
4f259223 771 struct fw_cdev_create_iso_context *request = buffer;
24315c5e 772 struct fw_iso_context *context;
19a15b93 773
fae60312
SR
774 /* We only support one context at this time. */
775 if (client->iso_context != NULL)
776 return -EBUSY;
777
4f259223 778 if (request->channel > 63)
21efb3cf
KH
779 return -EINVAL;
780
4f259223 781 switch (request->type) {
c70dc788 782 case FW_ISO_CONTEXT_RECEIVE:
4f259223 783 if (request->header_size < 4 || (request->header_size & 3))
c70dc788 784 return -EINVAL;
98b6cbe8 785
c70dc788
KH
786 break;
787
788 case FW_ISO_CONTEXT_TRANSMIT:
4f259223 789 if (request->speed > SCODE_3200)
c70dc788
KH
790 return -EINVAL;
791
792 break;
793
794 default:
21efb3cf 795 return -EINVAL;
c70dc788
KH
796 }
797
24315c5e
KH
798 context = fw_iso_context_create(client->device->card,
799 request->type,
800 request->channel,
801 request->speed,
802 request->header_size,
803 iso_callback, client);
804 if (IS_ERR(context))
805 return PTR_ERR(context);
806
abaa5743 807 client->iso_closure = request->closure;
24315c5e 808 client->iso_context = context;
19a15b93 809
abaa5743
KH
810 /* We only support one context at this time. */
811 request->handle = 0;
812
19a15b93
KH
813 return 0;
814}
815
1ca31ae7
KH
816/* Macros for decoding the iso packet control header. */
817#define GET_PAYLOAD_LENGTH(v) ((v) & 0xffff)
818#define GET_INTERRUPT(v) (((v) >> 16) & 0x01)
819#define GET_SKIP(v) (((v) >> 17) & 0x01)
7a100344
SR
820#define GET_TAG(v) (((v) >> 18) & 0x03)
821#define GET_SY(v) (((v) >> 20) & 0x0f)
1ca31ae7
KH
822#define GET_HEADER_LENGTH(v) (((v) >> 24) & 0xff)
823
4f259223 824static int ioctl_queue_iso(struct client *client, void *buffer)
19a15b93 825{
4f259223 826 struct fw_cdev_queue_iso *request = buffer;
19a15b93 827 struct fw_cdev_iso_packet __user *p, *end, *next;
9b32d5f3 828 struct fw_iso_context *ctx = client->iso_context;
ef370ee7 829 unsigned long payload, buffer_end, header_length;
1ca31ae7 830 u32 control;
19a15b93
KH
831 int count;
832 struct {
833 struct fw_iso_packet packet;
834 u8 header[256];
835 } u;
836
abaa5743 837 if (ctx == NULL || request->handle != 0)
19a15b93 838 return -EINVAL;
19a15b93 839
c781c06d
KH
840 /*
841 * If the user passes a non-NULL data pointer, has mmap()'ed
19a15b93
KH
842 * the iso buffer, and the pointer points inside the buffer,
843 * we setup the payload pointers accordingly. Otherwise we
9aad8125 844 * set them both to 0, which will still let packets with
19a15b93
KH
845 * payload_length == 0 through. In other words, if no packets
846 * use the indirect payload, the iso buffer need not be mapped
c781c06d
KH
847 * and the request->data pointer is ignored.
848 */
19a15b93 849
4f259223 850 payload = (unsigned long)request->data - client->vm_start;
ef370ee7 851 buffer_end = client->buffer.page_count << PAGE_SHIFT;
4f259223 852 if (request->data == 0 || client->buffer.pages == NULL ||
ef370ee7 853 payload >= buffer_end) {
9aad8125 854 payload = 0;
ef370ee7 855 buffer_end = 0;
19a15b93
KH
856 }
857
1ccc9147
AV
858 p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
859
860 if (!access_ok(VERIFY_READ, p, request->size))
19a15b93
KH
861 return -EFAULT;
862
4f259223 863 end = (void __user *)p + request->size;
19a15b93
KH
864 count = 0;
865 while (p < end) {
1ca31ae7 866 if (get_user(control, &p->control))
19a15b93 867 return -EFAULT;
1ca31ae7
KH
868 u.packet.payload_length = GET_PAYLOAD_LENGTH(control);
869 u.packet.interrupt = GET_INTERRUPT(control);
870 u.packet.skip = GET_SKIP(control);
871 u.packet.tag = GET_TAG(control);
872 u.packet.sy = GET_SY(control);
873 u.packet.header_length = GET_HEADER_LENGTH(control);
295e3feb 874
9b32d5f3 875 if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) {
295e3feb
KH
876 header_length = u.packet.header_length;
877 } else {
c781c06d
KH
878 /*
879 * We require that header_length is a multiple of
880 * the fixed header size, ctx->header_size.
881 */
9b32d5f3
KH
882 if (ctx->header_size == 0) {
883 if (u.packet.header_length > 0)
884 return -EINVAL;
885 } else if (u.packet.header_length % ctx->header_size != 0) {
295e3feb 886 return -EINVAL;
9b32d5f3 887 }
295e3feb
KH
888 header_length = 0;
889 }
890
19a15b93 891 next = (struct fw_cdev_iso_packet __user *)
295e3feb 892 &p->header[header_length / 4];
19a15b93
KH
893 if (next > end)
894 return -EINVAL;
895 if (__copy_from_user
295e3feb 896 (u.packet.header, p->header, header_length))
19a15b93 897 return -EFAULT;
98b6cbe8 898 if (u.packet.skip && ctx->type == FW_ISO_CONTEXT_TRANSMIT &&
19a15b93
KH
899 u.packet.header_length + u.packet.payload_length > 0)
900 return -EINVAL;
ef370ee7 901 if (payload + u.packet.payload_length > buffer_end)
19a15b93
KH
902 return -EINVAL;
903
9b32d5f3
KH
904 if (fw_iso_context_queue(ctx, &u.packet,
905 &client->buffer, payload))
19a15b93
KH
906 break;
907
908 p = next;
909 payload += u.packet.payload_length;
910 count++;
911 }
912
4f259223
KH
913 request->size -= uptr_to_u64(p) - request->packets;
914 request->packets = uptr_to_u64(p);
915 request->data = client->vm_start + payload;
19a15b93
KH
916
917 return count;
918}
919
4f259223 920static int ioctl_start_iso(struct client *client, void *buffer)
19a15b93 921{
4f259223 922 struct fw_cdev_start_iso *request = buffer;
19a15b93 923
fae60312 924 if (client->iso_context == NULL || request->handle != 0)
abaa5743 925 return -EINVAL;
fae60312 926
eb0306ea 927 if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) {
4f259223 928 if (request->tags == 0 || request->tags > 15)
eb0306ea
KH
929 return -EINVAL;
930
4f259223 931 if (request->sync > 15)
eb0306ea
KH
932 return -EINVAL;
933 }
934
4f259223
KH
935 return fw_iso_context_start(client->iso_context, request->cycle,
936 request->sync, request->tags);
19a15b93
KH
937}
938
4f259223 939static int ioctl_stop_iso(struct client *client, void *buffer)
b8295668 940{
abaa5743
KH
941 struct fw_cdev_stop_iso *request = buffer;
942
fae60312 943 if (client->iso_context == NULL || request->handle != 0)
abaa5743
KH
944 return -EINVAL;
945
b8295668
KH
946 return fw_iso_context_stop(client->iso_context);
947}
948
a64408b9
SR
949static int ioctl_get_cycle_timer(struct client *client, void *buffer)
950{
951 struct fw_cdev_get_cycle_timer *request = buffer;
952 struct fw_card *card = client->device->card;
953 unsigned long long bus_time;
954 struct timeval tv;
955 unsigned long flags;
956
957 preempt_disable();
958 local_irq_save(flags);
959
960 bus_time = card->driver->get_bus_time(card);
961 do_gettimeofday(&tv);
962
963 local_irq_restore(flags);
964 preempt_enable();
965
966 request->local_time = tv.tv_sec * 1000000ULL + tv.tv_usec;
967 request->cycle_timer = bus_time & 0xffffffff;
968 return 0;
969}
970
4f259223
KH
971static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
972 ioctl_get_info,
973 ioctl_send_request,
974 ioctl_allocate,
975 ioctl_deallocate,
976 ioctl_send_response,
977 ioctl_initiate_bus_reset,
978 ioctl_add_descriptor,
979 ioctl_remove_descriptor,
980 ioctl_create_iso_context,
981 ioctl_queue_iso,
982 ioctl_start_iso,
983 ioctl_stop_iso,
a64408b9 984 ioctl_get_cycle_timer,
4f259223
KH
985};
986
53dca511
SR
987static int dispatch_ioctl(struct client *client,
988 unsigned int cmd, void __user *arg)
19a15b93 989{
4f259223 990 char buffer[256];
2dbd7d7e 991 int ret;
4f259223
KH
992
993 if (_IOC_TYPE(cmd) != '#' ||
994 _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers))
19a15b93 995 return -EINVAL;
4f259223
KH
996
997 if (_IOC_DIR(cmd) & _IOC_WRITE) {
2d826cc5 998 if (_IOC_SIZE(cmd) > sizeof(buffer) ||
4f259223
KH
999 copy_from_user(buffer, arg, _IOC_SIZE(cmd)))
1000 return -EFAULT;
1001 }
1002
2dbd7d7e
SR
1003 ret = ioctl_handlers[_IOC_NR(cmd)](client, buffer);
1004 if (ret < 0)
1005 return ret;
4f259223
KH
1006
1007 if (_IOC_DIR(cmd) & _IOC_READ) {
2d826cc5 1008 if (_IOC_SIZE(cmd) > sizeof(buffer) ||
4f259223
KH
1009 copy_to_user(arg, buffer, _IOC_SIZE(cmd)))
1010 return -EFAULT;
19a15b93 1011 }
4f259223 1012
2dbd7d7e 1013 return ret;
19a15b93
KH
1014}
1015
53dca511
SR
1016static long fw_device_op_ioctl(struct file *file,
1017 unsigned int cmd, unsigned long arg)
19a15b93
KH
1018{
1019 struct client *client = file->private_data;
1020
551f4cb9
JF
1021 if (fw_device_is_shutdown(client->device))
1022 return -ENODEV;
1023
19a15b93
KH
1024 return dispatch_ioctl(client, cmd, (void __user *) arg);
1025}
1026
1027#ifdef CONFIG_COMPAT
53dca511
SR
1028static long fw_device_op_compat_ioctl(struct file *file,
1029 unsigned int cmd, unsigned long arg)
19a15b93
KH
1030{
1031 struct client *client = file->private_data;
1032
551f4cb9
JF
1033 if (fw_device_is_shutdown(client->device))
1034 return -ENODEV;
1035
19a15b93
KH
1036 return dispatch_ioctl(client, cmd, compat_ptr(arg));
1037}
1038#endif
1039
1040static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
1041{
1042 struct client *client = file->private_data;
9aad8125
KH
1043 enum dma_data_direction direction;
1044 unsigned long size;
2dbd7d7e 1045 int page_count, ret;
9aad8125 1046
551f4cb9
JF
1047 if (fw_device_is_shutdown(client->device))
1048 return -ENODEV;
1049
9aad8125
KH
1050 /* FIXME: We could support multiple buffers, but we don't. */
1051 if (client->buffer.pages != NULL)
1052 return -EBUSY;
1053
1054 if (!(vma->vm_flags & VM_SHARED))
1055 return -EINVAL;
19a15b93 1056
9aad8125 1057 if (vma->vm_start & ~PAGE_MASK)
19a15b93
KH
1058 return -EINVAL;
1059
1060 client->vm_start = vma->vm_start;
9aad8125
KH
1061 size = vma->vm_end - vma->vm_start;
1062 page_count = size >> PAGE_SHIFT;
1063 if (size & ~PAGE_MASK)
1064 return -EINVAL;
1065
1066 if (vma->vm_flags & VM_WRITE)
1067 direction = DMA_TO_DEVICE;
1068 else
1069 direction = DMA_FROM_DEVICE;
1070
2dbd7d7e
SR
1071 ret = fw_iso_buffer_init(&client->buffer, client->device->card,
1072 page_count, direction);
1073 if (ret < 0)
1074 return ret;
19a15b93 1075
2dbd7d7e
SR
1076 ret = fw_iso_buffer_map(&client->buffer, vma);
1077 if (ret < 0)
9aad8125
KH
1078 fw_iso_buffer_destroy(&client->buffer, client->device->card);
1079
2dbd7d7e 1080 return ret;
19a15b93
KH
1081}
1082
45ee3199
JF
1083static int shutdown_resource(int id, void *p, void *data)
1084{
1085 struct client_resource *r = p;
1086 struct client *client = data;
1087
1088 r->release(client, r);
fb443036 1089 client_put(client);
45ee3199
JF
1090
1091 return 0;
1092}
1093
19a15b93
KH
1094static int fw_device_op_release(struct inode *inode, struct file *file)
1095{
1096 struct client *client = file->private_data;
2603bf21 1097 struct event *e, *next_e;
45ee3199 1098 unsigned long flags;
19a15b93 1099
97811e34
SR
1100 mutex_lock(&client->device->client_list_mutex);
1101 list_del(&client->link);
1102 mutex_unlock(&client->device->client_list_mutex);
1103
9aad8125
KH
1104 if (client->buffer.pages)
1105 fw_iso_buffer_destroy(&client->buffer, client->device->card);
1106
19a15b93
KH
1107 if (client->iso_context)
1108 fw_iso_context_destroy(client->iso_context);
1109
45ee3199
JF
1110 /* Freeze client->resource_idr and client->event_list */
1111 spin_lock_irqsave(&client->lock, flags);
1112 client->in_shutdown = true;
1113 spin_unlock_irqrestore(&client->lock, flags);
66dea3e5 1114
45ee3199
JF
1115 idr_for_each(&client->resource_idr, shutdown_resource, client);
1116 idr_remove_all(&client->resource_idr);
1117 idr_destroy(&client->resource_idr);
28cf6a04 1118
2603bf21
KH
1119 list_for_each_entry_safe(e, next_e, &client->event_list, link)
1120 kfree(e);
19a15b93 1121
fb443036 1122 client_put(client);
19a15b93
KH
1123
1124 return 0;
1125}
1126
1127static unsigned int fw_device_op_poll(struct file *file, poll_table * pt)
1128{
1129 struct client *client = file->private_data;
2603bf21 1130 unsigned int mask = 0;
19a15b93
KH
1131
1132 poll_wait(file, &client->wait, pt);
1133
2603bf21
KH
1134 if (fw_device_is_shutdown(client->device))
1135 mask |= POLLHUP | POLLERR;
19a15b93 1136 if (!list_empty(&client->event_list))
2603bf21
KH
1137 mask |= POLLIN | POLLRDNORM;
1138
1139 return mask;
19a15b93
KH
1140}
1141
21ebcd12 1142const struct file_operations fw_device_ops = {
19a15b93
KH
1143 .owner = THIS_MODULE,
1144 .open = fw_device_op_open,
1145 .read = fw_device_op_read,
1146 .unlocked_ioctl = fw_device_op_ioctl,
1147 .poll = fw_device_op_poll,
1148 .release = fw_device_op_release,
1149 .mmap = fw_device_op_mmap,
1150
1151#ifdef CONFIG_COMPAT
5af4e5ea 1152 .compat_ioctl = fw_device_op_compat_ioctl,
19a15b93
KH
1153#endif
1154};
This page took 0.271852 seconds and 5 git commands to generate.