diff options
author | Kristian Høgsberg <krh@redhat.com> | 2007-03-28 15:26:42 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2007-03-28 15:30:14 -0400 |
commit | 66dea3e5f69abfdfa46b091ea117e497758351e7 (patch) | |
tree | 5db4238ff230cdb86f5c977c5a8cf0e76d055310 | |
parent | da8ecffaed434a12930f652898f9e86d1c2abc3e (diff) |
firewire: Add ioctls to add and remove config rom descriptors.
Signed-off-by: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (fixed whitespace)
-rw-r--r-- | drivers/firewire/fw-card.c | 2 | ||||
-rw-r--r-- | drivers/firewire/fw-device-cdev.c | 94 | ||||
-rw-r--r-- | drivers/firewire/fw-device-cdev.h | 23 |
3 files changed, 114 insertions, 5 deletions
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index 34863b60e23f..3eb06556a0c1 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c | |||
@@ -160,7 +160,7 @@ fw_core_add_descriptor (struct fw_descriptor *desc) | |||
160 | i += (desc->data[i] >> 16) + 1; | 160 | i += (desc->data[i] >> 16) + 1; |
161 | 161 | ||
162 | if (i != desc->length) | 162 | if (i != desc->length) |
163 | return -1; | 163 | return -EINVAL; |
164 | 164 | ||
165 | down_write(&fw_bus_type.subsys.rwsem); | 165 | down_write(&fw_bus_type.subsys.rwsem); |
166 | 166 | ||
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 | ||
548 | struct descriptor { | ||
549 | struct fw_descriptor d; | ||
550 | struct list_head link; | ||
551 | u32 handle; | ||
552 | u32 data[0]; | ||
553 | }; | ||
554 | |||
555 | static 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 | |||
602 | static 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 | |||
545 | static void | 629 | static void |
546 | iso_callback(struct fw_iso_context *context, u32 cycle, | 630 | iso_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 | ||
diff --git a/drivers/firewire/fw-device-cdev.h b/drivers/firewire/fw-device-cdev.h index 72befda989ba..62f5f66ca101 100644 --- a/drivers/firewire/fw-device-cdev.h +++ b/drivers/firewire/fw-device-cdev.h | |||
@@ -130,10 +130,13 @@ union fw_cdev_event { | |||
130 | #define FW_CDEV_IOC_DEALLOCATE _IO('#', 0x03) | 130 | #define FW_CDEV_IOC_DEALLOCATE _IO('#', 0x03) |
131 | #define FW_CDEV_IOC_SEND_RESPONSE _IO('#', 0x04) | 131 | #define FW_CDEV_IOC_SEND_RESPONSE _IO('#', 0x04) |
132 | #define FW_CDEV_IOC_INITIATE_BUS_RESET _IO('#', 0x05) | 132 | #define FW_CDEV_IOC_INITIATE_BUS_RESET _IO('#', 0x05) |
133 | #define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IO('#', 0x06) | 133 | #define FW_CDEV_IOC_ADD_DESCRIPTOR _IO('#', 0x06) |
134 | #define FW_CDEV_IOC_QUEUE_ISO _IO('#', 0x07) | 134 | #define FW_CDEV_IOC_REMOVE_DESCRIPTOR _IO('#', 0x07) |
135 | #define FW_CDEV_IOC_START_ISO _IO('#', 0x08) | 135 | |
136 | #define FW_CDEV_IOC_STOP_ISO _IO('#', 0x09) | 136 | #define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IO('#', 0x08) |
137 | #define FW_CDEV_IOC_QUEUE_ISO _IO('#', 0x09) | ||
138 | #define FW_CDEV_IOC_START_ISO _IO('#', 0x0a) | ||
139 | #define FW_CDEV_IOC_STOP_ISO _IO('#', 0x0b) | ||
137 | 140 | ||
138 | /* FW_CDEV_VERSION History | 141 | /* FW_CDEV_VERSION History |
139 | * | 142 | * |
@@ -203,6 +206,18 @@ struct fw_cdev_initiate_bus_reset { | |||
203 | __u32 type; | 206 | __u32 type; |
204 | }; | 207 | }; |
205 | 208 | ||
209 | struct fw_cdev_add_descriptor { | ||
210 | __u32 immediate; | ||
211 | __u32 key; | ||
212 | __u64 data; | ||
213 | __u32 length; | ||
214 | __u32 handle; | ||
215 | }; | ||
216 | |||
217 | struct fw_cdev_remove_descriptor { | ||
218 | __u32 handle; | ||
219 | }; | ||
220 | |||
206 | #define FW_CDEV_ISO_CONTEXT_TRANSMIT 0 | 221 | #define FW_CDEV_ISO_CONTEXT_TRANSMIT 0 |
207 | #define FW_CDEV_ISO_CONTEXT_RECEIVE 1 | 222 | #define FW_CDEV_ISO_CONTEXT_RECEIVE 1 |
208 | 223 | ||