From: =?utf-8?q?Kristian_H=C3=B8gsberg?= Subject: [PATCH 6/21] firewire: Add a bus reset event type for fw-device-cdev. Date: Wed, 7 Mar 2007 12:12:41 -0500 Signed-off-by: Kristian Høgsberg Signed-off-by: Stefan Richter --- drivers/firewire/fw-device-cdev.c | 56 +++++++++++++++++++++++++++++++++++++ drivers/firewire/fw-device-cdev.h | 17 +++++++++-- drivers/firewire/fw-device.c | 2 + drivers/firewire/fw-device.h | 3 ++ 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/drivers/firewire/fw-device-cdev.c b/drivers/firewire/fw-device-cdev.c index 33fe576..9f3c96c 100644 --- a/drivers/firewire/fw-device-cdev.c +++ b/drivers/firewire/fw-device-cdev.c @@ -50,6 +50,11 @@ struct event { struct list_head link; }; +struct bus_reset { + struct event event; + struct fw_cdev_event_bus_reset reset; +}; + struct response { struct event event; struct fw_transaction transaction; @@ -75,6 +80,8 @@ struct client { struct fw_iso_context *iso_context; struct fw_iso_buffer buffer; unsigned long vm_start; + + struct list_head link; }; static inline void __user * @@ -93,6 +100,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file) { struct fw_device *device; struct client *client; + unsigned long flags; device = container_of(inode->i_cdev, struct fw_device, cdev); @@ -110,6 +118,10 @@ static int fw_device_op_open(struct inode *inode, struct file *file) file->private_data = client; + spin_lock_irqsave(&device->card->lock, flags); + list_add_tail(&client->link, &device->client_list); + spin_unlock_irqrestore(&device->card->lock, flags); + return 0; } @@ -177,6 +189,45 @@ fw_device_op_read(struct file *file, return dequeue_event(client, buffer, count); } +static void +queue_bus_reset_event(struct client *client) +{ + struct bus_reset *bus_reset; + struct fw_device *device = client->device; + struct fw_card *card = device->card; + + bus_reset = kzalloc(sizeof *bus_reset, GFP_ATOMIC); + if (bus_reset == NULL) { + fw_notify("Out of memory when allocating bus reset event\n"); + return; + } + + bus_reset->reset.type = FW_CDEV_EVENT_BUS_RESET; + bus_reset->reset.node_id = device->node_id; + bus_reset->reset.local_node_id = card->local_node->node_id; + bus_reset->reset.bm_node_id = 0; /* FIXME: We don't track the BM. */ + bus_reset->reset.irm_node_id = card->irm_node->node_id; + bus_reset->reset.root_node_id = card->root_node->node_id; + bus_reset->reset.generation = card->generation; + + queue_event(client, &bus_reset->event, + &bus_reset->reset, sizeof bus_reset->reset, NULL, 0); +} + +void fw_device_cdev_update(struct fw_device *device) +{ + struct fw_card *card = device->card; + struct client *c; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + + list_for_each_entry(c, &device->client_list, link) + queue_bus_reset_event(c); + + spin_unlock_irqrestore(&card->lock, flags); +} + static int ioctl_config_rom(struct client *client, void __user *arg) { struct fw_cdev_get_config_rom rom; @@ -633,6 +684,7 @@ static int fw_device_op_release(struct inode *inode, struct file *file) struct client *client = file->private_data; struct address_handler *h, *next; struct request *r, *next_r; + unsigned long flags; if (client->buffer.pages) fw_iso_buffer_destroy(&client->buffer, client->device->card); @@ -657,6 +709,10 @@ static int fw_device_op_release(struct inode *inode, struct file *file) while (!list_empty(&client->event_list)) dequeue_event(client, NULL, 0); + spin_lock_irqsave(&client->device->card->lock, flags); + list_del(&client->link); + spin_unlock_irqrestore(&client->device->card->lock, flags); + fw_device_put(client->device); kfree(client); diff --git a/drivers/firewire/fw-device-cdev.h b/drivers/firewire/fw-device-cdev.h index 739f54f..4f94471 100644 --- a/drivers/firewire/fw-device-cdev.h +++ b/drivers/firewire/fw-device-cdev.h @@ -58,15 +58,26 @@ #define SCODE_1600 0x4 #define SCODE_3200 0x5 -#define FW_CDEV_EVENT_RESPONSE 0x00 -#define FW_CDEV_EVENT_REQUEST 0x01 -#define FW_CDEV_EVENT_ISO_INTERRUPT 0x02 +#define FW_CDEV_EVENT_BUS_RESET 0x00 +#define FW_CDEV_EVENT_RESPONSE 0x01 +#define FW_CDEV_EVENT_REQUEST 0x02 +#define FW_CDEV_EVENT_ISO_INTERRUPT 0x03 /* The 'closure' fields are for user space to use. Data passed in the * 'closure' field for a request will be returned in the corresponding * event. It's a 64-bit type so that it's a fixed size type big * enough to hold a pointer on all platforms. */ +struct fw_cdev_event_bus_reset { + __u32 type; + __u32 node_id; + __u32 local_node_id; + __u32 bm_node_id; + __u32 irm_node_id; + __u32 root_node_id; + __u32 generation; +}; + struct fw_cdev_event_response { __u32 type; __u32 rcode; diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 5599265..ccc05e5 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -535,6 +535,7 @@ static void fw_device_update(struct work_struct *work) struct fw_device *device = container_of(work, struct fw_device, work.work); + fw_device_cdev_update(device); device_for_each_child(&device->device, NULL, update_unit); } @@ -564,6 +565,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) device->node = fw_node_get(node); device->node_id = node->node_id; device->generation = card->generation; + INIT_LIST_HEAD(&device->client_list); /* Set the node data to point back to this device so * FW_NODE_UPDATED callbacks can update the node_id diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index 402a785..4f731c2 100644 --- a/drivers/firewire/fw-device.h +++ b/drivers/firewire/fw-device.h @@ -40,6 +40,7 @@ struct fw_device { struct fw_card *card; struct device device; struct cdev cdev; + struct list_head client_list; __be32 *config_rom; size_t config_rom_length; int config_rom_retries; @@ -56,6 +57,8 @@ struct fw_device *fw_device_get(struct fw_device *device); void fw_device_put(struct fw_device *device); int fw_device_enable_phys_dma(struct fw_device *device); +void fw_device_cdev_update(struct fw_device *device); + struct fw_unit { struct device device; u32 *directory;