aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/fw-device-cdev.c
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2007-03-07 12:12:48 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-03-09 16:03:11 -0500
commit2603bf219e9bef3396b96b65326de7db27958c95 (patch)
tree1e18057a1a7e4f22c0b7eaec1b3330ad426cdb72 /drivers/firewire/fw-device-cdev.c
parent2aaad97be6b58ae865f402fcd27d138e7346ff81 (diff)
firewire: Use only a wait queue and terminate poll and read on device removal.
Drop the event list semaphore and only use the wait queue and the list to synchronize queue access. Break out of a poll or read whenever the device is disconnected. Signed-off-by: Kristian Høgsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/fw-device-cdev.c')
-rw-r--r--drivers/firewire/fw-device-cdev.c80
1 files changed, 51 insertions, 29 deletions
diff --git a/drivers/firewire/fw-device-cdev.c b/drivers/firewire/fw-device-cdev.c
index 54ef27b2adb5..2d84284f7605 100644
--- a/drivers/firewire/fw-device-cdev.c
+++ b/drivers/firewire/fw-device-cdev.c
@@ -76,7 +76,6 @@ struct client {
76 struct list_head request_list; 76 struct list_head request_list;
77 u32 request_serial; 77 u32 request_serial;
78 struct list_head event_list; 78 struct list_head event_list;
79 struct semaphore event_list_sem;
80 wait_queue_head_t wait; 79 wait_queue_head_t wait;
81 80
82 struct fw_iso_context *iso_context; 81 struct fw_iso_context *iso_context;
@@ -114,7 +113,6 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
114 113
115 client->device = fw_device_get(device); 114 client->device = fw_device_get(device);
116 INIT_LIST_HEAD(&client->event_list); 115 INIT_LIST_HEAD(&client->event_list);
117 sema_init(&client->event_list_sem, 0);
118 INIT_LIST_HEAD(&client->handler_list); 116 INIT_LIST_HEAD(&client->handler_list);
119 INIT_LIST_HEAD(&client->request_list); 117 INIT_LIST_HEAD(&client->request_list);
120 spin_lock_init(&client->lock); 118 spin_lock_init(&client->lock);
@@ -142,38 +140,41 @@ static void queue_event(struct client *client, struct event *event,
142 spin_lock_irqsave(&client->lock, flags); 140 spin_lock_irqsave(&client->lock, flags);
143 141
144 list_add_tail(&event->link, &client->event_list); 142 list_add_tail(&event->link, &client->event_list);
145
146 up(&client->event_list_sem);
147 wake_up_interruptible(&client->wait); 143 wake_up_interruptible(&client->wait);
148 144
149 spin_unlock_irqrestore(&client->lock, flags); 145 spin_unlock_irqrestore(&client->lock, flags);
150} 146}
151 147
152static int dequeue_event(struct client *client, char __user *buffer, size_t count) 148static int
149dequeue_event(struct client *client, char __user *buffer, size_t count)
153{ 150{
154 unsigned long flags; 151 unsigned long flags;
155 struct event *event; 152 struct event *event;
156 size_t size, total; 153 size_t size, total;
157 int i, retval = -EFAULT; 154 int i, retval;
158 155
159 if (down_interruptible(&client->event_list_sem) < 0) 156 retval = wait_event_interruptible(client->wait,
160 return -EINTR; 157 !list_empty(&client->event_list) ||
158 fw_device_is_shutdown(client->device));
159 if (retval < 0)
160 return retval;
161 161
162 spin_lock_irqsave(&client->lock, flags); 162 if (list_empty(&client->event_list) &&
163 fw_device_is_shutdown(client->device))
164 return -ENODEV;
163 165
166 spin_lock_irqsave(&client->lock, flags);
164 event = container_of(client->event_list.next, struct event, link); 167 event = container_of(client->event_list.next, struct event, link);
165 list_del(&event->link); 168 list_del(&event->link);
166
167 spin_unlock_irqrestore(&client->lock, flags); 169 spin_unlock_irqrestore(&client->lock, flags);
168 170
169 if (buffer == NULL)
170 goto out;
171
172 total = 0; 171 total = 0;
173 for (i = 0; i < ARRAY_SIZE(event->v) && total < count; i++) { 172 for (i = 0; i < ARRAY_SIZE(event->v) && total < count; i++) {
174 size = min(event->v[i].size, count - total); 173 size = min(event->v[i].size, count - total);
175 if (copy_to_user(buffer + total, event->v[i].data, size)) 174 if (copy_to_user(buffer + total, event->v[i].data, size)) {
175 retval = -EFAULT;
176 goto out; 176 goto out;
177 }
177 total += size; 178 total += size;
178 } 179 }
179 retval = total; 180 retval = total;
@@ -209,6 +210,22 @@ fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
209} 210}
210 211
211static void 212static void
213for_each_client(struct fw_device *device,
214 void (*callback)(struct client *client))
215{
216 struct fw_card *card = device->card;
217 struct client *c;
218 unsigned long flags;
219
220 spin_lock_irqsave(&card->lock, flags);
221
222 list_for_each_entry(c, &device->client_list, link)
223 callback(c);
224
225 spin_unlock_irqrestore(&card->lock, flags);
226}
227
228static void
212queue_bus_reset_event(struct client *client) 229queue_bus_reset_event(struct client *client)
213{ 230{
214 struct bus_reset *bus_reset; 231 struct bus_reset *bus_reset;
@@ -228,16 +245,17 @@ queue_bus_reset_event(struct client *client)
228 245
229void fw_device_cdev_update(struct fw_device *device) 246void fw_device_cdev_update(struct fw_device *device)
230{ 247{
231 struct fw_card *card = device->card; 248 for_each_client(device, queue_bus_reset_event);
232 struct client *c; 249}
233 unsigned long flags;
234
235 spin_lock_irqsave(&card->lock, flags);
236 250
237 list_for_each_entry(c, &device->client_list, link) 251static void wake_up_client(struct client *client)
238 queue_bus_reset_event(c); 252{
253 wake_up_interruptible(&client->wait);
254}
239 255
240 spin_unlock_irqrestore(&card->lock, flags); 256void fw_device_cdev_remove(struct fw_device *device)
257{
258 for_each_client(device, wake_up_client);
241} 259}
242 260
243static int ioctl_get_info(struct client *client, void __user *arg) 261static int ioctl_get_info(struct client *client, void __user *arg)
@@ -731,8 +749,9 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
731static int fw_device_op_release(struct inode *inode, struct file *file) 749static int fw_device_op_release(struct inode *inode, struct file *file)
732{ 750{
733 struct client *client = file->private_data; 751 struct client *client = file->private_data;
734 struct address_handler *h, *next; 752 struct address_handler *h, *next_h;
735 struct request *r, *next_r; 753 struct request *r, *next_r;
754 struct event *e, *next_e;
736 unsigned long flags; 755 unsigned long flags;
737 756
738 if (client->buffer.pages) 757 if (client->buffer.pages)
@@ -741,7 +760,7 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
741 if (client->iso_context) 760 if (client->iso_context)
742 fw_iso_context_destroy(client->iso_context); 761 fw_iso_context_destroy(client->iso_context);
743 762
744 list_for_each_entry_safe(h, next, &client->handler_list, link) { 763 list_for_each_entry_safe(h, next_h, &client->handler_list, link) {
745 fw_core_remove_address_handler(&h->handler); 764 fw_core_remove_address_handler(&h->handler);
746 kfree(h); 765 kfree(h);
747 } 766 }
@@ -755,8 +774,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
755 /* TODO: wait for all transactions to finish so 774 /* TODO: wait for all transactions to finish so
756 * complete_transaction doesn't try to queue up responses 775 * complete_transaction doesn't try to queue up responses
757 * after we free client. */ 776 * after we free client. */
758 while (!list_empty(&client->event_list)) 777 list_for_each_entry_safe(e, next_e, &client->event_list, link)
759 dequeue_event(client, NULL, 0); 778 kfree(e);
760 779
761 spin_lock_irqsave(&client->device->card->lock, flags); 780 spin_lock_irqsave(&client->device->card->lock, flags);
762 list_del(&client->link); 781 list_del(&client->link);
@@ -771,13 +790,16 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
771static unsigned int fw_device_op_poll(struct file *file, poll_table * pt) 790static unsigned int fw_device_op_poll(struct file *file, poll_table * pt)
772{ 791{
773 struct client *client = file->private_data; 792 struct client *client = file->private_data;
793 unsigned int mask = 0;
774 794
775 poll_wait(file, &client->wait, pt); 795 poll_wait(file, &client->wait, pt);
776 796
797 if (fw_device_is_shutdown(client->device))
798 mask |= POLLHUP | POLLERR;
777 if (!list_empty(&client->event_list)) 799 if (!list_empty(&client->event_list))
778 return POLLIN | POLLRDNORM; 800 mask |= POLLIN | POLLRDNORM;
779 else 801
780 return 0; 802 return mask;
781} 803}
782 804
783const struct file_operations fw_device_ops = { 805const struct file_operations fw_device_ops = {