struct ti_ohci *ohci;
struct list_head stream_list;
spinlock_t stream_list_lock;
- struct list_head link;
};
static struct hpsb_highlevel *amdtp_highlevel;
-static LIST_HEAD(host_list);
-static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
+
/* FIXME: This doesn't belong here... */
{
u32 syt_cycle, cycle_count, start_cycle;
- cycle_count = reg_read(s->host->host->hostdata,
+ cycle_count = reg_read(s->host->ohci,
OHCI1394_IsochronousCycleTimer) >> 12;
syt_cycle = (pl->last_cycle_count - PACKET_LIST_SIZE + 1) & 0x0f;
static int amdtp_open(struct inode *inode, struct file *file)
{
struct amdtp_host *host;
+ int i = ieee1394_file_to_instance(file);
- /* FIXME: We just grab the first registered host */
- spin_lock(&host_list_lock);
- if (!list_empty(&host_list))
- host = list_entry(host_list.next, struct amdtp_host, link);
- else
- host = NULL;
- spin_unlock(&host_list_lock);
-
+ host = hpsb_get_hostinfo_bykey(amdtp_highlevel, i);
if (host == NULL)
return -ENODEV;
/* IEEE1394 Subsystem functions */
-static void amdtp_add_host(struct hpsb_host *host)
+static void amdtp_add_host(struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct amdtp_host *ah;
+ int minor;
+ char name[16];
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME) != 0)
return;
- ah = kmalloc(sizeof *ah, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+ ah = hpsb_create_hostinfo(hl, host, sizeof(*ah));
+ if (!ah) {
+ HPSB_ERR("amdtp: Unable able to alloc hostinfo");
+ return;
+ }
+
ah->host = host;
ah->ohci = host->hostdata;
+
+ hpsb_set_hostinfo_key(hl, host, ah->ohci->id);
+
+ minor = IEEE1394_MINOR_BLOCK_AMDTP * 16 + ah->ohci->id;
+
+ sprintf(name, "amdtp/%d", ah->ohci->id);
+
INIT_LIST_HEAD(&ah->stream_list);
spin_lock_init(&ah->stream_list_lock);
- spin_lock_irq(&host_list_lock);
- list_add_tail(&ah->link, &host_list);
- spin_unlock_irq(&host_list_lock);
+ devfs_register(NULL, name, 0, IEEE1394_MAJOR, minor,
+ S_IFCHR | S_IRUSR | S_IWUSR, &amdtp_fops, NULL);
}
static void amdtp_remove_host(struct hpsb_host *host)
{
- struct list_head *lh;
- struct amdtp_host *ah;
+ struct amdtp_host *ah = hpsb_get_hostinfo(amdtp_highlevel, host);
- spin_lock_irq(&host_list_lock);
- list_for_each(lh, &host_list) {
- if (list_entry(lh, struct amdtp_host, link)->host == host) {
- list_del(lh);
- break;
- }
- }
- spin_unlock_irq(&host_list_lock);
-
- if (lh != &host_list) {
- ah = list_entry(lh, struct amdtp_host, link);
- kfree(ah);
- }
- else
- HPSB_ERR("remove_host: bogus ohci host: %p", host);
+ if (ah)
+ devfs_remove("amdtp/%d", ah->ohci->id);
+
+ return;
}
static struct hpsb_highlevel_ops amdtp_highlevel_ops = {
return -EIO;
}
+ devfs_mk_dir("amdtp");
+
amdtp_highlevel = hpsb_register_highlevel ("amdtp",
&amdtp_highlevel_ops);
if (amdtp_highlevel == NULL) {
HPSB_ERR("amdtp: unable to register highlevel ops");
+ devfs_remove("amdtp");
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
return -EIO;
}
#endif
hpsb_unregister_highlevel(amdtp_highlevel);
+ devfs_remove("amdtp");
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
HPSB_INFO("Unloaded AMDTP driver");
quadlet_t impr_quadlet;
} v;
struct plug ipcr[2];
-
- struct list_head link;
};
enum {
static struct hpsb_highlevel *cmp_highlevel;
-static LIST_HEAD(host_list);
-static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
-
-static struct cmp_host *
-lookup_cmp_host(struct hpsb_host *host)
-{
- struct cmp_host *ch;
- struct list_head *lh;
- unsigned long flags;
-
- ch = NULL;
- spin_lock_irqsave(&host_list_lock, flags);
- list_for_each(lh, &host_list) {
- ch = list_entry(lh, struct cmp_host, link);
- if (ch->host == host)
- break;
- }
- spin_unlock_irqrestore(&host_list_lock, flags);
-
- if (lh == &host_list)
- return NULL;
- else
- return ch;
-}
-
struct cmp_pcr *
cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload,
void (*update)(struct cmp_pcr *pcr, void *data),
struct cmp_host *ch;
struct plug *plug;
- ch = lookup_cmp_host(host);
+ ch = hpsb_get_hostinfo(cmp_highlevel, host);
if (opcr_number >= ch->u.ompr.nplugs ||
ch->opcr[opcr_number].update != NULL)
struct cmp_host *ch;
struct plug *plug;
- ch = lookup_cmp_host(host);
+ ch = hpsb_get_hostinfo(cmp_highlevel, host);
plug = (struct plug *)opcr;
if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG();
}
}
-static void cmp_add_host(struct hpsb_host *host)
+static void cmp_add_host(struct hpsb_host *host, struct hpsb_highlevel *hl)
{
- struct cmp_host *ch;
+ struct cmp_host *ch = hpsb_create_hostinfo(hl, host, sizeof (*ch));
- ch = kmalloc(sizeof *ch, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
if (ch == NULL) {
HPSB_ERR("Failed to allocate cmp_host");
return;
}
- memset(ch, 0, sizeof *ch);
+
ch->host = host;
ch->u.ompr.rate = SPEED_100;
ch->u.ompr.bcast_channel_base = 63;
ch->u.ompr.nplugs = 2;
- reset_plugs(ch);
- spin_lock_irq(&host_list_lock);
- list_add_tail(&ch->link, &host_list);
- spin_unlock_irq(&host_list_lock);
-}
-
-static void cmp_host_reset(struct hpsb_host *host)
-{
- struct cmp_host *ch;
-
- ch = lookup_cmp_host(host);
- if (ch == NULL) BUG();
reset_plugs(ch);
}
-static void cmp_remove_host(struct hpsb_host *host)
+static void cmp_host_reset(struct hpsb_host *host)
{
struct cmp_host *ch;
- ch = lookup_cmp_host(host);
- if (ch == NULL) BUG();
-
- spin_lock_irq(&host_list_lock);
- list_del(&ch->link);
- spin_unlock_irq(&host_list_lock);
+ ch = hpsb_get_hostinfo(cmp_highlevel, host);
+ if (ch == NULL) {
+ HPSB_ERR("cmp: Tried to reset unknown host");
+ return;
+ }
- kfree(ch);
+ reset_plugs(ch);
}
static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
if (length != 4)
return RCODE_TYPE_ERROR;
- ch = lookup_cmp_host(host);
+ ch = hpsb_get_hostinfo(cmp_highlevel, host);
if (csraddr == 0x900) {
*buf = cpu_to_be32(ch->u.ompr_quadlet);
return RCODE_COMPLETE;
int plug;
struct cmp_host *ch;
- ch = lookup_cmp_host(host);
+ ch = hpsb_get_hostinfo(cmp_highlevel, host);
if (extcode != EXTCODE_COMPARE_SWAP)
return RCODE_TYPE_ERROR;
static struct hpsb_highlevel_ops cmp_highlevel_ops = {
.add_host = cmp_add_host,
- .remove_host = cmp_remove_host,
.host_reset = cmp_host_reset,
};
}
-static void add_host(struct hpsb_host *host)
+static void add_host(struct hpsb_host *host, struct hpsb_highlevel *hl)
{
host->csr.lock = SPIN_LOCK_UNLOCKED;
int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
size_t size, unsigned char rom_version)
{
- int ret,flags;
+ unsigned long flags;
+ int ret;
+
spin_lock_irqsave(&host->csr.lock, flags);
if (rom_version != host->csr.rom_version)
ret = -1;
int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
size_t buffersize, size_t *rom_size, unsigned char *rom_version)
{
- int ret,flags;
+ unsigned long flags;
+ int ret;
+
spin_lock_irqsave(&host->csr.lock, flags);
*rom_version=host->csr.rom_version;
*rom_size=host->csr.rom_size;
static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
u64 addr, unsigned int length, u16 fl)
{
+ unsigned long flags;
int csraddr = addr - CSR_REGISTER_BASE;
const char *src;
- int flags;
spin_lock_irqsave(&host->csr.lock, flags);
/* entry in dv1394_cards */
struct list_head list;
- /* handle to /dev/ieee1394/dv/N, NULL if devfs not in use */
- devfs_handle_t devfs_handle;
-
/* OHCI card IT DMA context number, -1 if not in use */
int ohci_it_ctx;
struct ohci1394_iso_tasklet it_tasklet;
(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
(video->mode == MODE_RECEIVE ? "in" : "out"));
- video->devfs_handle = devfs_register(NULL, buf, 0, IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
- S_IFCHR | S_IRUGO | S_IWUGO,
- &dv1394_fops, video);
- if (video->devfs_handle == NULL) {
- printk(KERN_ERR "dv1394: unable to create /dev/%s\n", buf);
- return -ENOMEM;
- }
+ devfs_register(NULL, buf, 0, IEEE1394_MAJOR,
+ IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
+ S_IFCHR | S_IRUGO | S_IWUGO, &dv1394_fops, video);
return 0;
}
#endif /* CONFIG_DEVFS_FS */
#endif
}
-static void dv1394_add_host (struct hpsb_host *host)
+static void dv1394_add_host (struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct ti_ohci *ohci;
char buf[16];
printk(KERN_ERR fmt, ## args)
static char version[] __devinitdata =
- "$Rev: 806 $ Ben Collins <bcollins@debian.org>";
+ "$Rev: 886 $ Ben Collins <bcollins@debian.org>";
/* Our ieee1394 highlevel driver */
#define ETHER1394_DRIVER_NAME "ether1394"
static kmem_cache_t *packet_task_cache;
static struct hpsb_highlevel *hl_handle = NULL;
-/* Card handling */
-static LIST_HEAD (host_info_list);
-static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
/* Use common.lf to determine header len */
static int hdr_type_len[] = {
static void ether1394_iso(struct hpsb_iso *iso);
-/* Find our host_info struct for a given host pointer. Must be called
- * under spinlock. */
-static inline struct host_info *find_host_info (struct hpsb_host *host)
-{
- struct list_head *lh;
- struct host_info *hi;
-
- lh = host_info_list.next;
- while (lh != &host_info_list) {
- hi = list_entry (lh, struct host_info, list);
-
- if (hi->host == host)
- return hi;
-
- lh = lh->next;
- }
- return NULL;
-}
-
-/* Find the network device for our host */
-static inline struct net_device *ether1394_find_dev (struct hpsb_host *host)
-{
- struct host_info *hi;
-
- spin_lock_irq (&host_info_lock);
- hi = find_host_info (host);
- spin_unlock_irq (&host_info_lock);
-
- if (hi == NULL)
- return NULL;
-
- return hi->dev;
-}
-
/* This is called after an "ifup" */
static int ether1394_open (struct net_device *dev)
{
* when the module is installed. This is where we add all of our ethernet
* devices. One for each host.
*/
-static void ether1394_add_host (struct hpsb_host *host)
+static void ether1394_add_host (struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct host_info *hi = NULL;
struct net_device *dev = NULL;
priv->host = host;
- hi = (struct host_info *)kmalloc (sizeof (struct host_info),
- in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+ hi = hpsb_create_hostinfo(hl, host, sizeof(*hi));
if (hi == NULL)
goto out;
if (register_netdev (dev)) {
ETH1394_PRINT (KERN_ERR, dev->name, "Error registering network driver\n");
- kfree (dev);
- kfree (hi);
- return;
+ goto out;
}
ETH1394_PRINT (KERN_ERR, dev->name, "IEEE-1394 IPv4 over 1394 Ethernet (%s)\n",
host->driver->name);
- INIT_LIST_HEAD (&hi->list);
hi->host = host;
hi->dev = dev;
- spin_lock_irq (&host_info_lock);
- list_add_tail (&hi->list, &host_info_list);
- spin_unlock_irq (&host_info_lock);
-
/* Ignore validity in hopes that it will be set in the future. It'll
* check it on transmit. */
priv->broadcast_channel = host->csr.broadcast_channel & 0x3f;
out:
if (dev != NULL)
kfree (dev);
+ if (hi)
+ hpsb_destroy_hostinfo(hl, host);
+
ETH1394_PRINT_G (KERN_ERR, "Out of memory\n");
return;
/* Remove a card from our list */
static void ether1394_remove_host (struct hpsb_host *host)
{
- struct eth1394_priv *priv;
- struct host_info *hi;
+ struct host_info *hi = hpsb_get_hostinfo(hl_handle, host);
- spin_lock_irq (&host_info_lock);
- hi = find_host_info (host);
if (hi != NULL) {
- priv = (struct eth1394_priv *)hi->dev->priv;
+ struct eth1394_priv *priv = (struct eth1394_priv *)hi->dev->priv;
+
priv->bc_state = ETHER1394_BC_CLOSED;
unregister_netdev (hi->dev);
+ hpsb_iso_shutdown(priv->iso);
+
kfree (hi->dev);
- list_del (&hi->list);
- kfree (hi);
}
- spin_unlock_irq (&host_info_lock);
return;
}
/* A reset has just arisen */
static void ether1394_host_reset (struct hpsb_host *host)
{
- struct net_device *dev = ether1394_find_dev(host);
+ struct host_info *hi = hpsb_get_hostinfo(hl_handle, host);
+ struct net_device *dev;
/* This can happen for hosts that we don't use */
- if (dev == NULL)
+ if (hi == NULL)
return;
+ dev = hi->dev;
+
/* Reset our private host data, but not our mtu */
netif_stop_queue (dev);
ether1394_reset_priv (dev, 0);
struct sk_buff *skb;
char *buf = (char *)data;
unsigned long flags;
- struct net_device *dev = ether1394_find_dev (host);
+ struct host_info *hi = hpsb_get_hostinfo(hl_handle, host);
+ struct net_device *dev;
struct eth1394_priv *priv;
- if (dev == NULL) {
+ if (hi == NULL) {
ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %p\n",
host);
return RCODE_ADDRESS_ERROR;
}
+ dev = hi->dev;
+
priv = (struct eth1394_priv *)dev->priv;
/* A packet has been received by the ieee1394 bus. Build an skbuff
struct sk_buff *skb;
quadlet_t *data;
char *buf;
- int flags;
- struct net_device *dev = ether1394_find_dev(iso->host);
+ unsigned long flags;
+ struct host_info *hi = hpsb_get_hostinfo(hl_handle, iso->host);
+ struct net_device *dev;
struct eth1394_priv *priv;
unsigned int len;
u32 specifier_id;
int i;
int nready;
- if (dev == NULL) {
+ if (hi == NULL) {
ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n",
iso->host->driver->name);
return;
}
+ dev = hi->dev;
+
nready = hpsb_iso_n_ready(iso);
for(i = 0; i < nready; i++) {
struct hpsb_iso_packet_info *info = &iso->infos[iso->first_packet + i];
static void __exit ether1394_exit_module (void)
{
- struct list_head *lh;
- struct host_info *hi;
- struct eth1394_priv *priv;
-
- lh = host_info_list.next;
- while (lh != &host_info_list) {
- hi = list_entry (lh, struct host_info, list);
- priv = (struct eth1394_priv*)hi->dev->priv;
- if (priv->bc_state != ETHER1394_BC_CLOSED) {
- hpsb_iso_shutdown(priv->iso);
- }
- lh = lh->next;
- }
hpsb_unregister_highlevel (hl_handle);
kmem_cache_destroy(packet_task_cache);
}
};
struct host_info {
- struct list_head list;
struct hpsb_host *host;
struct net_device *dev;
};
#include <linux/config.h>
#include <linux/slab.h>
+#include <linux/list.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "highlevel.h"
-LIST_HEAD(hl_drivers);
+struct hl_host_info {
+ struct list_head list;
+ struct hpsb_host *host;
+ size_t size;
+ unsigned long key;
+ void *data;
+};
+
+
+static LIST_HEAD(hl_drivers);
static DECLARE_MUTEX(hl_drivers_lock);
-LIST_HEAD(addr_space);
-rwlock_t addr_space_lock = RW_LOCK_UNLOCKED;
+static LIST_HEAD(addr_space);
+static rwlock_t addr_space_lock = RW_LOCK_UNLOCKED;
/* addr_space list will have zero and max already included as bounds */
static struct hpsb_address_ops dummy_ops = { NULL, NULL, NULL, NULL };
static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr;
+
+/* Internal usage. Must be called with hl_drivers_lock held */
+static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
+ struct hpsb_host *host)
+{
+ struct hl_host_info *hi;
+ struct list_head *lh;
+
+ list_for_each (lh, &hl->host_info_list) {
+ hi = list_entry(lh, struct hl_host_info, list);
+ if (hi->host == host)
+ return hi;
+ }
+
+ return NULL;
+}
+
+
+/* Returns a per host/driver data structure that was previously stored by
+ * hpsb_create_hostinfo. */
+void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
+{
+ struct hl_host_info *hi;
+ void *data = NULL;
+
+ read_lock(&hl_drivers_lock);
+ hi = hl_get_hostinfo(hl, host);
+ if (hi)
+ data = hi->data;
+ read_unlock(&hl_drivers_lock);
+
+ return data;
+}
+
+
+/* If size is zero, then the return here is only valid for error checking */
+void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
+ size_t data_size)
+{
+ struct hl_host_info *hi;
+ void *data;
+
+ read_lock(&hl_drivers_lock);
+ hi = hl_get_hostinfo(hl, host);
+ read_unlock(&hl_drivers_lock);
+ if (hi) {
+ HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already exists",
+ hl->name);
+ return NULL;
+ }
+
+ hi = kmalloc(sizeof(*hi) + data_size, GFP_KERNEL);
+ if (!hi)
+ return NULL;
+
+ memset(hi, 0, sizeof(*hi) + data_size);
+
+ if (data_size) {
+ data = hi->data = hi + 1;
+ hi->size = data_size;
+ } else
+ data = hi;
+
+ hi->host = host;
+
+ write_lock_irq(&hl_drivers_lock);
+ list_add_tail(&hi->list, &hl->host_info_list);
+ write_unlock_irq(&hl_drivers_lock);
+
+ return data;
+}
+
+
+int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
+ void *data)
+{
+ struct hl_host_info *hi;
+ int ret = -EINVAL;
+
+ write_lock_irq(&hl_drivers_lock);
+ hi = hl_get_hostinfo(hl, host);
+ if (hi) {
+ if (!hi->size && !hi->data) {
+ hi->data = data;
+ ret = 0;
+ } else
+ HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo already has data",
+ hl->name);
+ } else
+ HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
+ hl->name);
+ write_unlock_irq(&hl_drivers_lock);
+
+ return ret;
+}
+
+
+void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
+{
+ struct hl_host_info *hi;
+
+ write_lock_irq(&hl_drivers_lock);
+ hi = hl_get_hostinfo(hl, host);
+ if (hi) {
+ list_del(&hi->list);
+ kfree(hi);
+ }
+ write_unlock_irq(&hl_drivers_lock);
+
+ return;
+}
+
+
+void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key)
+{
+ struct hl_host_info *hi;
+
+ write_lock(&hl_drivers_lock);
+ hi = hl_get_hostinfo(hl, host);
+ if (hi)
+ hi->key = key;
+ write_unlock(&hl_drivers_lock);
+
+ return;
+}
+
+
+unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host)
+{
+ struct hl_host_info *hi;
+ unsigned long key = 0;
+
+ read_lock(&hl_drivers_lock);
+ hi = hl_get_hostinfo(hl, host);
+ if (hi)
+ key = hi->key;
+ read_unlock(&hl_drivers_lock);
+
+ return key;
+}
+
+
+void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
+{
+ struct list_head *lh;
+ struct hl_host_info *hi;
+ void *data = NULL;
+
+ read_lock(&hl_drivers_lock);
+ list_for_each (lh, &hl->host_info_list) {
+ hi = list_entry(lh, struct hl_host_info, list);
+ if (hi->key == key) {
+ data = hi->data;
+ break;
+ }
+ }
+ read_unlock(&hl_drivers_lock);
+
+ return data;
+}
+
+
struct hpsb_highlevel *hpsb_register_highlevel(const char *name,
struct hpsb_highlevel_ops *ops)
{
struct hpsb_highlevel *hl;
+ struct list_head *lh;
hl = (struct hpsb_highlevel *)kmalloc(sizeof(struct hpsb_highlevel),
GFP_KERNEL);
INIT_LIST_HEAD(&hl->hl_list);
INIT_LIST_HEAD(&hl->addr_list);
+ INIT_LIST_HEAD(&hl->host_info_list);
+
hl->name = name;
hl->op = ops;
list_add_tail(&hl->hl_list, &hl_drivers);
up(&hl_drivers_lock);
- if (hl->op->add_host)
- hl_all_hosts(hl->op->add_host);
+ if (hl->op->add_host) {
+ down(&hpsb_hosts_lock);
+ list_for_each (lh, &hpsb_hosts) {
+ struct hpsb_host *host = list_entry(lh, struct hpsb_host, host_list);
+ hl->op->add_host(host, hl);
+ }
+ up(&hpsb_hosts_lock);
+ }
return hl;
}
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
{
- struct list_head *entry;
+ struct list_head *lh, *next;
struct hpsb_address_serve *as;
if (hl == NULL) {
}
write_lock_irq(&addr_space_lock);
- entry = hl->addr_list.next;
-
- while (entry != &hl->addr_list) {
- as = list_entry(entry, struct hpsb_address_serve, addr_list);
+ list_for_each_safe (lh, next, &hl->addr_list) {
+ as = list_entry(lh, struct hpsb_address_serve, addr_list);
list_del(&as->as_list);
- entry = entry->next;
kfree(as);
}
write_unlock_irq(&addr_space_lock);
list_del(&hl->hl_list);
up(&hl_drivers_lock);
- if (hl->op->remove_host)
- hl_all_hosts(hl->op->remove_host);
+ if (hl->op->remove_host) {
+ down(&hpsb_hosts_lock);
+ list_for_each(lh, &hpsb_hosts) {
+ struct hpsb_host *host = list_entry(lh, struct hpsb_host, host_list);
+
+ hl->op->remove_host(host);
+ hpsb_destroy_hostinfo(hl, host);
+ }
+ up(&hpsb_hosts_lock);
+ }
kfree(hl);
}
hl = list_entry(entry, struct hpsb_highlevel, hl_list);
if (hl->op->add_host)
- hl->op->add_host(host);
+ hl->op->add_host(host, hl);
}
up(&hl_drivers_lock);
}
list_for_each(entry, &hl_drivers) {
hl = list_entry(entry, struct hpsb_highlevel, hl_list);
- if (hl->op->remove_host)
+ if (hl->op->remove_host) {
hl->op->remove_host(host);
+ hpsb_destroy_hostinfo(hl, host);
+ }
}
up(&hl_drivers_lock);
}
const char *name;
struct hpsb_highlevel_ops *op;
+
+ /* Used by the highlevel drivers to store data per host */
+ struct list_head host_info_list;
};
/* New host initialized. Will also be called during
* hpsb_register_highlevel for all hosts already installed. */
- void (*add_host) (struct hpsb_host *host);
+ void (*add_host) (struct hpsb_host *host, struct hpsb_highlevel *hl);
/* Host about to be removed. Will also be called during
* hpsb_unregister_highlevel once for each host. */
void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
unsigned int channel);
+
+/* Retrieve a hostinfo pointer bound to this driver/host */
+void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
+/* Allocate a hostinfo pointer of data_size bound to this driver/host */
+void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
+ size_t data_size);
+/* Free and remove the hostinfo pointer bound to this driver/host */
+void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
+/* Set an alternate lookup key for the hostinfo bound to this driver/host */
+void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key);
+/* Retrieve the alternate lookup key for the hostinfo bound to this driver/host */
+unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host);
+/* Retrive a hostinfo pointer bound to this driver using its alternate key */
+void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
+/* Set the hostinfo pointer to something useful. Usually follows a call to
+ * hpsb_create_hostinfo, where the size is 0. */
+int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, void *data);
+
+
#endif /* IEEE1394_HIGHLEVEL_H */
#include "ieee1394_core.h"
#include "highlevel.h"
-static struct list_head hosts = LIST_HEAD_INIT(hosts);
-static struct list_head host_drivers = LIST_HEAD_INIT(host_drivers);
-
-spinlock_t hosts_lock = SPIN_LOCK_UNLOCKED;
-spinlock_t host_drivers_lock = SPIN_LOCK_UNLOCKED;
-
+LIST_HEAD(hpsb_hosts);
+DECLARE_MUTEX(hpsb_hosts_lock);
static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
{
int hpsb_ref_host(struct hpsb_host *host)
{
struct list_head *lh;
- unsigned long flags;
int retval = 0;
- spin_lock_irqsave(&hosts_lock, flags);
- list_for_each(lh, &hosts) {
+ down(&hpsb_hosts_lock);
+ list_for_each(lh, &hpsb_hosts) {
if (host == list_entry(lh, struct hpsb_host, host_list)) {
if (try_module_get(host->driver->owner)) {
host->refcount++;
break;
}
}
- spin_unlock_irqrestore(&hosts_lock, flags);
+ up(&hpsb_hosts_lock);
return retval;
}
void hpsb_unref_host(struct hpsb_host *host)
{
- unsigned long flags;
-
module_put(host->driver->owner);
- spin_lock_irqsave(&hosts_lock, flags);
+ down(&hpsb_hosts_lock);
host->refcount--;
if (!host->refcount && host->is_shutdown)
kfree(host);
- spin_unlock_irqrestore(&hosts_lock, flags);
+ up(&hpsb_hosts_lock);
}
/**
void hpsb_add_host(struct hpsb_host *host)
{
- unsigned long flags;
-
- spin_lock_irqsave(&hosts_lock, flags);
- list_add_tail(&host->host_list, &hosts);
- spin_unlock_irqrestore(&hosts_lock, flags);
+ down(&hpsb_hosts_lock);
+ list_add_tail(&host->host_list, &hpsb_hosts);
+ up(&hpsb_hosts_lock);
highlevel_add_host(host);
host->driver->devctl(host, RESET_BUS, LONG_RESET);
void hpsb_remove_host(struct hpsb_host *host)
{
- unsigned long flags;
-
+ down(&hpsb_hosts_lock);
host->is_shutdown = 1;
host->driver = &dummy_driver;
- highlevel_remove_host(host);
+ list_del(&host->host_list);
+ up(&hpsb_hosts_lock);
- spin_lock_irqsave(&hosts_lock, flags);
- list_del(&host->host_list);
- spin_unlock_irqrestore(&hosts_lock, flags);
-}
-
-/*
- * This function calls the given function for every host currently registered.
- */
-void hl_all_hosts(void (*function)(struct hpsb_host*))
-{
- struct list_head *lh;
- struct hpsb_host *host;
-
- spin_lock_irq(&hosts_lock);
- list_for_each (lh, &hosts) {
- host = list_entry(lh, struct hpsb_host, host_list);
- function(host);
- }
- spin_unlock_irq(&hosts_lock);
+ highlevel_remove_host(host);
}
quadlet_t data, quadlet_t compare);
};
-/* high level internal use */
-struct hpsb_highlevel;
-void hl_all_hosts(void (*function)(struct hpsb_host*));
+
+extern struct list_head hpsb_hosts;
+extern struct semaphore hpsb_hosts_lock;
/*
atomic_inc(&host->generation);
host->in_bus_reset = 0;
highlevel_host_reset(host);
-
- /* check for common cycle master error */
- hpsb_check_cycle_master(host);
-}
-
-
-void hpsb_check_cycle_master(struct hpsb_host *host)
-{
- /* check if host is IRM and not ROOT */
- if (host->is_irm && !host->is_root) {
- HPSB_NOTICE("Host is IRM but not root, resetting");
- if (host->reset_retries++ < 4) {
- /* selfid stage did not yield valid cycle master */
- hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
- } else {
- host->reset_retries = 0;
- HPSB_NOTICE("Stopping out-of-control reset loop");
- HPSB_NOTICE("Warning - Cycle Master not set correctly");
- }
- return;
- }
-
- host->reset_retries = 0;
}
hpsb_schedule_work(&host->timeout_tq);
}
+/**
+ * hpsb_send_phy_config - transmit a PHY configuration packet on the bus
+ * @host: host that PHY config packet gets sent through
+ * @rootid: root whose force_root bit should get set (-1 = don't set force_root)
+ * @gapcnt: gap count value to set (-1 = don't set gap count)
+ *
+ * This function sends a PHY config packet on the bus through the specified host.
+ *
+ * Return value: 0 for success or error number otherwise.
+ */
+int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt)
+{
+ struct hpsb_packet *packet;
+ int retval = 0;
+
+ if(rootid >= ALL_NODES || rootid < -1 || gapcnt > 0x3f || gapcnt < -1 ||
+ (rootid == -1 && gapcnt == -1)) {
+ HPSB_DEBUG("Invalid Parameter: rootid = %d gapcnt = %d",
+ rootid, gapcnt);
+ return -EINVAL;
+ }
+
+ packet = alloc_hpsb_packet(0);
+ if (!packet)
+ return -ENOMEM;
+
+ packet->host = host;
+ packet->header_size = 16;
+ packet->data_size = 0;
+ packet->expect_response = 0;
+ packet->no_waiter = 0;
+ packet->type = hpsb_raw;
+ packet->header[0] = 0;
+ if(rootid != -1)
+ packet->header[0] |= rootid << 24 | 1 << 23;
+ if(gapcnt != -1)
+ packet->header[0] |= gapcnt << 16 | 1 << 22;
+
+ packet->header[1] = ~packet->header[0];
+
+ packet->generation = get_hpsb_generation(host);
+
+ HPSB_DEBUG("Sending PHY configuration packet (I hope)...");
+ if (!hpsb_send_packet(packet)) {
+ retval = -EINVAL;
+ goto fail;
+ }
+
+ down(&packet->state_change);
+ down(&packet->state_change);
+
+fail:
+ free_hpsb_packet(packet);
+
+ return retval;
+}
+
/**
* hpsb_send_packet - transmit a packet on the bus
* @packet: packet to send
.open = ieee1394_dispatch_open,
};
-devfs_handle_t ieee1394_devfs_handle;
-
-
/* claim a block of minor numbers */
int ieee1394_register_chardev(int blocknum,
struct module *module,
hpsb_packet_cache = kmem_cache_create("hpsb_packet", sizeof(struct hpsb_packet),
0, 0, NULL, NULL);
- ieee1394_devfs_handle = devfs_mk_dir("ieee1394");
+ devfs_mk_dir("ieee1394");
if (register_chrdev(IEEE1394_MAJOR, "ieee1394", &ieee1394_chardev_ops)) {
HPSB_ERR("unable to register character device major %d!\n", IEEE1394_MAJOR);
- devfs_unregister(ieee1394_devfs_handle);
+ devfs_remove("ieee1394");
return -ENODEV;
}
if (ieee1394_procfs_entry == NULL) {
HPSB_ERR("unable to create /proc/bus/ieee1394\n");
unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
- devfs_unregister(ieee1394_devfs_handle);
+ devfs_remove("ieee1394");
return -ENOMEM;
}
ieee1394_procfs_entry->owner = THIS_MODULE;
kmem_cache_destroy(hpsb_packet_cache);
unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
-
- /* it's ok to pass a NULL devfs_handle to devfs_unregister */
- devfs_unregister(ieee1394_devfs_handle);
-
+ devfs_remove("ieee1394");
remove_proc_entry("ieee1394", proc_bus);
}
EXPORT_SYMBOL(hpsb_set_packet_complete_task);
EXPORT_SYMBOL(alloc_hpsb_packet);
EXPORT_SYMBOL(free_hpsb_packet);
+EXPORT_SYMBOL(hpsb_send_phy_config);
EXPORT_SYMBOL(hpsb_send_packet);
EXPORT_SYMBOL(hpsb_reset_bus);
EXPORT_SYMBOL(hpsb_bus_reset);
EXPORT_SYMBOL(hpsb_selfid_received);
EXPORT_SYMBOL(hpsb_selfid_complete);
-EXPORT_SYMBOL(hpsb_check_cycle_master);
EXPORT_SYMBOL(hpsb_packet_sent);
EXPORT_SYMBOL(hpsb_packet_received);
EXPORT_SYMBOL(ieee1394_register_chardev);
EXPORT_SYMBOL(ieee1394_unregister_chardev);
-EXPORT_SYMBOL(ieee1394_devfs_handle);
EXPORT_SYMBOL(ieee1394_procfs_entry);
/** ieee1394_transactions.c **/
EXPORT_SYMBOL(hpsb_unregister_addrspace);
EXPORT_SYMBOL(hpsb_listen_channel);
EXPORT_SYMBOL(hpsb_unlisten_channel);
+EXPORT_SYMBOL(hpsb_get_hostinfo);
+EXPORT_SYMBOL(hpsb_create_hostinfo);
+EXPORT_SYMBOL(hpsb_destroy_hostinfo);
+EXPORT_SYMBOL(hpsb_set_hostinfo_key);
+EXPORT_SYMBOL(hpsb_get_hostinfo_key);
+EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
+EXPORT_SYMBOL(hpsb_set_hostinfo);
EXPORT_SYMBOL(highlevel_read);
EXPORT_SYMBOL(highlevel_write);
EXPORT_SYMBOL(highlevel_lock);
EXPORT_SYMBOL(hpsb_iso_packet_sent);
EXPORT_SYMBOL(hpsb_iso_packet_received);
EXPORT_SYMBOL(hpsb_iso_wake);
-
return atomic_read(&host->generation);
}
+/*
+ * Send a PHY configuration packet.
+ */
+int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
+
/*
* Queue packet for transmitting, return 0 for failure.
*/
*/
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
-/*
- * Check bus reset results to find cycle master
- */
-void hpsb_check_cycle_master(struct hpsb_host *host);
-
-
/*
* Notify core of sending a packet. Ackcode is the ack code returned for async
* transmits or ACKX_SEND_ERROR if the transmission failed completely; ACKX_NONE
/* release a block of minor numbers */
void ieee1394_unregister_chardev(int blocknum);
-/* the devfs handle for /dev/ieee1394; NULL if devfs is not in use */
-extern devfs_handle_t ieee1394_devfs_handle;
-
/* the proc_fs entry for /proc/ieee1394 */
extern struct proc_dir_entry *ieee1394_procfs_entry;
static DECLARE_MUTEX(nodemgr_serialize);
-static LIST_HEAD(host_info_list);
-static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
+static struct hpsb_highlevel *nodemgr_hl;
struct host_info {
struct hpsb_host *host;
address += 4;
infop = (quadlet_t *) ud->quadlets;
- for (; length > 0; length--, address += 4, infop++) {
+ for (; length > 0; length--, address += 4) {
int code;
quadlet_t value;
quadlet_t *quadp;
CSR offsets for now. */
code &= CONFIG_ROM_KEY_TYPE_MASK;
if ((code & 0x80) == 0)
- *infop = quad;
+ *infop++ = quad;
break;
}
}
static int nodemgr_alloc_host_num(void)
{
- int hostnum = 0;
- unsigned long flags;
- struct list_head *lh;
-
- spin_lock_irqsave (&host_info_lock, flags);
-
- while (1) {
- int found = 0;
-
- list_for_each(lh, &host_info_list) {
- struct host_info *hi = list_entry(lh, struct host_info, list);
- if (hi->id == hostnum) {
- found = 1;
- break;
- }
- }
+ int hostnum;
- if (!found)
- break;
-
- hostnum++;
- }
-
- spin_unlock_irqrestore (&host_info_lock, flags);
+ for (hostnum = 0; hpsb_get_hostinfo_bykey(nodemgr_hl, hostnum); hostnum++)
+ /* Do nothing */;
return hostnum;
}
/* Because we are a 1394a-2000 compliant IRM, we need to inform all the other
* nodes of the broadcast channel. (Really we're only setting the validity
- * bit). */
+ * bit). Other IRM responsibilities go in here as well. */
static void nodemgr_do_irm_duties(struct hpsb_host *host)
{
quadlet_t bc;
hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host),
(CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
&bc, sizeof(quadlet_t));
+
+ /* If there is no bus manager then we should set the root node's
+ * force_root bit to promote bus stability per the 1394
+ * spec. (8.4.2.6) */
+ if(host->busmgr_id == 0x3f && host->node_count > 1)
+ {
+ u16 root_node = host->node_count - 1;
+ struct node_entry *ne = hpsb_nodeid_get_entry(host, root_node);
+
+ if(ne->busopt.cmc)
+ hpsb_send_phy_config(host, root_node, -1);
+ else {
+ HPSB_DEBUG("The root node is not cycle master capable; "
+ "selecting a new root node and resetting...");
+ hpsb_send_phy_config(host, host->node_id, -1);
+ hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
+ }
+ }
}
/* We need to ensure that if we are not the IRM, that the IRM node is capable of
* everything we can do, otherwise issue a bus reset and try to become the IRM
* ourselves. */
-static int nodemgr_check_root_capability(struct hpsb_host *host)
+static int nodemgr_check_irm_capability(struct hpsb_host *host)
{
quadlet_t bc;
int status;
&bc, sizeof(quadlet_t));
if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {
- /* The root node does not have a valid BROADCAST_CHANNEL
+ /* The current irm node does not have a valid BROADCAST_CHANNEL
* register and we do, so reset the bus with force_root set */
- HPSB_DEBUG("Remote root is not IRM capable, resetting...");
+ HPSB_DEBUG("Current remote IRM is not 1394a-2000 compliant, resetting...");
+ hpsb_send_phy_config(host, host->node_id, -1);
hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
return 0;
}
* for the read transactions, so that if another reset occurs
* during the scan the transactions will fail instead of
* returning bogus data. */
- generation = get_hpsb_generation(hi->host);
+ generation = get_hpsb_generation(host);
/* If we get a reset before we are done waiting, then
* start the the waiting over again */
i = HZ/4;
}
- if (!nodemgr_check_root_capability(host)) {
+ if (!nodemgr_check_irm_capability(host)) {
/* Do nothing, we are resetting */
up(&nodemgr_serialize);
continue;
addr, extcode, data, arg);
}
-static void nodemgr_add_host(struct hpsb_host *host)
+static void nodemgr_add_host(struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct host_info *hi;
- unsigned long flags;
- hi = kmalloc(sizeof (struct host_info), in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+ hi = hpsb_create_hostinfo(hl, host, sizeof(*hi));
if (!hi) {
HPSB_ERR ("NodeMgr: out of memory in add host");
/* Initialize the hostinfo here and start the thread. The
* thread blocks on the reset semaphore until a bus reset
* happens. */
- memset(hi, 0, sizeof(*hi));
hi->host = host;
- INIT_LIST_HEAD(&hi->list);
init_completion(&hi->exited);
sema_init(&hi->reset_sem, 0);
hi->id = nodemgr_alloc_host_num();
+ hpsb_set_hostinfo_key(hl, host, hi->id);
+
memcpy(&host->device, &nodemgr_dev_template_host,
sizeof(host->device));
host->device.parent = &host->pdev->dev;
sprintf(hi->daemon_name, "knodemgrd_%d", hi->id);
- spin_lock_irqsave (&host_info_lock, flags);
-
hi->pid = kernel_thread(nodemgr_host_thread, hi,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-
+
if (hi->pid < 0) {
HPSB_ERR ("NodeMgr: failed to start %s thread for %s",
hi->daemon_name, host->driver->name);
- kfree(hi);
- spin_unlock_irqrestore (&host_info_lock, flags);
+ hpsb_destroy_hostinfo(hl, host);
return;
}
- list_add_tail (&hi->list, &host_info_list);
-
- spin_unlock_irqrestore (&host_info_lock, flags);
-
return;
}
static void nodemgr_host_reset(struct hpsb_host *host)
{
- struct list_head *lh;
- struct host_info *hi = NULL;
- unsigned long flags;
-
- spin_lock_irqsave (&host_info_lock, flags);
- list_for_each(lh, &host_info_list) {
- struct host_info *myhi = list_entry(lh, struct host_info, list);
- if (myhi->host == host) {
- hi = myhi;
- break;
- }
- }
+ struct host_info *hi = hpsb_get_hostinfo(nodemgr_hl, host);
if (hi != NULL) {
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
#endif
up(&hi->reset_sem);
} else
- HPSB_ERR ("NodeMgr: could not process reset of non-existent host");
-
- spin_unlock_irqrestore (&host_info_lock, flags);
+ HPSB_ERR ("NodeMgr: could not process reset of unused host");
return;
}
static void nodemgr_remove_host(struct hpsb_host *host)
{
- struct list_head *lh, *next;
- unsigned long flags;
- struct host_info *hi = NULL;
-
- spin_lock_irqsave (&host_info_lock, flags);
- list_for_each_safe(lh, next, &host_info_list) {
- struct host_info *myhi = list_entry(lh, struct host_info, list);
- if (myhi->host == host) {
- list_del(&myhi->list);
- hi = myhi;
- break;
- }
- }
- spin_unlock_irqrestore (&host_info_lock, flags);
+ struct host_info *hi = hpsb_get_hostinfo(nodemgr_hl, host);
if (hi) {
if (hi->pid >= 0) {
nodemgr_remove_host_dev(&host->device);
device_unregister(&host->device);
}
- kfree(hi);
} else
HPSB_ERR("NodeMgr: host %s does not exist, cannot remove",
host->driver->name);
.remove_host = nodemgr_remove_host,
};
-static struct hpsb_highlevel *hl;
-
void init_ieee1394_nodemgr(void)
{
bus_register(&ieee1394_bus_type);
- hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);
- if (!hl) {
+ nodemgr_hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);
+ if (!nodemgr_hl) {
HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization");
}
}
void cleanup_ieee1394_nodemgr(void)
{
- hpsb_unregister_highlevel(hl);
+ hpsb_unregister_highlevel(nodemgr_hl);
bus_unregister(&ieee1394_bus_type);
}
printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
static char version[] __devinitdata =
- "$Rev: 858 $ Ben Collins <bcollins@debian.org>";
+ "$Rev: 866 $ Ben Collins <bcollins@debian.org>";
/* Module Parameters */
static int phys_dma = 1;
#define DBGMSG(fmt, args...)
#endif
-static devfs_handle_t devfs_handle;
-
static LIST_HEAD(host_info_list);
static int host_count;
static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
}
-static void add_host(struct hpsb_host *host)
+static void add_host(struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct host_info *hi;
unsigned long flags;
- hi = (struct host_info *)kmalloc(sizeof(struct host_info),
- in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+ hi = (struct host_info *)kmalloc(sizeof(struct host_info), GFP_KERNEL);
+
if (hi != NULL) {
INIT_LIST_HEAD(&hi->list);
hi->host = host;
return -ENOMEM;
}
- devfs_handle = devfs_register(NULL,
- RAW1394_DEVICE_NAME, DEVFS_FL_NONE,
- IEEE1394_MAJOR,
- IEEE1394_MINOR_BLOCK_RAW1394 * 16,
- S_IFCHR | S_IRUSR | S_IWUSR, &file_ops,
- NULL);
+ devfs_register(NULL, RAW1394_DEVICE_NAME, 0,
+ IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16,
+ S_IFCHR | S_IRUSR | S_IWUSR, &file_ops, NULL);
if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
THIS_MODULE, &file_ops)) {
HPSB_ERR("raw1394 failed to register minor device block");
- devfs_unregister(devfs_handle);
+ devfs_remove(RAW1394_DEVICE_NAME);
hpsb_unregister_highlevel(hl_handle);
return -EBUSY;
}
{
hpsb_unregister_protocol(&raw1394_driver);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
- devfs_unregister(devfs_handle);
+ devfs_remove(RAW1394_DEVICE_NAME);
hpsb_unregister_highlevel(hl_handle);
}
#include "sbp2.h"
static char version[] __devinitdata =
- "$Rev: 846 $ James Goodwin <jamesg@filanet.com>";
+ "$Rev: 884 $ James Goodwin <jamesg@filanet.com>";
/*
* Module load parameter definitions
static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };
-static LIST_HEAD(sbp2_host_info_list);
-
-static spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED;
-
static struct hpsb_highlevel *sbp2_hl_handle = NULL;
static struct hpsb_highlevel_ops sbp2_hl_ops = {
static void sbp2util_free_command_dma(struct sbp2_command_info *command)
{
struct sbp2scsi_host_info *hi;
-
- hi = (struct sbp2scsi_host_info *)&command->Current_SCpnt->device->host->hostdata;
- if (hi == NULL) {
+ hi = hpsb_get_hostinfo_bykey(sbp2_hl_handle, (unsigned long)command->Current_SCpnt->device->host);
+ if (!hi) {
printk(KERN_ERR "%s: hi == NULL\n", __FUNCTION__);
return;
}
static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host)
{
struct sbp2scsi_host_info *hi;
- unsigned long flags;
struct Scsi_Host *scsi_host;
SBP2_DEBUG("sbp2_add_host");
- hi = sbp2_find_host_info(host);
+ hi = hpsb_get_hostinfo(sbp2_hl_handle, host);
if (hi)
return hi;
/* Register our host with the SCSI stack. */
- scsi_host = scsi_register (&scsi_driver_template, sizeof(struct sbp2scsi_host_info));
+ scsi_host = scsi_register (&scsi_driver_template, 0);
if (!scsi_host) {
SBP2_ERR("failed to register scsi host");
return NULL;
}
- hi = (struct sbp2scsi_host_info *)&scsi_host->hostdata;
- memset(hi, 0, sizeof(struct sbp2scsi_host_info));
+ hi = hpsb_create_hostinfo(sbp2_hl_handle, host, sizeof(*hi));
+ if (!hi) {
+ SBP2_ERR("failed to allocate hostinfo");
+ scsi_unregister(hi->scsi_host);
+ }
+
+ hpsb_set_hostinfo_key(sbp2_hl_handle, host, (unsigned long)scsi_host);
hi->scsi_host = scsi_host;
- INIT_LIST_HEAD(&hi->list);
hi->host = host;
hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED;
hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS;
- spin_lock_irqsave(&sbp2_host_info_lock, flags);
- list_add_tail(&hi->list, &sbp2_host_info_list);
- spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
-
/* XXX We need a device to pass here as the scsi-host class. Can't
* use the PCI device, since it is already bound to the ieee1394
* host. Can't use the fw-host device since it is multi-class
* enabled (scsi-host uses classdata member of the device). */
if (scsi_add_host(hi->scsi_host, NULL)) {
SBP2_ERR("failed to add scsi host");
-
- spin_lock_irqsave(&sbp2_host_info_lock, flags);
- list_del(&hi->list);
- spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
-
scsi_unregister(hi->scsi_host);
+ hpsb_destroy_hostinfo(sbp2_hl_handle, host);
}
return hi;
}
-/*
- * This fuction returns a host info structure from the host structure, in
- * case we have multiple hosts.
- */
-static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host)
-{
- struct list_head *lh;
- struct sbp2scsi_host_info *hi;
-
- list_for_each (lh, &sbp2_host_info_list) {
- hi = list_entry(lh, struct sbp2scsi_host_info, list);
- if (hi->host == host)
- return hi;
- }
-
- return NULL;
-}
-
-/*
- * This function returns a host info structure for a given Scsi_Host
- * struct.
- */
-static struct sbp2scsi_host_info *sbp2_find_host_info_scsi(struct Scsi_Host *host)
-{
- struct list_head *lh;
- struct sbp2scsi_host_info *hi;
-
- list_for_each (lh, &sbp2_host_info_list) {
- hi = list_entry(lh, struct sbp2scsi_host_info, list);
- if (hi->scsi_host == host)
- return hi;
- }
-
- return NULL;
-}
/*
* This function is called when a host is removed.
static void sbp2_remove_host(struct hpsb_host *host)
{
struct sbp2scsi_host_info *hi;
- unsigned long flags;
SBP2_DEBUG("sbp2_remove_host");
- spin_lock_irqsave(&sbp2_host_info_lock, flags);
- hi = sbp2_find_host_info(host);
- if (hi)
- list_del(&hi->list);
- spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
+ hi = hpsb_get_hostinfo(sbp2_hl_handle, host);
if (hi) {
scsi_remove_host(hi->scsi_host);
scsi_unregister(hi->scsi_host);
- }
+ } else
+ SBP2_ERR("attempt to remove unknown host %p", host);
}
/*
return(RCODE_ADDRESS_ERROR);
}
- spin_lock_irqsave(&sbp2_host_info_lock, flags);
- hi = sbp2_find_host_info(host);
- spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
+ hi = hpsb_get_hostinfo(sbp2_hl_handle, host);
if (!hi) {
SBP2_ERR("host info is NULL - this is bad!");
/*
* Pull our host info and scsi id instance data from the scsi command
*/
- hi = (struct sbp2scsi_host_info *) &SCpnt->device->host->hostdata;
+ hi = hpsb_get_hostinfo_bykey(sbp2_hl_handle, (unsigned long)SCpnt->device->host);
if (!hi) {
SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!");
*/
static int sbp2scsi_abort (Scsi_Cmnd *SCpnt)
{
- struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)&SCpnt->device->host->hostdata;
+ struct sbp2scsi_host_info *hi = hpsb_get_hostinfo_bykey(sbp2_hl_handle,
+ (unsigned long)SCpnt->device->host);
struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->device->id];
struct sbp2_command_info *command;
unsigned long flags;
*/
static int sbp2scsi_reset (Scsi_Cmnd *SCpnt)
{
- struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)&SCpnt->device->host->hostdata;
+ struct sbp2scsi_host_info *hi = hpsb_get_hostinfo_bykey(sbp2_hl_handle,
+ (unsigned long)SCpnt->device->host);
struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->device->id];
SBP2_ERR("reset requested");
if (!host) /* if we couldn't find it, we return an error */
return -ESRCH;
- hi = sbp2_find_host_info_scsi(host);
+ hi = hpsb_get_hostinfo_bykey(sbp2_hl_handle, (unsigned long)host);
if (!hi) /* shouldn't happen, but... */
return -ESRCH;
* Sbp2 host data structure (one per sbp2 host)
*/
struct sbp2scsi_host_info {
-
- /*
- * For use in keeping track of hosts
- */
- struct list_head list;
struct hpsb_host *host;
/*
* IEEE-1394 core driver related prototypes
*/
static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host);
-static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host);
static void sbp2_remove_host(struct hpsb_host *host);
static int sbp2_probe(struct device *dev);
struct list_head link;
};
-struct video_card {
- struct ti_ohci *ohci;
- struct list_head list;
- int id;
- devfs_handle_t devfs;
-};
-
struct file_ctx {
- struct video_card *video;
+ struct ti_ohci *ohci;
struct list_head context_list;
struct dma_iso_ctx *current_ctx;
};
void wakeup_dma_ir_ctx(unsigned long l);
void wakeup_dma_it_ctx(unsigned long l);
-static LIST_HEAD(video1394_cards);
-static spinlock_t video1394_cards_lock = SPIN_LOCK_UNLOCKED;
-
-static devfs_handle_t devfs_handle;
static struct hpsb_highlevel *hl_handle = NULL;
unsigned int cmd, unsigned long arg)
{
struct file_ctx *ctx = (struct file_ctx *)file->private_data;
- struct video_card *video = ctx->video;
- struct ti_ohci *ohci = video->ohci;
+ struct ti_ohci *ohci = ctx->ohci;
unsigned long flags;
switch(cmd)
lock_kernel();
if (ctx->current_ctx == NULL) {
- PRINT(KERN_ERR, ctx->video->ohci->id, "Current iso context not set");
+ PRINT(KERN_ERR, ctx->ohci->id, "Current iso context not set");
} else
res = dma_region_mmap(&ctx->current_ctx->dma, file, vma);
unlock_kernel();
static int video1394_open(struct inode *inode, struct file *file)
{
int i = ieee1394_file_to_instance(file);
- unsigned long flags;
- struct video_card *video = NULL;
- struct list_head *lh;
+ struct ti_ohci *ohci;
struct file_ctx *ctx;
- spin_lock_irqsave(&video1394_cards_lock, flags);
- list_for_each(lh, &video1394_cards) {
- struct video_card *p = list_entry(lh, struct video_card, list);
- if (p->id == i) {
- video = p;
- break;
- }
- }
- spin_unlock_irqrestore(&video1394_cards_lock, flags);
-
- if (video == NULL)
+ ohci = hpsb_get_hostinfo_bykey(hl_handle, i);
+ if (ohci == NULL)
return -EIO;
ctx = kmalloc(sizeof(struct file_ctx), GFP_KERNEL);
if (ctx == NULL) {
- PRINT(KERN_ERR, video->ohci->id, "Cannot malloc file_ctx");
+ PRINT(KERN_ERR, ohci->id, "Cannot malloc file_ctx");
return -ENOMEM;
}
memset(ctx, 0, sizeof(struct file_ctx));
- ctx->video = video;
+ ctx->ohci = ohci;
INIT_LIST_HEAD(&ctx->context_list);
ctx->current_ctx = NULL;
file->private_data = ctx;
static int video1394_release(struct inode *inode, struct file *file)
{
struct file_ctx *ctx = (struct file_ctx *)file->private_data;
- struct video_card *video = ctx->video;
- struct ti_ohci *ohci = video->ohci;
+ struct ti_ohci *ohci = ctx->ohci;
struct list_head *lh, *next;
u64 mask;
};
-static int video1394_init(struct ti_ohci *ohci)
-{
- struct video_card *video;
- unsigned long flags;
- char name[24];
- int minor;
-
- video = kmalloc(sizeof(struct video_card), GFP_KERNEL);
- if (video == NULL) {
- PRINT(KERN_ERR, ohci->id, "Cannot allocate video_card");
- return -1;
- }
-
- memset(video, 0, sizeof(struct video_card));
-
- spin_lock_irqsave(&video1394_cards_lock, flags);
- INIT_LIST_HEAD(&video->list);
- list_add_tail(&video->list, &video1394_cards);
- spin_unlock_irqrestore(&video1394_cards_lock, flags);
-
- video->id = ohci->id;
- video->ohci = ohci;
-
- sprintf(name, "%s/%d", VIDEO1394_DRIVER_NAME, video->id);
- minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + video->id;
- video->devfs = devfs_register(NULL, name, DEVFS_FL_DEFAULT,
- IEEE1394_MAJOR, minor,
- S_IFCHR | S_IRUSR | S_IWUSR,
- &video1394_fops, NULL);
-
- return 0;
-}
-
-/* Must be called under spinlock */
-static void remove_card(struct video_card *video)
-{
- devfs_unregister(video->devfs);
- list_del(&video->list);
-
- kfree(video);
-}
-
-static void video1394_remove_host (struct hpsb_host *host)
+static void video1394_add_host (struct hpsb_host *host, struct hpsb_highlevel *hl)
{
struct ti_ohci *ohci;
- unsigned long flags;
- struct list_head *lh, *next;
- struct video_card *p;
+ char name[16];
+ int minor;
/* We only work with the OHCI-1394 driver */
if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
ohci = (struct ti_ohci *)host->hostdata;
- spin_lock_irqsave(&video1394_cards_lock, flags);
- list_for_each_safe(lh, next, &video1394_cards) {
- p = list_entry(lh, struct video_card, list);
- if (p->ohci == ohci) {
- remove_card(p);
- break;
- }
+ if (!hpsb_create_hostinfo(hl, host, 0)) {
+ PRINT(KERN_ERR, ohci->id, "Cannot allocate hostinfo");
+ return;
}
- spin_unlock_irqrestore(&video1394_cards_lock, flags);
+
+ hpsb_set_hostinfo(hl, host, ohci);
+ hpsb_set_hostinfo_key(hl, host, ohci->id);
+
+ sprintf(name, "%s/%d", VIDEO1394_DRIVER_NAME, ohci->id);
+ minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->id;
+ devfs_register(NULL, name, 0, IEEE1394_MAJOR, minor,
+ S_IFCHR | S_IRUSR | S_IWUSR, &video1394_fops, NULL);
return;
}
-static void video1394_add_host (struct hpsb_host *host)
-{
- struct ti_ohci *ohci;
- /* We only work with the OHCI-1394 driver */
- if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
- return;
+static void video1394_remove_host (struct hpsb_host *host)
+{
+ struct ti_ohci *ohci = hpsb_get_hostinfo(hl_handle, host);
- ohci = (struct ti_ohci *)host->hostdata;
+ if (ohci)
+ devfs_remove("%s/%d", VIDEO1394_DRIVER_NAME, ohci->id);
- video1394_init(ohci);
-
return;
}
+
static struct hpsb_highlevel_ops hl_ops = {
.add_host = video1394_add_host,
.remove_host = video1394_remove_host,
hpsb_unregister_highlevel (hl_handle);
- devfs_unregister(devfs_handle);
+ devfs_remove(VIDEO1394_DRIVER_NAME);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
return -EIO;
}
- devfs_handle = devfs_mk_dir(VIDEO1394_DRIVER_NAME);
+ devfs_mk_dir(VIDEO1394_DRIVER_NAME);
hl_handle = hpsb_register_highlevel (VIDEO1394_DRIVER_NAME, &hl_ops);
if (hl_handle == NULL) {
PRINT_G(KERN_ERR, "No more memory for driver\n");
- devfs_unregister(devfs_handle);
+ devfs_remove(VIDEO1394_DRIVER_NAME);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
return -ENOMEM;
}