aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/fw-device-cdev.c80
-rw-r--r--drivers/firewire/fw-device.c1
-rw-r--r--drivers/firewire/fw-device.h7
3 files changed, 59 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 = {
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index 4ade867db888..4877cdbc58cc 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -453,6 +453,7 @@ static void fw_device_shutdown(struct work_struct *work)
453 idr_remove(&fw_device_idr, minor); 453 idr_remove(&fw_device_idr, minor);
454 up_write(&fw_bus_type.subsys.rwsem); 454 up_write(&fw_bus_type.subsys.rwsem);
455 455
456 fw_device_cdev_remove(device);
456 device_remove_file(&device->device, &config_rom_attribute); 457 device_remove_file(&device->device, &config_rom_attribute);
457 device_for_each_child(&device->device, NULL, shutdown_unit); 458 device_for_each_child(&device->device, NULL, shutdown_unit);
458 device_unregister(&device->device); 459 device_unregister(&device->device);
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
index 1a3655bea335..ba0e2463e4a7 100644
--- a/drivers/firewire/fw-device.h
+++ b/drivers/firewire/fw-device.h
@@ -53,11 +53,18 @@ fw_device(struct device *dev)
53 return container_of(dev, struct fw_device, device); 53 return container_of(dev, struct fw_device, device);
54} 54}
55 55
56static inline int
57fw_device_is_shutdown(struct fw_device *device)
58{
59 return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN;
60}
61
56struct fw_device *fw_device_get(struct fw_device *device); 62struct fw_device *fw_device_get(struct fw_device *device);
57void fw_device_put(struct fw_device *device); 63void fw_device_put(struct fw_device *device);
58int fw_device_enable_phys_dma(struct fw_device *device); 64int fw_device_enable_phys_dma(struct fw_device *device);
59 65
60void fw_device_cdev_update(struct fw_device *device); 66void fw_device_cdev_update(struct fw_device *device);
67void fw_device_cdev_remove(struct fw_device *device);
61 68
62struct fw_device *fw_device_from_devt(dev_t devt); 69struct fw_device *fw_device_from_devt(dev_t devt);
63extern int fw_cdev_major; 70extern int fw_cdev_major;