mirror of
https://github.com/adulau/aha.git
synced 2024-12-27 19:26:25 +00:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: firewire: core: use more outbound tlabels firewire: core: don't update Broadcast_Channel if RFC 2734 conditions aren't met firewire: core: prepare for non-core children of card devices firewire: core: include linux/uaccess.h instead of asm/uaccess.h firewire: add parent-of-unit accessor firewire: rename source files firewire: reorganize header files firewire: clean up includes firewire: ohci: access bus_seconds atomically firewire: also use vendor ID in root directory for driver matches firewire: share device ID table type with ieee1394 firewire: core: add sysfs attribute for easier udev rules firewire: core: check for missing struct update at build time, not run time firewire: core: improve check for local node
This commit is contained in:
commit
f83b1e616f
15 changed files with 903 additions and 830 deletions
|
@ -2,10 +2,10 @@
|
|||
# Makefile for the Linux IEEE 1394 implementation
|
||||
#
|
||||
|
||||
firewire-core-y += fw-card.o fw-topology.o fw-transaction.o fw-iso.o \
|
||||
fw-device.o fw-cdev.o
|
||||
firewire-ohci-y += fw-ohci.o
|
||||
firewire-sbp2-y += fw-sbp2.o
|
||||
firewire-core-y += core-card.o core-cdev.o core-device.o \
|
||||
core-iso.o core-topology.o core-transaction.o
|
||||
firewire-ohci-y += ohci.o
|
||||
firewire-sbp2-y += sbp2.o
|
||||
|
||||
obj-$(CONFIG_FIREWIRE) += firewire-core.o
|
||||
obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o
|
||||
|
|
|
@ -16,18 +16,27 @@
|
|||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/crc-itu-t.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firewire.h>
|
||||
#include <linux/firewire-constants.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "fw-transaction.h"
|
||||
#include "fw-topology.h"
|
||||
#include "fw-device.h"
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
int fw_compute_block_crc(u32 *block)
|
||||
{
|
||||
|
@ -181,12 +190,6 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc)
|
|||
mutex_unlock(&card_mutex);
|
||||
}
|
||||
|
||||
static int set_broadcast_channel(struct device *dev, void *data)
|
||||
{
|
||||
fw_device_set_broadcast_channel(fw_device(dev), (long)data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void allocate_broadcast_channel(struct fw_card *card, int generation)
|
||||
{
|
||||
int channel, bandwidth = 0;
|
||||
|
@ -196,7 +199,7 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)
|
|||
if (channel == 31) {
|
||||
card->broadcast_channel_allocated = true;
|
||||
device_for_each_child(card->device, (void *)(long)generation,
|
||||
set_broadcast_channel);
|
||||
fw_device_set_broadcast_channel);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firewire.h>
|
||||
#include <linux/firewire-cdev.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
@ -34,16 +35,14 @@
|
|||
#include <linux/preempt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "fw-device.h"
|
||||
#include "fw-topology.h"
|
||||
#include "fw-transaction.h"
|
||||
#include "core.h"
|
||||
|
||||
struct client {
|
||||
u32 version;
|
||||
|
@ -739,15 +738,11 @@ static void release_descriptor(struct client *client,
|
|||
static int ioctl_add_descriptor(struct client *client, void *buffer)
|
||||
{
|
||||
struct fw_cdev_add_descriptor *request = buffer;
|
||||
struct fw_card *card = client->device->card;
|
||||
struct descriptor_resource *r;
|
||||
int ret;
|
||||
|
||||
/* Access policy: Allow this ioctl only on local nodes' device files. */
|
||||
spin_lock_irq(&card->lock);
|
||||
ret = client->device->node_id != card->local_node->node_id;
|
||||
spin_unlock_irq(&card->lock);
|
||||
if (ret)
|
||||
if (!client->device->is_local)
|
||||
return -ENOSYS;
|
||||
|
||||
if (request->length > 256)
|
|
@ -22,10 +22,14 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firewire.h>
|
||||
#include <linux/firewire-constants.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/semaphore.h>
|
||||
|
@ -33,11 +37,11 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include "fw-device.h"
|
||||
#include "fw-topology.h"
|
||||
#include "fw-transaction.h"
|
||||
#include "core.h"
|
||||
|
||||
void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p)
|
||||
{
|
||||
|
@ -55,9 +59,10 @@ int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value)
|
|||
}
|
||||
EXPORT_SYMBOL(fw_csr_iterator_next);
|
||||
|
||||
static int is_fw_unit(struct device *dev);
|
||||
static bool is_fw_unit(struct device *dev);
|
||||
|
||||
static int match_unit_directory(u32 * directory, const struct fw_device_id *id)
|
||||
static int match_unit_directory(u32 *directory, u32 match_flags,
|
||||
const struct ieee1394_device_id *id)
|
||||
{
|
||||
struct fw_csr_iterator ci;
|
||||
int key, value, match;
|
||||
|
@ -65,31 +70,42 @@ static int match_unit_directory(u32 * directory, const struct fw_device_id *id)
|
|||
match = 0;
|
||||
fw_csr_iterator_init(&ci, directory);
|
||||
while (fw_csr_iterator_next(&ci, &key, &value)) {
|
||||
if (key == CSR_VENDOR && value == id->vendor)
|
||||
match |= FW_MATCH_VENDOR;
|
||||
if (key == CSR_MODEL && value == id->model)
|
||||
match |= FW_MATCH_MODEL;
|
||||
if (key == CSR_VENDOR && value == id->vendor_id)
|
||||
match |= IEEE1394_MATCH_VENDOR_ID;
|
||||
if (key == CSR_MODEL && value == id->model_id)
|
||||
match |= IEEE1394_MATCH_MODEL_ID;
|
||||
if (key == CSR_SPECIFIER_ID && value == id->specifier_id)
|
||||
match |= FW_MATCH_SPECIFIER_ID;
|
||||
match |= IEEE1394_MATCH_SPECIFIER_ID;
|
||||
if (key == CSR_VERSION && value == id->version)
|
||||
match |= FW_MATCH_VERSION;
|
||||
match |= IEEE1394_MATCH_VERSION;
|
||||
}
|
||||
|
||||
return (match & id->match_flags) == id->match_flags;
|
||||
return (match & match_flags) == match_flags;
|
||||
}
|
||||
|
||||
static int fw_unit_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct fw_unit *unit = fw_unit(dev);
|
||||
struct fw_driver *driver = fw_driver(drv);
|
||||
int i;
|
||||
struct fw_device *device;
|
||||
const struct ieee1394_device_id *id;
|
||||
|
||||
/* We only allow binding to fw_units. */
|
||||
if (!is_fw_unit(dev))
|
||||
return 0;
|
||||
|
||||
for (i = 0; driver->id_table[i].match_flags != 0; i++) {
|
||||
if (match_unit_directory(unit->directory, &driver->id_table[i]))
|
||||
device = fw_parent_device(unit);
|
||||
id = container_of(drv, struct fw_driver, driver)->id_table;
|
||||
|
||||
for (; id->match_flags != 0; id++) {
|
||||
if (match_unit_directory(unit->directory, id->match_flags, id))
|
||||
return 1;
|
||||
|
||||
/* Also check vendor ID in the root directory. */
|
||||
if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
|
||||
match_unit_directory(&device->config_rom[5],
|
||||
IEEE1394_MATCH_VENDOR_ID, id) &&
|
||||
match_unit_directory(unit->directory, id->match_flags
|
||||
& ~IEEE1394_MATCH_VENDOR_ID, id))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -98,7 +114,7 @@ static int fw_unit_match(struct device *dev, struct device_driver *drv)
|
|||
|
||||
static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
|
||||
{
|
||||
struct fw_device *device = fw_device(unit->device.parent);
|
||||
struct fw_device *device = fw_parent_device(unit);
|
||||
struct fw_csr_iterator ci;
|
||||
|
||||
int key, value;
|
||||
|
@ -292,8 +308,7 @@ static void init_fw_attribute_group(struct device *dev,
|
|||
group->attrs[j++] = &attr->attr;
|
||||
}
|
||||
|
||||
BUG_ON(j >= ARRAY_SIZE(group->attrs));
|
||||
group->attrs[j++] = NULL;
|
||||
group->attrs[j] = NULL;
|
||||
group->groups[0] = &group->group;
|
||||
group->groups[1] = NULL;
|
||||
group->group.attrs = group->attrs;
|
||||
|
@ -356,9 +371,56 @@ static ssize_t guid_show(struct device *dev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int units_sprintf(char *buf, u32 *directory)
|
||||
{
|
||||
struct fw_csr_iterator ci;
|
||||
int key, value;
|
||||
int specifier_id = 0;
|
||||
int version = 0;
|
||||
|
||||
fw_csr_iterator_init(&ci, directory);
|
||||
while (fw_csr_iterator_next(&ci, &key, &value)) {
|
||||
switch (key) {
|
||||
case CSR_SPECIFIER_ID:
|
||||
specifier_id = value;
|
||||
break;
|
||||
case CSR_VERSION:
|
||||
version = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return sprintf(buf, "0x%06x:0x%06x ", specifier_id, version);
|
||||
}
|
||||
|
||||
static ssize_t units_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct fw_device *device = fw_device(dev);
|
||||
struct fw_csr_iterator ci;
|
||||
int key, value, i = 0;
|
||||
|
||||
down_read(&fw_device_rwsem);
|
||||
fw_csr_iterator_init(&ci, &device->config_rom[5]);
|
||||
while (fw_csr_iterator_next(&ci, &key, &value)) {
|
||||
if (key != (CSR_UNIT | CSR_DIRECTORY))
|
||||
continue;
|
||||
i += units_sprintf(&buf[i], ci.p + value - 1);
|
||||
if (i >= PAGE_SIZE - (8 + 1 + 8 + 1))
|
||||
break;
|
||||
}
|
||||
up_read(&fw_device_rwsem);
|
||||
|
||||
if (i)
|
||||
buf[i - 1] = '\n';
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static struct device_attribute fw_device_attributes[] = {
|
||||
__ATTR_RO(config_rom),
|
||||
__ATTR_RO(guid),
|
||||
__ATTR_RO(units),
|
||||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
|
@ -518,7 +580,9 @@ static int read_bus_info_block(struct fw_device *device, int generation)
|
|||
|
||||
kfree(old_rom);
|
||||
ret = 0;
|
||||
device->cmc = rom[2] >> 30 & 1;
|
||||
device->max_rec = rom[2] >> 12 & 0xf;
|
||||
device->cmc = rom[2] >> 30 & 1;
|
||||
device->irmc = rom[2] >> 31 & 1;
|
||||
out:
|
||||
kfree(rom);
|
||||
|
||||
|
@ -537,7 +601,7 @@ static struct device_type fw_unit_type = {
|
|||
.release = fw_unit_release,
|
||||
};
|
||||
|
||||
static int is_fw_unit(struct device *dev)
|
||||
static bool is_fw_unit(struct device *dev)
|
||||
{
|
||||
return dev->type == &fw_unit_type;
|
||||
}
|
||||
|
@ -570,9 +634,13 @@ static void create_units(struct fw_device *device)
|
|||
unit->device.parent = &device->device;
|
||||
dev_set_name(&unit->device, "%s.%d", dev_name(&device->device), i++);
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(unit->attribute_group.attrs) <
|
||||
ARRAY_SIZE(fw_unit_attributes) +
|
||||
ARRAY_SIZE(config_rom_attributes));
|
||||
init_fw_attribute_group(&unit->device,
|
||||
fw_unit_attributes,
|
||||
&unit->attribute_group);
|
||||
|
||||
if (device_register(&unit->device) < 0)
|
||||
goto skip_unit;
|
||||
|
||||
|
@ -683,6 +751,11 @@ static struct device_type fw_device_type = {
|
|||
.release = fw_device_release,
|
||||
};
|
||||
|
||||
static bool is_fw_device(struct device *dev)
|
||||
{
|
||||
return dev->type == &fw_device_type;
|
||||
}
|
||||
|
||||
static int update_unit(struct device *dev, void *data)
|
||||
{
|
||||
struct fw_unit *unit = fw_unit(dev);
|
||||
|
@ -719,6 +792,9 @@ static int lookup_existing_device(struct device *dev, void *data)
|
|||
struct fw_card *card = new->card;
|
||||
int match = 0;
|
||||
|
||||
if (!is_fw_device(dev))
|
||||
return 0;
|
||||
|
||||
down_read(&fw_device_rwsem); /* serialize config_rom access */
|
||||
spin_lock_irq(&card->lock); /* serialize node access */
|
||||
|
||||
|
@ -758,7 +834,7 @@ static int lookup_existing_device(struct device *dev, void *data)
|
|||
|
||||
enum { BC_UNKNOWN = 0, BC_UNIMPLEMENTED, BC_IMPLEMENTED, };
|
||||
|
||||
void fw_device_set_broadcast_channel(struct fw_device *device, int generation)
|
||||
static void set_broadcast_channel(struct fw_device *device, int generation)
|
||||
{
|
||||
struct fw_card *card = device->card;
|
||||
__be32 data;
|
||||
|
@ -767,6 +843,20 @@ void fw_device_set_broadcast_channel(struct fw_device *device, int generation)
|
|||
if (!card->broadcast_channel_allocated)
|
||||
return;
|
||||
|
||||
/*
|
||||
* The Broadcast_Channel Valid bit is required by nodes which want to
|
||||
* transmit on this channel. Such transmissions are practically
|
||||
* exclusive to IP over 1394 (RFC 2734). IP capable nodes are required
|
||||
* to be IRM capable and have a max_rec of 8 or more. We use this fact
|
||||
* to narrow down to which nodes we send Broadcast_Channel updates.
|
||||
*/
|
||||
if (!device->irmc || device->max_rec < 8)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Some 1394-1995 nodes crash if this 1394a-2000 register is written.
|
||||
* Perform a read test first.
|
||||
*/
|
||||
if (device->bc_implemented == BC_UNKNOWN) {
|
||||
rcode = fw_run_transaction(card, TCODE_READ_QUADLET_REQUEST,
|
||||
device->node_id, generation, device->max_speed,
|
||||
|
@ -794,6 +884,14 @@ void fw_device_set_broadcast_channel(struct fw_device *device, int generation)
|
|||
}
|
||||
}
|
||||
|
||||
int fw_device_set_broadcast_channel(struct device *dev, void *gen)
|
||||
{
|
||||
if (is_fw_device(dev))
|
||||
set_broadcast_channel(fw_device(dev), (long)gen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fw_device_init(struct work_struct *work)
|
||||
{
|
||||
struct fw_device *device =
|
||||
|
@ -849,9 +947,13 @@ static void fw_device_init(struct work_struct *work)
|
|||
device->device.devt = MKDEV(fw_cdev_major, minor);
|
||||
dev_set_name(&device->device, "fw%d", minor);
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(device->attribute_group.attrs) <
|
||||
ARRAY_SIZE(fw_device_attributes) +
|
||||
ARRAY_SIZE(config_rom_attributes));
|
||||
init_fw_attribute_group(&device->device,
|
||||
fw_device_attributes,
|
||||
&device->attribute_group);
|
||||
|
||||
if (device_add(&device->device)) {
|
||||
fw_error("Failed to add device.\n");
|
||||
goto error_with_cdev;
|
||||
|
@ -888,7 +990,7 @@ static void fw_device_init(struct work_struct *work)
|
|||
1 << device->max_speed);
|
||||
device->config_rom_retries = 0;
|
||||
|
||||
fw_device_set_broadcast_channel(device, device->generation);
|
||||
set_broadcast_channel(device, device->generation);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -993,6 +1095,9 @@ static void fw_device_refresh(struct work_struct *work)
|
|||
|
||||
create_units(device);
|
||||
|
||||
/* Userspace may want to re-read attributes. */
|
||||
kobject_uevent(&device->device.kobj, KOBJ_CHANGE);
|
||||
|
||||
if (atomic_cmpxchg(&device->state,
|
||||
FW_DEVICE_INITIALIZING,
|
||||
FW_DEVICE_RUNNING) == FW_DEVICE_GONE)
|
||||
|
@ -1042,6 +1147,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;
|
||||
device->is_local = node == card->local_node;
|
||||
mutex_init(&device->client_list_mutex);
|
||||
INIT_LIST_HEAD(&device->client_list);
|
||||
|
||||
|
@ -1075,7 +1181,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
|
|||
FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
|
||||
PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
|
||||
schedule_delayed_work(&device->work,
|
||||
node == card->local_node ? 0 : INITIAL_DELAY);
|
||||
device->is_local ? 0 : INITIAL_DELAY);
|
||||
}
|
||||
break;
|
||||
|
|
@ -22,14 +22,16 @@
|
|||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firewire.h>
|
||||
#include <linux/firewire-constants.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "fw-topology.h"
|
||||
#include "fw-transaction.h"
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/*
|
||||
* Isochronous DMA context management
|
|
@ -18,13 +18,22 @@
|
|||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/errno.h>
|
||||
#include <asm/bug.h>
|
||||
#include <linux/firewire.h>
|
||||
#include <linux/firewire-constants.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/system.h>
|
||||
#include "fw-transaction.h"
|
||||
#include "fw-topology.h"
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#define SELF_ID_PHY_ID(q) (((q) >> 24) & 0x3f)
|
||||
#define SELF_ID_EXTENDED(q) (((q) >> 23) & 0x01)
|
||||
|
@ -37,6 +46,11 @@
|
|||
|
||||
#define SELF_ID_EXT_SEQUENCE(q) (((q) >> 20) & 0x07)
|
||||
|
||||
#define SELFID_PORT_CHILD 0x3
|
||||
#define SELFID_PORT_PARENT 0x2
|
||||
#define SELFID_PORT_NCONN 0x1
|
||||
#define SELFID_PORT_NONE 0x0
|
||||
|
||||
static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count)
|
||||
{
|
||||
u32 q;
|
|
@ -18,24 +18,28 @@
|
|||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firewire.h>
|
||||
#include <linux/firewire-constants.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "fw-transaction.h"
|
||||
#include "fw-topology.h"
|
||||
#include "fw-device.h"
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#define HEADER_PRI(pri) ((pri) << 0)
|
||||
#define HEADER_TCODE(tcode) ((tcode) << 4)
|
||||
|
@ -60,6 +64,10 @@
|
|||
#define HEADER_DESTINATION_IS_BROADCAST(q) \
|
||||
(((q) & HEADER_DESTINATION(0x3f)) == HEADER_DESTINATION(0x3f))
|
||||
|
||||
#define PHY_PACKET_CONFIG 0x0
|
||||
#define PHY_PACKET_LINK_ON 0x1
|
||||
#define PHY_PACKET_SELF_ID 0x2
|
||||
|
||||
#define PHY_CONFIG_GAP_COUNT(gap_count) (((gap_count) << 16) | (1 << 22))
|
||||
#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))
|
||||
#define PHY_IDENTIFIER(id) ((id) << 30)
|
||||
|
@ -74,7 +82,7 @@ static int close_transaction(struct fw_transaction *transaction,
|
|||
list_for_each_entry(t, &card->transaction_list, link) {
|
||||
if (t == transaction) {
|
||||
list_del(&t->link);
|
||||
card->tlabel_mask &= ~(1 << t->tlabel);
|
||||
card->tlabel_mask &= ~(1ULL << t->tlabel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -280,14 +288,14 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
|
|||
spin_lock_irqsave(&card->lock, flags);
|
||||
|
||||
tlabel = card->current_tlabel;
|
||||
if (card->tlabel_mask & (1 << tlabel)) {
|
||||
if (card->tlabel_mask & (1ULL << tlabel)) {
|
||||
spin_unlock_irqrestore(&card->lock, flags);
|
||||
callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
|
||||
return;
|
||||
}
|
||||
|
||||
card->current_tlabel = (card->current_tlabel + 1) & 0x1f;
|
||||
card->tlabel_mask |= (1 << tlabel);
|
||||
card->current_tlabel = (card->current_tlabel + 1) & 0x3f;
|
||||
card->tlabel_mask |= (1ULL << tlabel);
|
||||
|
||||
t->node_id = destination_id;
|
||||
t->tlabel = tlabel;
|
293
drivers/firewire/core.h
Normal file
293
drivers/firewire/core.h
Normal file
|
@ -0,0 +1,293 @@
|
|||
#ifndef _FIREWIRE_CORE_H
|
||||
#define _FIREWIRE_CORE_H
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
|
||||
struct device;
|
||||
struct fw_card;
|
||||
struct fw_device;
|
||||
struct fw_iso_buffer;
|
||||
struct fw_iso_context;
|
||||
struct fw_iso_packet;
|
||||
struct fw_node;
|
||||
struct fw_packet;
|
||||
|
||||
|
||||
/* -card */
|
||||
|
||||
/* bitfields within the PHY registers */
|
||||
#define PHY_LINK_ACTIVE 0x80
|
||||
#define PHY_CONTENDER 0x40
|
||||
#define PHY_BUS_RESET 0x40
|
||||
#define PHY_BUS_SHORT_RESET 0x40
|
||||
|
||||
#define BANDWIDTH_AVAILABLE_INITIAL 4915
|
||||
#define BROADCAST_CHANNEL_INITIAL (1 << 31 | 31)
|
||||
#define BROADCAST_CHANNEL_VALID (1 << 30)
|
||||
|
||||
struct fw_card_driver {
|
||||
/*
|
||||
* Enable the given card with the given initial config rom.
|
||||
* This function is expected to activate the card, and either
|
||||
* enable the PHY or set the link_on bit and initiate a bus
|
||||
* reset.
|
||||
*/
|
||||
int (*enable)(struct fw_card *card, u32 *config_rom, size_t length);
|
||||
|
||||
int (*update_phy_reg)(struct fw_card *card, int address,
|
||||
int clear_bits, int set_bits);
|
||||
|
||||
/*
|
||||
* Update the config rom for an enabled card. This function
|
||||
* should change the config rom that is presented on the bus
|
||||
* an initiate a bus reset.
|
||||
*/
|
||||
int (*set_config_rom)(struct fw_card *card,
|
||||
u32 *config_rom, size_t length);
|
||||
|
||||
void (*send_request)(struct fw_card *card, struct fw_packet *packet);
|
||||
void (*send_response)(struct fw_card *card, struct fw_packet *packet);
|
||||
/* Calling cancel is valid once a packet has been submitted. */
|
||||
int (*cancel_packet)(struct fw_card *card, struct fw_packet *packet);
|
||||
|
||||
/*
|
||||
* Allow the specified node ID to do direct DMA out and in of
|
||||
* host memory. The card will disable this for all node when
|
||||
* a bus reset happens, so driver need to reenable this after
|
||||
* bus reset. Returns 0 on success, -ENODEV if the card
|
||||
* doesn't support this, -ESTALE if the generation doesn't
|
||||
* match.
|
||||
*/
|
||||
int (*enable_phys_dma)(struct fw_card *card,
|
||||
int node_id, int generation);
|
||||
|
||||
u64 (*get_bus_time)(struct fw_card *card);
|
||||
|
||||
struct fw_iso_context *
|
||||
(*allocate_iso_context)(struct fw_card *card,
|
||||
int type, int channel, size_t header_size);
|
||||
void (*free_iso_context)(struct fw_iso_context *ctx);
|
||||
|
||||
int (*start_iso)(struct fw_iso_context *ctx,
|
||||
s32 cycle, u32 sync, u32 tags);
|
||||
|
||||
int (*queue_iso)(struct fw_iso_context *ctx,
|
||||
struct fw_iso_packet *packet,
|
||||
struct fw_iso_buffer *buffer,
|
||||
unsigned long payload);
|
||||
|
||||
int (*stop_iso)(struct fw_iso_context *ctx);
|
||||
};
|
||||
|
||||
void fw_card_initialize(struct fw_card *card,
|
||||
const struct fw_card_driver *driver, struct device *device);
|
||||
int fw_card_add(struct fw_card *card,
|
||||
u32 max_receive, u32 link_speed, u64 guid);
|
||||
void fw_core_remove_card(struct fw_card *card);
|
||||
int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
|
||||
int fw_compute_block_crc(u32 *block);
|
||||
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
|
||||
|
||||
struct fw_descriptor {
|
||||
struct list_head link;
|
||||
size_t length;
|
||||
u32 immediate;
|
||||
u32 key;
|
||||
const u32 *data;
|
||||
};
|
||||
|
||||
int fw_core_add_descriptor(struct fw_descriptor *desc);
|
||||
void fw_core_remove_descriptor(struct fw_descriptor *desc);
|
||||
|
||||
|
||||
/* -cdev */
|
||||
|
||||
extern const struct file_operations fw_device_ops;
|
||||
|
||||
void fw_device_cdev_update(struct fw_device *device);
|
||||
void fw_device_cdev_remove(struct fw_device *device);
|
||||
|
||||
|
||||
/* -device */
|
||||
|
||||
extern struct rw_semaphore fw_device_rwsem;
|
||||
extern struct idr fw_device_idr;
|
||||
extern int fw_cdev_major;
|
||||
|
||||
struct fw_device *fw_device_get_by_devt(dev_t devt);
|
||||
int fw_device_set_broadcast_channel(struct device *dev, void *gen);
|
||||
void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
|
||||
|
||||
|
||||
/* -iso */
|
||||
|
||||
/*
|
||||
* The iso packet format allows for an immediate header/payload part
|
||||
* stored in 'header' immediately after the packet info plus an
|
||||
* indirect payload part that is pointer to by the 'payload' field.
|
||||
* Applications can use one or the other or both to implement simple
|
||||
* low-bandwidth streaming (e.g. audio) or more advanced
|
||||
* scatter-gather streaming (e.g. assembling video frame automatically).
|
||||
*/
|
||||
struct fw_iso_packet {
|
||||
u16 payload_length; /* Length of indirect payload. */
|
||||
u32 interrupt:1; /* Generate interrupt on this packet */
|
||||
u32 skip:1; /* Set to not send packet at all. */
|
||||
u32 tag:2;
|
||||
u32 sy:4;
|
||||
u32 header_length:8; /* Length of immediate header. */
|
||||
u32 header[0];
|
||||
};
|
||||
|
||||
#define FW_ISO_CONTEXT_TRANSMIT 0
|
||||
#define FW_ISO_CONTEXT_RECEIVE 1
|
||||
|
||||
#define FW_ISO_CONTEXT_MATCH_TAG0 1
|
||||
#define FW_ISO_CONTEXT_MATCH_TAG1 2
|
||||
#define FW_ISO_CONTEXT_MATCH_TAG2 4
|
||||
#define FW_ISO_CONTEXT_MATCH_TAG3 8
|
||||
#define FW_ISO_CONTEXT_MATCH_ALL_TAGS 15
|
||||
|
||||
/*
|
||||
* An iso buffer is just a set of pages mapped for DMA in the
|
||||
* specified direction. Since the pages are to be used for DMA, they
|
||||
* are not mapped into the kernel virtual address space. We store the
|
||||
* DMA address in the page private. The helper function
|
||||
* fw_iso_buffer_map() will map the pages into a given vma.
|
||||
*/
|
||||
struct fw_iso_buffer {
|
||||
enum dma_data_direction direction;
|
||||
struct page **pages;
|
||||
int page_count;
|
||||
};
|
||||
|
||||
typedef void (*fw_iso_callback_t)(struct fw_iso_context *context,
|
||||
u32 cycle, size_t header_length,
|
||||
void *header, void *data);
|
||||
|
||||
struct fw_iso_context {
|
||||
struct fw_card *card;
|
||||
int type;
|
||||
int channel;
|
||||
int speed;
|
||||
size_t header_size;
|
||||
fw_iso_callback_t callback;
|
||||
void *callback_data;
|
||||
};
|
||||
|
||||
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
|
||||
int page_count, enum dma_data_direction direction);
|
||||
int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
|
||||
void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
|
||||
|
||||
struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
|
||||
int type, int channel, int speed, size_t header_size,
|
||||
fw_iso_callback_t callback, void *callback_data);
|
||||
int fw_iso_context_queue(struct fw_iso_context *ctx,
|
||||
struct fw_iso_packet *packet,
|
||||
struct fw_iso_buffer *buffer,
|
||||
unsigned long payload);
|
||||
int fw_iso_context_start(struct fw_iso_context *ctx,
|
||||
int cycle, int sync, int tags);
|
||||
int fw_iso_context_stop(struct fw_iso_context *ctx);
|
||||
void fw_iso_context_destroy(struct fw_iso_context *ctx);
|
||||
|
||||
void fw_iso_resource_manage(struct fw_card *card, int generation,
|
||||
u64 channels_mask, int *channel, int *bandwidth, bool allocate);
|
||||
|
||||
|
||||
/* -topology */
|
||||
|
||||
enum {
|
||||
FW_NODE_CREATED,
|
||||
FW_NODE_UPDATED,
|
||||
FW_NODE_DESTROYED,
|
||||
FW_NODE_LINK_ON,
|
||||
FW_NODE_LINK_OFF,
|
||||
FW_NODE_INITIATED_RESET,
|
||||
};
|
||||
|
||||
struct fw_node {
|
||||
u16 node_id;
|
||||
u8 color;
|
||||
u8 port_count;
|
||||
u8 link_on:1;
|
||||
u8 initiated_reset:1;
|
||||
u8 b_path:1;
|
||||
u8 phy_speed:2; /* As in the self ID packet. */
|
||||
u8 max_speed:2; /* Minimum of all phy-speeds on the path from the
|
||||
* local node to this node. */
|
||||
u8 max_depth:4; /* Maximum depth to any leaf node */
|
||||
u8 max_hops:4; /* Max hops in this sub tree */
|
||||
atomic_t ref_count;
|
||||
|
||||
/* For serializing node topology into a list. */
|
||||
struct list_head link;
|
||||
|
||||
/* Upper layer specific data. */
|
||||
void *data;
|
||||
|
||||
struct fw_node *ports[0];
|
||||
};
|
||||
|
||||
static inline struct fw_node *fw_node_get(struct fw_node *node)
|
||||
{
|
||||
atomic_inc(&node->ref_count);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static inline void fw_node_put(struct fw_node *node)
|
||||
{
|
||||
if (atomic_dec_and_test(&node->ref_count))
|
||||
kfree(node);
|
||||
}
|
||||
|
||||
void fw_core_handle_bus_reset(struct fw_card *card, int node_id,
|
||||
int generation, int self_id_count, u32 *self_ids);
|
||||
void fw_destroy_nodes(struct fw_card *card);
|
||||
|
||||
/*
|
||||
* Check whether new_generation is the immediate successor of old_generation.
|
||||
* Take counter roll-over at 255 (as per OHCI) into account.
|
||||
*/
|
||||
static inline bool is_next_generation(int new_generation, int old_generation)
|
||||
{
|
||||
return (new_generation & 0xff) == ((old_generation + 1) & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/* -transaction */
|
||||
|
||||
#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4)
|
||||
#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0)
|
||||
#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0)
|
||||
#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0)
|
||||
#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4)
|
||||
#define TCODE_HAS_RESPONSE_DATA(tcode) (((tcode) & 12) != 0)
|
||||
|
||||
#define LOCAL_BUS 0xffc0
|
||||
|
||||
void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
|
||||
void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
|
||||
void fw_fill_response(struct fw_packet *response, u32 *request_header,
|
||||
int rcode, void *payload, size_t length);
|
||||
void fw_flush_transactions(struct fw_card *card);
|
||||
void fw_send_phy_config(struct fw_card *card,
|
||||
int node_id, int generation, int gap_count);
|
||||
|
||||
static inline int fw_stream_packet_destination_id(int tag, int channel, int sy)
|
||||
{
|
||||
return tag << 14 | channel << 8 | sy;
|
||||
}
|
||||
|
||||
#endif /* _FIREWIRE_CORE_H */
|
|
@ -1,202 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2005-2006 Kristian Hoegsberg <krh@bitplanet.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __fw_device_h
|
||||
#define __fw_device_h
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
|
||||
enum fw_device_state {
|
||||
FW_DEVICE_INITIALIZING,
|
||||
FW_DEVICE_RUNNING,
|
||||
FW_DEVICE_GONE,
|
||||
FW_DEVICE_SHUTDOWN,
|
||||
};
|
||||
|
||||
struct fw_attribute_group {
|
||||
struct attribute_group *groups[2];
|
||||
struct attribute_group group;
|
||||
struct attribute *attrs[11];
|
||||
};
|
||||
|
||||
struct fw_node;
|
||||
struct fw_card;
|
||||
|
||||
/*
|
||||
* Note, fw_device.generation always has to be read before fw_device.node_id.
|
||||
* Use SMP memory barriers to ensure this. Otherwise requests will be sent
|
||||
* to an outdated node_id if the generation was updated in the meantime due
|
||||
* to a bus reset.
|
||||
*
|
||||
* Likewise, fw-core will take care to update .node_id before .generation so
|
||||
* that whenever fw_device.generation is current WRT the actual bus generation,
|
||||
* fw_device.node_id is guaranteed to be current too.
|
||||
*
|
||||
* The same applies to fw_device.card->node_id vs. fw_device.generation.
|
||||
*
|
||||
* fw_device.config_rom and fw_device.config_rom_length may be accessed during
|
||||
* the lifetime of any fw_unit belonging to the fw_device, before device_del()
|
||||
* was called on the last fw_unit. Alternatively, they may be accessed while
|
||||
* holding fw_device_rwsem.
|
||||
*/
|
||||
struct fw_device {
|
||||
atomic_t state;
|
||||
struct fw_node *node;
|
||||
int node_id;
|
||||
int generation;
|
||||
unsigned max_speed;
|
||||
struct fw_card *card;
|
||||
struct device device;
|
||||
|
||||
struct mutex client_list_mutex;
|
||||
struct list_head client_list;
|
||||
|
||||
u32 *config_rom;
|
||||
size_t config_rom_length;
|
||||
int config_rom_retries;
|
||||
unsigned cmc:1;
|
||||
unsigned bc_implemented:2;
|
||||
|
||||
struct delayed_work work;
|
||||
struct fw_attribute_group attribute_group;
|
||||
};
|
||||
|
||||
static inline struct fw_device *fw_device(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct fw_device, device);
|
||||
}
|
||||
|
||||
static inline int fw_device_is_shutdown(struct fw_device *device)
|
||||
{
|
||||
return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN;
|
||||
}
|
||||
|
||||
static inline struct fw_device *fw_device_get(struct fw_device *device)
|
||||
{
|
||||
get_device(&device->device);
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static inline void fw_device_put(struct fw_device *device)
|
||||
{
|
||||
put_device(&device->device);
|
||||
}
|
||||
|
||||
struct fw_device *fw_device_get_by_devt(dev_t devt);
|
||||
int fw_device_enable_phys_dma(struct fw_device *device);
|
||||
void fw_device_set_broadcast_channel(struct fw_device *device, int generation);
|
||||
|
||||
void fw_device_cdev_update(struct fw_device *device);
|
||||
void fw_device_cdev_remove(struct fw_device *device);
|
||||
|
||||
extern struct rw_semaphore fw_device_rwsem;
|
||||
extern struct idr fw_device_idr;
|
||||
extern int fw_cdev_major;
|
||||
|
||||
/*
|
||||
* fw_unit.directory must not be accessed after device_del(&fw_unit.device).
|
||||
*/
|
||||
struct fw_unit {
|
||||
struct device device;
|
||||
u32 *directory;
|
||||
struct fw_attribute_group attribute_group;
|
||||
};
|
||||
|
||||
static inline struct fw_unit *fw_unit(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct fw_unit, device);
|
||||
}
|
||||
|
||||
static inline struct fw_unit *fw_unit_get(struct fw_unit *unit)
|
||||
{
|
||||
get_device(&unit->device);
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
static inline void fw_unit_put(struct fw_unit *unit)
|
||||
{
|
||||
put_device(&unit->device);
|
||||
}
|
||||
|
||||
#define CSR_OFFSET 0x40
|
||||
#define CSR_LEAF 0x80
|
||||
#define CSR_DIRECTORY 0xc0
|
||||
|
||||
#define CSR_DESCRIPTOR 0x01
|
||||
#define CSR_VENDOR 0x03
|
||||
#define CSR_HARDWARE_VERSION 0x04
|
||||
#define CSR_NODE_CAPABILITIES 0x0c
|
||||
#define CSR_UNIT 0x11
|
||||
#define CSR_SPECIFIER_ID 0x12
|
||||
#define CSR_VERSION 0x13
|
||||
#define CSR_DEPENDENT_INFO 0x14
|
||||
#define CSR_MODEL 0x17
|
||||
#define CSR_INSTANCE 0x18
|
||||
#define CSR_DIRECTORY_ID 0x20
|
||||
|
||||
struct fw_csr_iterator {
|
||||
u32 *p;
|
||||
u32 *end;
|
||||
};
|
||||
|
||||
void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 *p);
|
||||
int fw_csr_iterator_next(struct fw_csr_iterator *ci,
|
||||
int *key, int *value);
|
||||
|
||||
#define FW_MATCH_VENDOR 0x0001
|
||||
#define FW_MATCH_MODEL 0x0002
|
||||
#define FW_MATCH_SPECIFIER_ID 0x0004
|
||||
#define FW_MATCH_VERSION 0x0008
|
||||
|
||||
struct fw_device_id {
|
||||
u32 match_flags;
|
||||
u32 vendor;
|
||||
u32 model;
|
||||
u32 specifier_id;
|
||||
u32 version;
|
||||
void *driver_data;
|
||||
};
|
||||
|
||||
struct fw_driver {
|
||||
struct device_driver driver;
|
||||
/* Called when the parent device sits through a bus reset. */
|
||||
void (*update) (struct fw_unit *unit);
|
||||
const struct fw_device_id *id_table;
|
||||
};
|
||||
|
||||
static inline struct fw_driver *fw_driver(struct device_driver *drv)
|
||||
{
|
||||
return container_of(drv, struct fw_driver, driver);
|
||||
}
|
||||
|
||||
extern const struct file_operations fw_device_ops;
|
||||
|
||||
#endif /* __fw_device_h */
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __fw_topology_h
|
||||
#define __fw_topology_h
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
|
||||
enum {
|
||||
FW_NODE_CREATED,
|
||||
FW_NODE_UPDATED,
|
||||
FW_NODE_DESTROYED,
|
||||
FW_NODE_LINK_ON,
|
||||
FW_NODE_LINK_OFF,
|
||||
FW_NODE_INITIATED_RESET,
|
||||
};
|
||||
|
||||
struct fw_node {
|
||||
u16 node_id;
|
||||
u8 color;
|
||||
u8 port_count;
|
||||
u8 link_on : 1;
|
||||
u8 initiated_reset : 1;
|
||||
u8 b_path : 1;
|
||||
u8 phy_speed : 2; /* As in the self ID packet. */
|
||||
u8 max_speed : 2; /* Minimum of all phy-speeds on the path from the
|
||||
* local node to this node. */
|
||||
u8 max_depth : 4; /* Maximum depth to any leaf node */
|
||||
u8 max_hops : 4; /* Max hops in this sub tree */
|
||||
atomic_t ref_count;
|
||||
|
||||
/* For serializing node topology into a list. */
|
||||
struct list_head link;
|
||||
|
||||
/* Upper layer specific data. */
|
||||
void *data;
|
||||
|
||||
struct fw_node *ports[0];
|
||||
};
|
||||
|
||||
static inline struct fw_node *fw_node_get(struct fw_node *node)
|
||||
{
|
||||
atomic_inc(&node->ref_count);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static inline void fw_node_put(struct fw_node *node)
|
||||
{
|
||||
if (atomic_dec_and_test(&node->ref_count))
|
||||
kfree(node);
|
||||
}
|
||||
|
||||
struct fw_card;
|
||||
void fw_destroy_nodes(struct fw_card *card);
|
||||
|
||||
int fw_compute_block_crc(u32 *block);
|
||||
|
||||
#endif /* __fw_topology_h */
|
|
@ -1,446 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __fw_transaction_h
|
||||
#define __fw_transaction_h
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/firewire-constants.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock_types.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4)
|
||||
#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0)
|
||||
#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0)
|
||||
#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0)
|
||||
#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4)
|
||||
#define TCODE_HAS_RESPONSE_DATA(tcode) (((tcode) & 12) != 0)
|
||||
|
||||
#define LOCAL_BUS 0xffc0
|
||||
|
||||
#define SELFID_PORT_CHILD 0x3
|
||||
#define SELFID_PORT_PARENT 0x2
|
||||
#define SELFID_PORT_NCONN 0x1
|
||||
#define SELFID_PORT_NONE 0x0
|
||||
|
||||
#define PHY_PACKET_CONFIG 0x0
|
||||
#define PHY_PACKET_LINK_ON 0x1
|
||||
#define PHY_PACKET_SELF_ID 0x2
|
||||
|
||||
/* Bit fields _within_ the PHY registers. */
|
||||
#define PHY_LINK_ACTIVE 0x80
|
||||
#define PHY_CONTENDER 0x40
|
||||
#define PHY_BUS_RESET 0x40
|
||||
#define PHY_BUS_SHORT_RESET 0x40
|
||||
|
||||
#define CSR_REGISTER_BASE 0xfffff0000000ULL
|
||||
|
||||
/* register offsets relative to CSR_REGISTER_BASE */
|
||||
#define CSR_STATE_CLEAR 0x0
|
||||
#define CSR_STATE_SET 0x4
|
||||
#define CSR_NODE_IDS 0x8
|
||||
#define CSR_RESET_START 0xc
|
||||
#define CSR_SPLIT_TIMEOUT_HI 0x18
|
||||
#define CSR_SPLIT_TIMEOUT_LO 0x1c
|
||||
#define CSR_CYCLE_TIME 0x200
|
||||
#define CSR_BUS_TIME 0x204
|
||||
#define CSR_BUSY_TIMEOUT 0x210
|
||||
#define CSR_BUS_MANAGER_ID 0x21c
|
||||
#define CSR_BANDWIDTH_AVAILABLE 0x220
|
||||
#define CSR_CHANNELS_AVAILABLE 0x224
|
||||
#define CSR_CHANNELS_AVAILABLE_HI 0x224
|
||||
#define CSR_CHANNELS_AVAILABLE_LO 0x228
|
||||
#define CSR_BROADCAST_CHANNEL 0x234
|
||||
#define CSR_CONFIG_ROM 0x400
|
||||
#define CSR_CONFIG_ROM_END 0x800
|
||||
#define CSR_FCP_COMMAND 0xB00
|
||||
#define CSR_FCP_RESPONSE 0xD00
|
||||
#define CSR_FCP_END 0xF00
|
||||
#define CSR_TOPOLOGY_MAP 0x1000
|
||||
#define CSR_TOPOLOGY_MAP_END 0x1400
|
||||
#define CSR_SPEED_MAP 0x2000
|
||||
#define CSR_SPEED_MAP_END 0x3000
|
||||
|
||||
#define BANDWIDTH_AVAILABLE_INITIAL 4915
|
||||
#define BROADCAST_CHANNEL_INITIAL (1 << 31 | 31)
|
||||
#define BROADCAST_CHANNEL_VALID (1 << 30)
|
||||
|
||||
#define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
|
||||
#define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
|
||||
|
||||
static inline void fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
|
||||
{
|
||||
u32 *dst = _dst;
|
||||
__be32 *src = _src;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size / 4; i++)
|
||||
dst[i] = be32_to_cpu(src[i]);
|
||||
}
|
||||
|
||||
static inline void fw_memcpy_to_be32(void *_dst, void *_src, size_t size)
|
||||
{
|
||||
fw_memcpy_from_be32(_dst, _src, size);
|
||||
}
|
||||
|
||||
struct fw_card;
|
||||
struct fw_packet;
|
||||
struct fw_node;
|
||||
struct fw_request;
|
||||
|
||||
struct fw_descriptor {
|
||||
struct list_head link;
|
||||
size_t length;
|
||||
u32 immediate;
|
||||
u32 key;
|
||||
const u32 *data;
|
||||
};
|
||||
|
||||
int fw_core_add_descriptor(struct fw_descriptor *desc);
|
||||
void fw_core_remove_descriptor(struct fw_descriptor *desc);
|
||||
|
||||
typedef void (*fw_packet_callback_t)(struct fw_packet *packet,
|
||||
struct fw_card *card, int status);
|
||||
|
||||
typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
|
||||
void *data, size_t length,
|
||||
void *callback_data);
|
||||
|
||||
/*
|
||||
* Important note: The callback must guarantee that either fw_send_response()
|
||||
* or kfree() is called on the @request.
|
||||
*/
|
||||
typedef void (*fw_address_callback_t)(struct fw_card *card,
|
||||
struct fw_request *request,
|
||||
int tcode, int destination, int source,
|
||||
int generation, int speed,
|
||||
unsigned long long offset,
|
||||
void *data, size_t length,
|
||||
void *callback_data);
|
||||
|
||||
struct fw_packet {
|
||||
int speed;
|
||||
int generation;
|
||||
u32 header[4];
|
||||
size_t header_length;
|
||||
void *payload;
|
||||
size_t payload_length;
|
||||
dma_addr_t payload_bus;
|
||||
u32 timestamp;
|
||||
|
||||
/*
|
||||
* This callback is called when the packet transmission has
|
||||
* completed; for successful transmission, the status code is
|
||||
* the ack received from the destination, otherwise it's a
|
||||
* negative errno: ENOMEM, ESTALE, ETIMEDOUT, ENODEV, EIO.
|
||||
* The callback can be called from tasklet context and thus
|
||||
* must never block.
|
||||
*/
|
||||
fw_packet_callback_t callback;
|
||||
int ack;
|
||||
struct list_head link;
|
||||
void *driver_data;
|
||||
};
|
||||
|
||||
struct fw_transaction {
|
||||
int node_id; /* The generation is implied; it is always the current. */
|
||||
int tlabel;
|
||||
int timestamp;
|
||||
struct list_head link;
|
||||
|
||||
struct fw_packet packet;
|
||||
|
||||
/*
|
||||
* The data passed to the callback is valid only during the
|
||||
* callback.
|
||||
*/
|
||||
fw_transaction_callback_t callback;
|
||||
void *callback_data;
|
||||
};
|
||||
|
||||
struct fw_address_handler {
|
||||
u64 offset;
|
||||
size_t length;
|
||||
fw_address_callback_t address_callback;
|
||||
void *callback_data;
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
struct fw_address_region {
|
||||
u64 start;
|
||||
u64 end;
|
||||
};
|
||||
|
||||
extern const struct fw_address_region fw_high_memory_region;
|
||||
|
||||
int fw_core_add_address_handler(struct fw_address_handler *handler,
|
||||
const struct fw_address_region *region);
|
||||
void fw_core_remove_address_handler(struct fw_address_handler *handler);
|
||||
void fw_fill_response(struct fw_packet *response, u32 *request_header,
|
||||
int rcode, void *payload, size_t length);
|
||||
void fw_send_response(struct fw_card *card,
|
||||
struct fw_request *request, int rcode);
|
||||
|
||||
extern struct bus_type fw_bus_type;
|
||||
|
||||
struct fw_card {
|
||||
const struct fw_card_driver *driver;
|
||||
struct device *device;
|
||||
struct kref kref;
|
||||
struct completion done;
|
||||
|
||||
int node_id;
|
||||
int generation;
|
||||
int current_tlabel, tlabel_mask;
|
||||
struct list_head transaction_list;
|
||||
struct timer_list flush_timer;
|
||||
unsigned long reset_jiffies;
|
||||
|
||||
unsigned long long guid;
|
||||
unsigned max_receive;
|
||||
int link_speed;
|
||||
int config_rom_generation;
|
||||
|
||||
spinlock_t lock; /* Take this lock when handling the lists in
|
||||
* this struct. */
|
||||
struct fw_node *local_node;
|
||||
struct fw_node *root_node;
|
||||
struct fw_node *irm_node;
|
||||
u8 color; /* must be u8 to match the definition in struct fw_node */
|
||||
int gap_count;
|
||||
bool beta_repeaters_present;
|
||||
|
||||
int index;
|
||||
|
||||
struct list_head link;
|
||||
|
||||
/* Work struct for BM duties. */
|
||||
struct delayed_work work;
|
||||
int bm_retries;
|
||||
int bm_generation;
|
||||
|
||||
bool broadcast_channel_allocated;
|
||||
u32 broadcast_channel;
|
||||
u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
|
||||
};
|
||||
|
||||
static inline struct fw_card *fw_card_get(struct fw_card *card)
|
||||
{
|
||||
kref_get(&card->kref);
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
void fw_card_release(struct kref *kref);
|
||||
|
||||
static inline void fw_card_put(struct fw_card *card)
|
||||
{
|
||||
kref_put(&card->kref, fw_card_release);
|
||||
}
|
||||
|
||||
extern void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
|
||||
|
||||
/*
|
||||
* Check whether new_generation is the immediate successor of old_generation.
|
||||
* Take counter roll-over at 255 (as per to OHCI) into account.
|
||||
*/
|
||||
static inline bool is_next_generation(int new_generation, int old_generation)
|
||||
{
|
||||
return (new_generation & 0xff) == ((old_generation + 1) & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* The iso packet format allows for an immediate header/payload part
|
||||
* stored in 'header' immediately after the packet info plus an
|
||||
* indirect payload part that is pointer to by the 'payload' field.
|
||||
* Applications can use one or the other or both to implement simple
|
||||
* low-bandwidth streaming (e.g. audio) or more advanced
|
||||
* scatter-gather streaming (e.g. assembling video frame automatically).
|
||||
*/
|
||||
|
||||
struct fw_iso_packet {
|
||||
u16 payload_length; /* Length of indirect payload. */
|
||||
u32 interrupt : 1; /* Generate interrupt on this packet */
|
||||
u32 skip : 1; /* Set to not send packet at all. */
|
||||
u32 tag : 2;
|
||||
u32 sy : 4;
|
||||
u32 header_length : 8; /* Length of immediate header. */
|
||||
u32 header[0];
|
||||
};
|
||||
|
||||
#define FW_ISO_CONTEXT_TRANSMIT 0
|
||||
#define FW_ISO_CONTEXT_RECEIVE 1
|
||||
|
||||
#define FW_ISO_CONTEXT_MATCH_TAG0 1
|
||||
#define FW_ISO_CONTEXT_MATCH_TAG1 2
|
||||
#define FW_ISO_CONTEXT_MATCH_TAG2 4
|
||||
#define FW_ISO_CONTEXT_MATCH_TAG3 8
|
||||
#define FW_ISO_CONTEXT_MATCH_ALL_TAGS 15
|
||||
|
||||
struct fw_iso_context;
|
||||
|
||||
typedef void (*fw_iso_callback_t)(struct fw_iso_context *context,
|
||||
u32 cycle, size_t header_length,
|
||||
void *header, void *data);
|
||||
|
||||
/*
|
||||
* An iso buffer is just a set of pages mapped for DMA in the
|
||||
* specified direction. Since the pages are to be used for DMA, they
|
||||
* are not mapped into the kernel virtual address space. We store the
|
||||
* DMA address in the page private. The helper function
|
||||
* fw_iso_buffer_map() will map the pages into a given vma.
|
||||
*/
|
||||
|
||||
struct fw_iso_buffer {
|
||||
enum dma_data_direction direction;
|
||||
struct page **pages;
|
||||
int page_count;
|
||||
};
|
||||
|
||||
struct fw_iso_context {
|
||||
struct fw_card *card;
|
||||
int type;
|
||||
int channel;
|
||||
int speed;
|
||||
size_t header_size;
|
||||
fw_iso_callback_t callback;
|
||||
void *callback_data;
|
||||
};
|
||||
|
||||
int fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
|
||||
int page_count, enum dma_data_direction direction);
|
||||
int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
|
||||
void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
|
||||
|
||||
struct fw_iso_context *fw_iso_context_create(struct fw_card *card,
|
||||
int type, int channel, int speed, size_t header_size,
|
||||
fw_iso_callback_t callback, void *callback_data);
|
||||
int fw_iso_context_queue(struct fw_iso_context *ctx,
|
||||
struct fw_iso_packet *packet,
|
||||
struct fw_iso_buffer *buffer,
|
||||
unsigned long payload);
|
||||
int fw_iso_context_start(struct fw_iso_context *ctx,
|
||||
int cycle, int sync, int tags);
|
||||
int fw_iso_context_stop(struct fw_iso_context *ctx);
|
||||
void fw_iso_context_destroy(struct fw_iso_context *ctx);
|
||||
|
||||
void fw_iso_resource_manage(struct fw_card *card, int generation,
|
||||
u64 channels_mask, int *channel, int *bandwidth, bool allocate);
|
||||
|
||||
struct fw_card_driver {
|
||||
/*
|
||||
* Enable the given card with the given initial config rom.
|
||||
* This function is expected to activate the card, and either
|
||||
* enable the PHY or set the link_on bit and initiate a bus
|
||||
* reset.
|
||||
*/
|
||||
int (*enable)(struct fw_card *card, u32 *config_rom, size_t length);
|
||||
|
||||
int (*update_phy_reg)(struct fw_card *card, int address,
|
||||
int clear_bits, int set_bits);
|
||||
|
||||
/*
|
||||
* Update the config rom for an enabled card. This function
|
||||
* should change the config rom that is presented on the bus
|
||||
* an initiate a bus reset.
|
||||
*/
|
||||
int (*set_config_rom)(struct fw_card *card,
|
||||
u32 *config_rom, size_t length);
|
||||
|
||||
void (*send_request)(struct fw_card *card, struct fw_packet *packet);
|
||||
void (*send_response)(struct fw_card *card, struct fw_packet *packet);
|
||||
/* Calling cancel is valid once a packet has been submitted. */
|
||||
int (*cancel_packet)(struct fw_card *card, struct fw_packet *packet);
|
||||
|
||||
/*
|
||||
* Allow the specified node ID to do direct DMA out and in of
|
||||
* host memory. The card will disable this for all node when
|
||||
* a bus reset happens, so driver need to reenable this after
|
||||
* bus reset. Returns 0 on success, -ENODEV if the card
|
||||
* doesn't support this, -ESTALE if the generation doesn't
|
||||
* match.
|
||||
*/
|
||||
int (*enable_phys_dma)(struct fw_card *card,
|
||||
int node_id, int generation);
|
||||
|
||||
u64 (*get_bus_time)(struct fw_card *card);
|
||||
|
||||
struct fw_iso_context *
|
||||
(*allocate_iso_context)(struct fw_card *card,
|
||||
int type, int channel, size_t header_size);
|
||||
void (*free_iso_context)(struct fw_iso_context *ctx);
|
||||
|
||||
int (*start_iso)(struct fw_iso_context *ctx,
|
||||
s32 cycle, u32 sync, u32 tags);
|
||||
|
||||
int (*queue_iso)(struct fw_iso_context *ctx,
|
||||
struct fw_iso_packet *packet,
|
||||
struct fw_iso_buffer *buffer,
|
||||
unsigned long payload);
|
||||
|
||||
int (*stop_iso)(struct fw_iso_context *ctx);
|
||||
};
|
||||
|
||||
int fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
|
||||
|
||||
void fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||
int tcode, int destination_id, int generation, int speed,
|
||||
unsigned long long offset, void *payload, size_t length,
|
||||
fw_transaction_callback_t callback, void *callback_data);
|
||||
int fw_cancel_transaction(struct fw_card *card,
|
||||
struct fw_transaction *transaction);
|
||||
void fw_flush_transactions(struct fw_card *card);
|
||||
int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
|
||||
int generation, int speed, unsigned long long offset,
|
||||
void *payload, size_t length);
|
||||
void fw_send_phy_config(struct fw_card *card,
|
||||
int node_id, int generation, int gap_count);
|
||||
|
||||
static inline int fw_stream_packet_destination_id(int tag, int channel, int sy)
|
||||
{
|
||||
return tag << 14 | channel << 8 | sy;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by the topology code to inform the device code of node
|
||||
* activity; found, lost, or updated nodes.
|
||||
*/
|
||||
void fw_node_event(struct fw_card *card, struct fw_node *node, int event);
|
||||
|
||||
/* API used by card level drivers */
|
||||
|
||||
void fw_card_initialize(struct fw_card *card,
|
||||
const struct fw_card_driver *driver, struct device *device);
|
||||
int fw_card_add(struct fw_card *card,
|
||||
u32 max_receive, u32 link_speed, u64 guid);
|
||||
void fw_core_remove_card(struct fw_card *card);
|
||||
void fw_core_handle_bus_reset(struct fw_card *card, int node_id,
|
||||
int generation, int self_id_count, u32 *self_ids);
|
||||
void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
|
||||
void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
|
||||
|
||||
extern int fw_irm_set_broadcast_channel_register(struct device *dev,
|
||||
void *data);
|
||||
|
||||
#endif /* __fw_transaction_h */
|
|
@ -20,17 +20,25 @@
|
|||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/firewire.h>
|
||||
#include <linux/firewire-constants.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
|
@ -38,8 +46,8 @@
|
|||
#include <asm/pmac_feature.h>
|
||||
#endif
|
||||
|
||||
#include "fw-ohci.h"
|
||||
#include "fw-transaction.h"
|
||||
#include "core.h"
|
||||
#include "ohci.h"
|
||||
|
||||
#define DESCRIPTOR_OUTPUT_MORE 0
|
||||
#define DESCRIPTOR_OUTPUT_LAST (1 << 12)
|
||||
|
@ -178,7 +186,7 @@ struct fw_ohci {
|
|||
int node_id;
|
||||
int generation;
|
||||
int request_generation; /* for timestamping incoming requests */
|
||||
u32 bus_seconds;
|
||||
atomic_t bus_seconds;
|
||||
|
||||
bool use_dualbuffer;
|
||||
bool old_uninorth;
|
||||
|
@ -231,7 +239,6 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
|
|||
#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
|
||||
#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
|
||||
|
||||
#define FW_OHCI_MAJOR 240
|
||||
#define OHCI1394_REGISTER_SIZE 0x800
|
||||
#define OHCI_LOOP_COUNT 500
|
||||
#define OHCI1394_PCI_HCI_Control 0x40
|
||||
|
@ -1434,7 +1441,7 @@ static irqreturn_t irq_handler(int irq, void *data)
|
|||
if (event & OHCI1394_cycle64Seconds) {
|
||||
cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
|
||||
if ((cycle_time & 0x80000000) == 0)
|
||||
ohci->bus_seconds++;
|
||||
atomic_inc(&ohci->bus_seconds);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -1770,7 +1777,7 @@ static u64 ohci_get_bus_time(struct fw_card *card)
|
|||
u64 bus_time;
|
||||
|
||||
cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
|
||||
bus_time = ((u64) ohci->bus_seconds << 32) | cycle_time;
|
||||
bus_time = ((u64)atomic_read(&ohci->bus_seconds) << 32) | cycle_time;
|
||||
|
||||
return bus_time;
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef __fw_ohci_h
|
||||
#define __fw_ohci_h
|
||||
#ifndef _FIREWIRE_OHCI_H
|
||||
#define _FIREWIRE_OHCI_H
|
||||
|
||||
/* OHCI register map */
|
||||
|
||||
|
@ -154,4 +154,4 @@
|
|||
|
||||
#define OHCI1394_phy_tcode 0xe
|
||||
|
||||
#endif /* __fw_ohci_h */
|
||||
#endif /* _FIREWIRE_OHCI_H */
|
|
@ -30,18 +30,28 @@
|
|||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/firewire.h>
|
||||
#include <linux/firewire-constants.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/stringify.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
|
@ -49,10 +59,6 @@
|
|||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
|
||||
#include "fw-device.h"
|
||||
#include "fw-topology.h"
|
||||
#include "fw-transaction.h"
|
||||
|
||||
/*
|
||||
* So far only bridges from Oxford Semiconductor are known to support
|
||||
* concurrent logins. Depending on firmware, four or two concurrent logins
|
||||
|
@ -174,6 +180,11 @@ struct sbp2_target {
|
|||
int blocked; /* ditto */
|
||||
};
|
||||
|
||||
static struct fw_device *target_device(struct sbp2_target *tgt)
|
||||
{
|
||||
return fw_parent_device(tgt->unit);
|
||||
}
|
||||
|
||||
/* Impossible login_id, to detect logout attempt before successful login */
|
||||
#define INVALID_LOGIN_ID 0x10000
|
||||
|
||||
|
@ -482,7 +493,7 @@ static void complete_transaction(struct fw_card *card, int rcode,
|
|||
static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
|
||||
int node_id, int generation, u64 offset)
|
||||
{
|
||||
struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(lu->tgt);
|
||||
unsigned long flags;
|
||||
|
||||
orb->pointer.high = 0;
|
||||
|
@ -504,7 +515,7 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
|
|||
|
||||
static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
|
||||
{
|
||||
struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(lu->tgt);
|
||||
struct sbp2_orb *orb, *next;
|
||||
struct list_head list;
|
||||
unsigned long flags;
|
||||
|
@ -542,7 +553,7 @@ static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
|
|||
int generation, int function,
|
||||
int lun_or_login_id, void *response)
|
||||
{
|
||||
struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(lu->tgt);
|
||||
struct sbp2_management_orb *orb;
|
||||
unsigned int timeout;
|
||||
int retval = -ENOMEM;
|
||||
|
@ -638,7 +649,7 @@ static int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id,
|
|||
|
||||
static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
|
||||
{
|
||||
struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(lu->tgt);
|
||||
__be32 d = 0;
|
||||
|
||||
fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST,
|
||||
|
@ -655,7 +666,7 @@ static void complete_agent_reset_write_no_wait(struct fw_card *card,
|
|||
|
||||
static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
|
||||
{
|
||||
struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(lu->tgt);
|
||||
struct fw_transaction *t;
|
||||
static __be32 d;
|
||||
|
||||
|
@ -694,7 +705,7 @@ static inline void sbp2_allow_block(struct sbp2_logical_unit *lu)
|
|||
static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
|
||||
{
|
||||
struct sbp2_target *tgt = lu->tgt;
|
||||
struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
|
||||
struct fw_card *card = target_device(tgt)->card;
|
||||
struct Scsi_Host *shost =
|
||||
container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
|
||||
unsigned long flags;
|
||||
|
@ -718,7 +729,7 @@ static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
|
|||
static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
|
||||
{
|
||||
struct sbp2_target *tgt = lu->tgt;
|
||||
struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
|
||||
struct fw_card *card = target_device(tgt)->card;
|
||||
struct Scsi_Host *shost =
|
||||
container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
|
||||
unsigned long flags;
|
||||
|
@ -743,7 +754,7 @@ static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
|
|||
*/
|
||||
static void sbp2_unblock(struct sbp2_target *tgt)
|
||||
{
|
||||
struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
|
||||
struct fw_card *card = target_device(tgt)->card;
|
||||
struct Scsi_Host *shost =
|
||||
container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
|
||||
unsigned long flags;
|
||||
|
@ -773,7 +784,7 @@ static void sbp2_release_target(struct kref *kref)
|
|||
struct Scsi_Host *shost =
|
||||
container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
|
||||
struct scsi_device *sdev;
|
||||
struct fw_device *device = fw_device(tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(tgt);
|
||||
|
||||
/* prevent deadlocks */
|
||||
sbp2_unblock(tgt);
|
||||
|
@ -846,7 +857,7 @@ static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay)
|
|||
*/
|
||||
static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu)
|
||||
{
|
||||
struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(lu->tgt);
|
||||
__be32 d = cpu_to_be32(SBP2_CYCLE_LIMIT | SBP2_RETRY_LIMIT);
|
||||
|
||||
fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST,
|
||||
|
@ -862,7 +873,7 @@ static void sbp2_login(struct work_struct *work)
|
|||
struct sbp2_logical_unit *lu =
|
||||
container_of(work, struct sbp2_logical_unit, work.work);
|
||||
struct sbp2_target *tgt = lu->tgt;
|
||||
struct fw_device *device = fw_device(tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(tgt);
|
||||
struct Scsi_Host *shost;
|
||||
struct scsi_device *sdev;
|
||||
struct sbp2_login_response response;
|
||||
|
@ -1110,7 +1121,7 @@ static struct scsi_host_template scsi_driver_template;
|
|||
static int sbp2_probe(struct device *dev)
|
||||
{
|
||||
struct fw_unit *unit = fw_unit(dev);
|
||||
struct fw_device *device = fw_device(unit->device.parent);
|
||||
struct fw_device *device = fw_parent_device(unit);
|
||||
struct sbp2_target *tgt;
|
||||
struct sbp2_logical_unit *lu;
|
||||
struct Scsi_Host *shost;
|
||||
|
@ -1191,7 +1202,7 @@ static void sbp2_reconnect(struct work_struct *work)
|
|||
struct sbp2_logical_unit *lu =
|
||||
container_of(work, struct sbp2_logical_unit, work.work);
|
||||
struct sbp2_target *tgt = lu->tgt;
|
||||
struct fw_device *device = fw_device(tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(tgt);
|
||||
int generation, node_id, local_node_id;
|
||||
|
||||
if (fw_device_is_shutdown(device))
|
||||
|
@ -1243,7 +1254,7 @@ static void sbp2_update(struct fw_unit *unit)
|
|||
struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
|
||||
struct sbp2_logical_unit *lu;
|
||||
|
||||
fw_device_enable_phys_dma(fw_device(unit->device.parent));
|
||||
fw_device_enable_phys_dma(fw_parent_device(unit));
|
||||
|
||||
/*
|
||||
* Fw-core serializes sbp2_update() against sbp2_remove().
|
||||
|
@ -1259,9 +1270,10 @@ static void sbp2_update(struct fw_unit *unit)
|
|||
#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e
|
||||
#define SBP2_SW_VERSION_ENTRY 0x00010483
|
||||
|
||||
static const struct fw_device_id sbp2_id_table[] = {
|
||||
static const struct ieee1394_device_id sbp2_id_table[] = {
|
||||
{
|
||||
.match_flags = FW_MATCH_SPECIFIER_ID | FW_MATCH_VERSION,
|
||||
.match_flags = IEEE1394_MATCH_SPECIFIER_ID |
|
||||
IEEE1394_MATCH_VERSION,
|
||||
.specifier_id = SBP2_UNIT_SPEC_ID_ENTRY,
|
||||
.version = SBP2_SW_VERSION_ENTRY,
|
||||
},
|
||||
|
@ -1335,7 +1347,7 @@ static void complete_command_orb(struct sbp2_orb *base_orb,
|
|||
{
|
||||
struct sbp2_command_orb *orb =
|
||||
container_of(base_orb, struct sbp2_command_orb, base);
|
||||
struct fw_device *device = fw_device(orb->lu->tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(orb->lu->tgt);
|
||||
int result;
|
||||
|
||||
if (status != NULL) {
|
||||
|
@ -1442,7 +1454,7 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
|
|||
static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
|
||||
{
|
||||
struct sbp2_logical_unit *lu = cmd->device->hostdata;
|
||||
struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
|
||||
struct fw_device *device = target_device(lu->tgt);
|
||||
struct sbp2_command_orb *orb;
|
||||
int generation, retval = SCSI_MLQUEUE_HOST_BUSY;
|
||||
|
358
include/linux/firewire.h
Normal file
358
include/linux/firewire.h
Normal file
|
@ -0,0 +1,358 @@
|
|||
#ifndef _LINUX_FIREWIRE_H
|
||||
#define _LINUX_FIREWIRE_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
|
||||
#define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
|
||||
|
||||
static inline void fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
|
||||
{
|
||||
u32 *dst = _dst;
|
||||
__be32 *src = _src;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size / 4; i++)
|
||||
dst[i] = be32_to_cpu(src[i]);
|
||||
}
|
||||
|
||||
static inline void fw_memcpy_to_be32(void *_dst, void *_src, size_t size)
|
||||
{
|
||||
fw_memcpy_from_be32(_dst, _src, size);
|
||||
}
|
||||
#define CSR_REGISTER_BASE 0xfffff0000000ULL
|
||||
|
||||
/* register offsets are relative to CSR_REGISTER_BASE */
|
||||
#define CSR_STATE_CLEAR 0x0
|
||||
#define CSR_STATE_SET 0x4
|
||||
#define CSR_NODE_IDS 0x8
|
||||
#define CSR_RESET_START 0xc
|
||||
#define CSR_SPLIT_TIMEOUT_HI 0x18
|
||||
#define CSR_SPLIT_TIMEOUT_LO 0x1c
|
||||
#define CSR_CYCLE_TIME 0x200
|
||||
#define CSR_BUS_TIME 0x204
|
||||
#define CSR_BUSY_TIMEOUT 0x210
|
||||
#define CSR_BUS_MANAGER_ID 0x21c
|
||||
#define CSR_BANDWIDTH_AVAILABLE 0x220
|
||||
#define CSR_CHANNELS_AVAILABLE 0x224
|
||||
#define CSR_CHANNELS_AVAILABLE_HI 0x224
|
||||
#define CSR_CHANNELS_AVAILABLE_LO 0x228
|
||||
#define CSR_BROADCAST_CHANNEL 0x234
|
||||
#define CSR_CONFIG_ROM 0x400
|
||||
#define CSR_CONFIG_ROM_END 0x800
|
||||
#define CSR_FCP_COMMAND 0xB00
|
||||
#define CSR_FCP_RESPONSE 0xD00
|
||||
#define CSR_FCP_END 0xF00
|
||||
#define CSR_TOPOLOGY_MAP 0x1000
|
||||
#define CSR_TOPOLOGY_MAP_END 0x1400
|
||||
#define CSR_SPEED_MAP 0x2000
|
||||
#define CSR_SPEED_MAP_END 0x3000
|
||||
|
||||
#define CSR_OFFSET 0x40
|
||||
#define CSR_LEAF 0x80
|
||||
#define CSR_DIRECTORY 0xc0
|
||||
|
||||
#define CSR_DESCRIPTOR 0x01
|
||||
#define CSR_VENDOR 0x03
|
||||
#define CSR_HARDWARE_VERSION 0x04
|
||||
#define CSR_NODE_CAPABILITIES 0x0c
|
||||
#define CSR_UNIT 0x11
|
||||
#define CSR_SPECIFIER_ID 0x12
|
||||
#define CSR_VERSION 0x13
|
||||
#define CSR_DEPENDENT_INFO 0x14
|
||||
#define CSR_MODEL 0x17
|
||||
#define CSR_INSTANCE 0x18
|
||||
#define CSR_DIRECTORY_ID 0x20
|
||||
|
||||
struct fw_csr_iterator {
|
||||
u32 *p;
|
||||
u32 *end;
|
||||
};
|
||||
|
||||
void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 *p);
|
||||
int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value);
|
||||
|
||||
extern struct bus_type fw_bus_type;
|
||||
|
||||
struct fw_card_driver;
|
||||
struct fw_node;
|
||||
|
||||
struct fw_card {
|
||||
const struct fw_card_driver *driver;
|
||||
struct device *device;
|
||||
struct kref kref;
|
||||
struct completion done;
|
||||
|
||||
int node_id;
|
||||
int generation;
|
||||
int current_tlabel;
|
||||
u64 tlabel_mask;
|
||||
struct list_head transaction_list;
|
||||
struct timer_list flush_timer;
|
||||
unsigned long reset_jiffies;
|
||||
|
||||
unsigned long long guid;
|
||||
unsigned max_receive;
|
||||
int link_speed;
|
||||
int config_rom_generation;
|
||||
|
||||
spinlock_t lock; /* Take this lock when handling the lists in
|
||||
* this struct. */
|
||||
struct fw_node *local_node;
|
||||
struct fw_node *root_node;
|
||||
struct fw_node *irm_node;
|
||||
u8 color; /* must be u8 to match the definition in struct fw_node */
|
||||
int gap_count;
|
||||
bool beta_repeaters_present;
|
||||
|
||||
int index;
|
||||
|
||||
struct list_head link;
|
||||
|
||||
/* Work struct for BM duties. */
|
||||
struct delayed_work work;
|
||||
int bm_retries;
|
||||
int bm_generation;
|
||||
|
||||
bool broadcast_channel_allocated;
|
||||
u32 broadcast_channel;
|
||||
u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4];
|
||||
};
|
||||
|
||||
static inline struct fw_card *fw_card_get(struct fw_card *card)
|
||||
{
|
||||
kref_get(&card->kref);
|
||||
|
||||
return card;
|
||||
}
|
||||
|
||||
void fw_card_release(struct kref *kref);
|
||||
|
||||
static inline void fw_card_put(struct fw_card *card)
|
||||
{
|
||||
kref_put(&card->kref, fw_card_release);
|
||||
}
|
||||
|
||||
struct fw_attribute_group {
|
||||
struct attribute_group *groups[2];
|
||||
struct attribute_group group;
|
||||
struct attribute *attrs[12];
|
||||
};
|
||||
|
||||
enum fw_device_state {
|
||||
FW_DEVICE_INITIALIZING,
|
||||
FW_DEVICE_RUNNING,
|
||||
FW_DEVICE_GONE,
|
||||
FW_DEVICE_SHUTDOWN,
|
||||
};
|
||||
|
||||
/*
|
||||
* Note, fw_device.generation always has to be read before fw_device.node_id.
|
||||
* Use SMP memory barriers to ensure this. Otherwise requests will be sent
|
||||
* to an outdated node_id if the generation was updated in the meantime due
|
||||
* to a bus reset.
|
||||
*
|
||||
* Likewise, fw-core will take care to update .node_id before .generation so
|
||||
* that whenever fw_device.generation is current WRT the actual bus generation,
|
||||
* fw_device.node_id is guaranteed to be current too.
|
||||
*
|
||||
* The same applies to fw_device.card->node_id vs. fw_device.generation.
|
||||
*
|
||||
* fw_device.config_rom and fw_device.config_rom_length may be accessed during
|
||||
* the lifetime of any fw_unit belonging to the fw_device, before device_del()
|
||||
* was called on the last fw_unit. Alternatively, they may be accessed while
|
||||
* holding fw_device_rwsem.
|
||||
*/
|
||||
struct fw_device {
|
||||
atomic_t state;
|
||||
struct fw_node *node;
|
||||
int node_id;
|
||||
int generation;
|
||||
unsigned max_speed;
|
||||
struct fw_card *card;
|
||||
struct device device;
|
||||
|
||||
struct mutex client_list_mutex;
|
||||
struct list_head client_list;
|
||||
|
||||
u32 *config_rom;
|
||||
size_t config_rom_length;
|
||||
int config_rom_retries;
|
||||
unsigned is_local:1;
|
||||
unsigned max_rec:4;
|
||||
unsigned cmc:1;
|
||||
unsigned irmc:1;
|
||||
unsigned bc_implemented:2;
|
||||
|
||||
struct delayed_work work;
|
||||
struct fw_attribute_group attribute_group;
|
||||
};
|
||||
|
||||
static inline struct fw_device *fw_device(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct fw_device, device);
|
||||
}
|
||||
|
||||
static inline int fw_device_is_shutdown(struct fw_device *device)
|
||||
{
|
||||
return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN;
|
||||
}
|
||||
|
||||
static inline struct fw_device *fw_device_get(struct fw_device *device)
|
||||
{
|
||||
get_device(&device->device);
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
static inline void fw_device_put(struct fw_device *device)
|
||||
{
|
||||
put_device(&device->device);
|
||||
}
|
||||
|
||||
int fw_device_enable_phys_dma(struct fw_device *device);
|
||||
|
||||
/*
|
||||
* fw_unit.directory must not be accessed after device_del(&fw_unit.device).
|
||||
*/
|
||||
struct fw_unit {
|
||||
struct device device;
|
||||
u32 *directory;
|
||||
struct fw_attribute_group attribute_group;
|
||||
};
|
||||
|
||||
static inline struct fw_unit *fw_unit(struct device *dev)
|
||||
{
|
||||
return container_of(dev, struct fw_unit, device);
|
||||
}
|
||||
|
||||
static inline struct fw_unit *fw_unit_get(struct fw_unit *unit)
|
||||
{
|
||||
get_device(&unit->device);
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
static inline void fw_unit_put(struct fw_unit *unit)
|
||||
{
|
||||
put_device(&unit->device);
|
||||
}
|
||||
|
||||
static inline struct fw_device *fw_parent_device(struct fw_unit *unit)
|
||||
{
|
||||
return fw_device(unit->device.parent);
|
||||
}
|
||||
|
||||
struct ieee1394_device_id;
|
||||
|
||||
struct fw_driver {
|
||||
struct device_driver driver;
|
||||
/* Called when the parent device sits through a bus reset. */
|
||||
void (*update)(struct fw_unit *unit);
|
||||
const struct ieee1394_device_id *id_table;
|
||||
};
|
||||
|
||||
struct fw_packet;
|
||||
struct fw_request;
|
||||
|
||||
typedef void (*fw_packet_callback_t)(struct fw_packet *packet,
|
||||
struct fw_card *card, int status);
|
||||
typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
|
||||
void *data, size_t length,
|
||||
void *callback_data);
|
||||
/*
|
||||
* Important note: The callback must guarantee that either fw_send_response()
|
||||
* or kfree() is called on the @request.
|
||||
*/
|
||||
typedef void (*fw_address_callback_t)(struct fw_card *card,
|
||||
struct fw_request *request,
|
||||
int tcode, int destination, int source,
|
||||
int generation, int speed,
|
||||
unsigned long long offset,
|
||||
void *data, size_t length,
|
||||
void *callback_data);
|
||||
|
||||
struct fw_packet {
|
||||
int speed;
|
||||
int generation;
|
||||
u32 header[4];
|
||||
size_t header_length;
|
||||
void *payload;
|
||||
size_t payload_length;
|
||||
dma_addr_t payload_bus;
|
||||
u32 timestamp;
|
||||
|
||||
/*
|
||||
* This callback is called when the packet transmission has
|
||||
* completed; for successful transmission, the status code is
|
||||
* the ack received from the destination, otherwise it's a
|
||||
* negative errno: ENOMEM, ESTALE, ETIMEDOUT, ENODEV, EIO.
|
||||
* The callback can be called from tasklet context and thus
|
||||
* must never block.
|
||||
*/
|
||||
fw_packet_callback_t callback;
|
||||
int ack;
|
||||
struct list_head link;
|
||||
void *driver_data;
|
||||
};
|
||||
|
||||
struct fw_transaction {
|
||||
int node_id; /* The generation is implied; it is always the current. */
|
||||
int tlabel;
|
||||
int timestamp;
|
||||
struct list_head link;
|
||||
|
||||
struct fw_packet packet;
|
||||
|
||||
/*
|
||||
* The data passed to the callback is valid only during the
|
||||
* callback.
|
||||
*/
|
||||
fw_transaction_callback_t callback;
|
||||
void *callback_data;
|
||||
};
|
||||
|
||||
struct fw_address_handler {
|
||||
u64 offset;
|
||||
size_t length;
|
||||
fw_address_callback_t address_callback;
|
||||
void *callback_data;
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
struct fw_address_region {
|
||||
u64 start;
|
||||
u64 end;
|
||||
};
|
||||
|
||||
extern const struct fw_address_region fw_high_memory_region;
|
||||
|
||||
int fw_core_add_address_handler(struct fw_address_handler *handler,
|
||||
const struct fw_address_region *region);
|
||||
void fw_core_remove_address_handler(struct fw_address_handler *handler);
|
||||
void fw_send_response(struct fw_card *card,
|
||||
struct fw_request *request, int rcode);
|
||||
void fw_send_request(struct fw_card *card, struct fw_transaction *t,
|
||||
int tcode, int destination_id, int generation, int speed,
|
||||
unsigned long long offset, void *payload, size_t length,
|
||||
fw_transaction_callback_t callback, void *callback_data);
|
||||
int fw_cancel_transaction(struct fw_card *card,
|
||||
struct fw_transaction *transaction);
|
||||
int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
|
||||
int generation, int speed, unsigned long long offset,
|
||||
void *payload, size_t length);
|
||||
|
||||
#endif /* _LINUX_FIREWIRE_H */
|
Loading…
Reference in a new issue