Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97bd9efa authored by Kristian Høgsberg's avatar Kristian Høgsberg Committed by Stefan Richter
Browse files

firewire: Add a bus reset event type for fw-device-cdev.

parent 1da0c93b
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -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);

+14 −3
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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;