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:
Linus Torvalds 2009-06-16 14:29:46 -07:00
commit f83b1e616f
15 changed files with 903 additions and 830 deletions

View File

@ -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

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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->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;

View File

@ -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

View File

@ -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;

View File

@ -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
View 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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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
View 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 */