aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/fw-device-cdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire/fw-device-cdev.c')
-rw-r--r--drivers/firewire/fw-device-cdev.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/drivers/firewire/fw-device-cdev.c b/drivers/firewire/fw-device-cdev.c
index 12471444f1bd..e3c4a52a44a9 100644
--- a/drivers/firewire/fw-device-cdev.c
+++ b/drivers/firewire/fw-device-cdev.c
@@ -73,9 +73,11 @@ struct client {
73 u32 version; 73 u32 version;
74 struct fw_device *device; 74 struct fw_device *device;
75 spinlock_t lock; 75 spinlock_t lock;
76 u32 resource_handle;
76 struct list_head handler_list; 77 struct list_head handler_list;
77 struct list_head request_list; 78 struct list_head request_list;
78 struct list_head transaction_list; 79 struct list_head transaction_list;
80 struct list_head descriptor_list;
79 u32 request_serial; 81 u32 request_serial;
80 struct list_head event_list; 82 struct list_head event_list;
81 wait_queue_head_t wait; 83 wait_queue_head_t wait;
@@ -119,6 +121,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
119 INIT_LIST_HEAD(&client->handler_list); 121 INIT_LIST_HEAD(&client->handler_list);
120 INIT_LIST_HEAD(&client->request_list); 122 INIT_LIST_HEAD(&client->request_list);
121 INIT_LIST_HEAD(&client->transaction_list); 123 INIT_LIST_HEAD(&client->transaction_list);
124 INIT_LIST_HEAD(&client->descriptor_list);
122 spin_lock_init(&client->lock); 125 spin_lock_init(&client->lock);
123 init_waitqueue_head(&client->wait); 126 init_waitqueue_head(&client->wait);
124 127
@@ -542,6 +545,87 @@ static int ioctl_initiate_bus_reset(struct client *client, void __user *arg)
542 return fw_core_initiate_bus_reset(client->device->card, short_reset); 545 return fw_core_initiate_bus_reset(client->device->card, short_reset);
543} 546}
544 547
548struct descriptor {
549 struct fw_descriptor d;
550 struct list_head link;
551 u32 handle;
552 u32 data[0];
553};
554
555static int ioctl_add_descriptor(struct client *client, void __user *arg)
556{
557 struct fw_cdev_add_descriptor request;
558 struct descriptor *descriptor;
559 unsigned long flags;
560 int retval;
561
562 if (copy_from_user(&request, arg, sizeof request))
563 return -EFAULT;
564
565 if (request.length > 256)
566 return -EINVAL;
567
568 descriptor =
569 kmalloc(sizeof *descriptor + request.length * 4, GFP_KERNEL);
570 if (descriptor == NULL)
571 return -ENOMEM;
572
573 if (copy_from_user(descriptor->data,
574 u64_to_uptr(request.data), request.length * 4)) {
575 kfree(descriptor);
576 return -EFAULT;
577 }
578
579 descriptor->d.length = request.length;
580 descriptor->d.immediate = request.immediate;
581 descriptor->d.key = request.key;
582 descriptor->d.data = descriptor->data;
583
584 retval = fw_core_add_descriptor(&descriptor->d);
585 if (retval < 0) {
586 kfree(descriptor);
587 return retval;
588 }
589
590 spin_lock_irqsave(&client->lock, flags);
591 list_add_tail(&descriptor->link, &client->descriptor_list);
592 descriptor->handle = client->resource_handle++;
593 spin_unlock_irqrestore(&client->lock, flags);
594
595 request.handle = descriptor->handle;
596 if (copy_to_user(arg, &request, sizeof request))
597 return -EFAULT;
598
599 return 0;
600}
601
602static int ioctl_remove_descriptor(struct client *client, void __user *arg)
603{
604 struct fw_cdev_remove_descriptor request;
605 struct descriptor *d;
606 unsigned long flags;
607
608 if (copy_from_user(&request, arg, sizeof request))
609 return -EFAULT;
610
611 spin_lock_irqsave(&client->lock, flags);
612 list_for_each_entry(d, &client->descriptor_list, link) {
613 if (d->handle == request.handle) {
614 list_del(&d->link);
615 break;
616 }
617 }
618 spin_unlock_irqrestore(&client->lock, flags);
619
620 if (&d->link == &client->descriptor_list)
621 return -EINVAL;
622
623 fw_core_remove_descriptor(&d->d);
624 kfree(d);
625
626 return 0;
627}
628
545static void 629static void
546iso_callback(struct fw_iso_context *context, u32 cycle, 630iso_callback(struct fw_iso_context *context, u32 cycle,
547 size_t header_length, void *header, void *data) 631 size_t header_length, void *header, void *data)
@@ -731,6 +815,10 @@ dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
731 return ioctl_send_response(client, arg); 815 return ioctl_send_response(client, arg);
732 case FW_CDEV_IOC_INITIATE_BUS_RESET: 816 case FW_CDEV_IOC_INITIATE_BUS_RESET:
733 return ioctl_initiate_bus_reset(client, arg); 817 return ioctl_initiate_bus_reset(client, arg);
818 case FW_CDEV_IOC_ADD_DESCRIPTOR:
819 return ioctl_add_descriptor(client, arg);
820 case FW_CDEV_IOC_REMOVE_DESCRIPTOR:
821 return ioctl_remove_descriptor(client, arg);
734 case FW_CDEV_IOC_CREATE_ISO_CONTEXT: 822 case FW_CDEV_IOC_CREATE_ISO_CONTEXT:
735 return ioctl_create_iso_context(client, arg); 823 return ioctl_create_iso_context(client, arg);
736 case FW_CDEV_IOC_QUEUE_ISO: 824 case FW_CDEV_IOC_QUEUE_ISO:
@@ -811,6 +899,7 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
811 struct request *r, *next_r; 899 struct request *r, *next_r;
812 struct event *e, *next_e; 900 struct event *e, *next_e;
813 struct response *t, *next_t; 901 struct response *t, *next_t;
902 struct descriptor *d, *next_d;
814 unsigned long flags; 903 unsigned long flags;
815 904
816 if (client->buffer.pages) 905 if (client->buffer.pages)
@@ -835,6 +924,11 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
835 kfree(t); 924 kfree(t);
836 } 925 }
837 926
927 list_for_each_entry_safe(d, next_d, &client->descriptor_list, link) {
928 fw_core_remove_descriptor(&d->d);
929 kfree(d);
930 }
931
838 /* FIXME: We should wait for the async tasklets to stop 932 /* FIXME: We should wait for the async tasklets to stop
839 * running before freeing the memory. */ 933 * running before freeing the memory. */
840 934