#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
+#include <linux/ioctl32.h>
+#include <linux/compat.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
static int __init amdtp_init_module (void)
{
- if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP,
- THIS_MODULE, &amdtp_fops)) {
+ int ret;
+
+ ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_AMDTP,
+ THIS_MODULE, &amdtp_fops);
+ if (ret) {
HPSB_ERR("amdtp: unable to get minor device block");
return -EIO;
}
return -EIO;
}
+#ifdef CONFIG_COMPAT
+ ret = register_ioctl32_conversion(AMDTP_IOC_CHANNEL, NULL);
+ ret |= register_ioctl32_conversion(AMDTP_IOC_PLUG, NULL);
+ ret |= register_ioctl32_conversion(AMDTP_IOC_PING, NULL);
+ ret |= register_ioctl32_conversion(AMDTP_IOC_ZAP, NULL);
+ if (ret)
+ HPSB_ERR("amdtp: Error registering ioctl32 translations");
+#endif
+
HPSB_INFO("Loaded AMDTP driver");
return 0;
static void __exit amdtp_exit_module (void)
{
+#ifdef CONFIG_COMPAT
+ int ret;
+
+ ret = unregister_ioctl32_conversion(AMDTP_IOC_CHANNEL);
+ ret |= unregister_ioctl32_conversion(AMDTP_IOC_PLUG);
+ ret |= unregister_ioctl32_conversion(AMDTP_IOC_PING);
+ ret |= unregister_ioctl32_conversion(AMDTP_IOC_ZAP);
+ if (ret)
+ HPSB_ERR("amdtp: Error unregistering ioctl32 translations");
+#endif
+
hpsb_unregister_highlevel(amdtp_highlevel);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_AMDTP);
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#include <linux/mm.h>
#include "dma.h"
/* dma_prog_region */
#include <linux/wrapper.h>
#include <linux/vmalloc.h>
#include <linux/string.h>
+#include <linux/ioctl32.h>
+#include <linux/compat.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
.host_reset = dv1394_host_reset,
};
+#ifdef CONFIG_COMPAT
+
+#define DV1394_IOC32_INIT _IOW('#', 0x06, struct dv1394_init32)
+#define DV1394_IOC32_GET_STATUS _IOR('#', 0x0c, struct dv1394_status32)
+
+struct dv1394_init32 {
+ u32 api_version;
+ u32 channel;
+ u32 n_frames;
+ u32 format;
+ u32 cip_n;
+ u32 cip_d;
+ u32 syt_offset;
+};
+
+struct dv1394_status32 {
+ struct dv1394_init32 init;
+ s32 active_frame;
+ u32 first_clear_frame;
+ u32 n_clear_frames;
+ u32 dropped_frames;
+};
+
+static int handle_dv1394_init(unsigned int fd, unsigned int cmd, unsigned long arg,
+ struct file *file)
+{
+ struct dv1394_init32 dv32;
+ struct dv1394_init dv;
+ mm_segment_t old_fs;
+ int ret;
+
+ if (file->f_op->ioctl != dv1394_ioctl)
+ return -EFAULT;
+
+ if (copy_from_user(&dv32, (void *)arg, sizeof(dv32)))
+ return -EFAULT;
+
+ dv.api_version = dv32.api_version;
+ dv.channel = dv32.channel;
+ dv.n_frames = dv32.n_frames;
+ dv.format = dv32.format;
+ dv.cip_n = (unsigned long)dv32.cip_n;
+ dv.cip_d = (unsigned long)dv32.cip_d;
+ dv.syt_offset = dv32.syt_offset;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = dv1394_ioctl(file->f_dentry->d_inode, file,
+ DV1394_IOC_INIT, (unsigned long)&dv);
+ set_fs(old_fs);
+
+ return ret;
+}
+
+static int handle_dv1394_get_status(unsigned int fd, unsigned int cmd, unsigned long arg,
+ struct file *file)
+{
+ struct dv1394_status32 dv32;
+ struct dv1394_status dv;
+ mm_segment_t old_fs;
+ int ret;
+
+ if (file->f_op->ioctl != dv1394_ioctl)
+ return -EFAULT;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = dv1394_ioctl(file->f_dentry->d_inode, file,
+ DV1394_IOC_GET_STATUS, (unsigned long)&dv);
+ set_fs(old_fs);
+
+ if (!ret) {
+ dv32.init.api_version = dv.init.api_version;
+ dv32.init.channel = dv.init.channel;
+ dv32.init.n_frames = dv.init.n_frames;
+ dv32.init.format = dv.init.format;
+ dv32.init.cip_n = (u32)dv.init.cip_n;
+ dv32.init.cip_d = (u32)dv.init.cip_d;
+ dv32.init.syt_offset = dv.init.syt_offset;
+ dv32.active_frame = dv.active_frame;
+ dv32.first_clear_frame = dv.first_clear_frame;
+ dv32.n_clear_frames = dv.n_clear_frames;
+ dv32.dropped_frames = dv.dropped_frames;
+
+ if (copy_to_user((struct dv1394_status32 *)arg, &dv32, sizeof(dv32)))
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+#endif /* CONFIG_COMPAT */
+
/*** KERNEL MODULE HANDLERS ************************************************/
static void __exit dv1394_exit_module(void)
{
+#ifdef CONFIG_COMPAT
+ int ret;
+
+ ret = unregister_ioctl32_conversion(DV1394_IOC_SHUTDOWN);
+ ret |= unregister_ioctl32_conversion(DV1394_IOC_SUBMIT_FRAMES);
+ ret |= unregister_ioctl32_conversion(DV1394_IOC_WAIT_FRAMES);
+ ret |= unregister_ioctl32_conversion(DV1394_IOC_RECEIVE_FRAMES);
+ ret |= unregister_ioctl32_conversion(DV1394_IOC_START_RECEIVE);
+ ret |= unregister_ioctl32_conversion(DV1394_IOC32_INIT);
+ ret |= unregister_ioctl32_conversion(DV1394_IOC32_GET_STATUS);
+ if (ret)
+ printk(KERN_ERR "dv1394: Error unregistering ioctl32 translations\n");
+#endif
+
hpsb_unregister_highlevel (hl_handle);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
#ifdef CONFIG_DEVFS_FS
static int __init dv1394_init_module(void)
{
- if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394,
- THIS_MODULE, &dv1394_fops)) {
+ int ret;
+
+ ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_DV1394,
+ THIS_MODULE, &dv1394_fops);
+ if (ret) {
printk(KERN_ERR "dv1394: unable to register character device\n");
return -EIO;
}
#ifdef CONFIG_DEVFS_FS
- if (dv1394_devfs_add_dir("dv", NULL, NULL) < 0) {
+ ret = dv1394_devfs_add_dir("dv", NULL, NULL);
+ if (ret < 0) {
printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/dv\n");
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
return -ENOMEM;
#endif
#ifdef CONFIG_PROC_FS
- if (dv1394_procfs_add_dir("dv",NULL,NULL) < 0) {
+ ret = dv1394_procfs_add_dir("dv",NULL,NULL);
+ if (ret < 0) {
printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv\n");
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
#ifdef CONFIG_DEVFS_FS
return -ENOMEM;
}
+#ifdef CONFIG_COMPAT
+ /* First compatible ones */
+ ret = register_ioctl32_conversion(DV1394_IOC_SHUTDOWN, NULL);
+ ret |= register_ioctl32_conversion(DV1394_IOC_SUBMIT_FRAMES, NULL);
+ ret |= register_ioctl32_conversion(DV1394_IOC_WAIT_FRAMES, NULL);
+ ret |= register_ioctl32_conversion(DV1394_IOC_RECEIVE_FRAMES, NULL);
+ ret |= register_ioctl32_conversion(DV1394_IOC_START_RECEIVE, NULL);
+
+ /* These need to be handled by translation */
+ ret |= register_ioctl32_conversion(DV1394_IOC32_INIT, handle_dv1394_init);
+ ret |= register_ioctl32_conversion(DV1394_IOC32_GET_STATUS, handle_dv1394_get_status);
+ if (ret)
+ printk(KERN_ERR "dv1394: Error registering ioctl32 translations\n");
+#endif
+
return 0;
}
module_init(dv1394_init_module);
module_exit(dv1394_exit_module);
-
#include "ieee1394_transactions.h"
#include "ieee1394.h"
#include "highlevel.h"
+#include "iso.h"
#include "eth1394.h"
#define ETH1394_PRINT_G(level, fmt, args...) \
printk(KERN_ERR fmt, ## args)
static char version[] __devinitdata =
- "$Rev: 770 $ Ben Collins <bcollins@debian.org>";
+ "$Rev: 801 $ Ben Collins <bcollins@debian.org>";
/* Our ieee1394 highlevel driver */
#define ETHER1394_DRIVER_NAME "ether1394"
MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");
MODULE_LICENSE("GPL");
+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)
* XXX: This is where we need to create a list of skb's for fragmented
* packets. */
static inline void ether1394_encapsulate (struct sk_buff *skb, struct net_device *dev,
- int proto)
+ int proto, struct packet_task *ptask)
{
union eth1394_hdr *hdr =
(union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]);
+ hdr->words.word1 = 0;
hdr->common.lf = ETH1394_HDR_LF_UF;
hdr->words.word1 = htons(hdr->words.word1);
hdr->uf.ether_type = proto;
+ /* Set the transmission type for the packet. Right now only ARP
+ * packets are sent via GASP. IP broadcast and IP multicast are not
+ * yet supported properly, they too should use GASP. */
+ switch(proto) {
+ case __constant_htons(ETH_P_ARP):
+ ptask->tx_type = ETH1394_GASP;
+ break;
+ default:
+ ptask->tx_type = ETH1394_WRREQ;
+ }
return;
}
{
struct eth1394_priv *priv =
(struct eth1394_priv *)(dev->priv);
- u16 phy_id = priv->host->node_id & NODE_MASK;
+ u16 phy_id = NODEID_TO_NODE(priv->host->node_id);
unsigned char *arp_ptr = (unsigned char *)skb->data;
struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data;
{
unsigned long flags;
struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
- int phy_id = priv->host->node_id & NODE_MASK;
+ int phy_id = NODEID_TO_NODE(priv->host->node_id);
+ struct hpsb_host *host = priv->host;
spin_lock_irqsave (&priv->lock, flags);
memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi));
memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo));
+ priv->bc_state = ETHER1394_BC_CHECK;
+
/* Register our limits now */
- ether1394_register_limits (phy_id, (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf,
- priv->host->speed_map[(phy_id << 6) + phy_id],
- (u64)(((u64)be32_to_cpu(priv->host->csr.rom[3]) << 32) |
- be32_to_cpu(priv->host->csr.rom[4])),
+ ether1394_register_limits (phy_id, (be32_to_cpu(host->csr.rom[2]) >> 12) & 0xf,
+ host->speed_map[(phy_id << 6) + phy_id],
+ (u64)(((u64)be32_to_cpu(host->csr.rom[3]) << 32) |
+ be32_to_cpu(host->csr.rom[4])),
ETHER1394_REGION_ADDR >> 32,
ETHER1394_REGION_ADDR & 0xffffffff, priv);
/* We'll use our max_rec as the default mtu */
if (set_mtu)
- dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - sizeof (union eth1394_hdr);
+ dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - /* mtu = max_rec - */
+ (sizeof (union eth1394_hdr) + 8); /* (hdr + GASP) */
/* Set our hardware address while we're at it */
- *(nodeid_t *)dev->dev_addr = htons (priv->host->node_id);
+ *(nodeid_t *)dev->dev_addr = htons (host->node_id);
spin_unlock_irqrestore (&priv->lock, flags);
}
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;
+
+ priv->iso = hpsb_iso_recv_init(host, 8 * 4096, 8, priv->broadcast_channel,
+ 1, ether1394_iso);
+ if (priv->iso == NULL) {
+ priv->bc_state = ETHER1394_BC_CLOSED;
+ }
return;
out:
/* Remove a card from our list */
static void ether1394_remove_host (struct hpsb_host *host)
{
+ struct eth1394_priv *priv;
struct host_info *hi;
spin_lock_irq (&host_info_lock);
hi = find_host_info (host);
if (hi != NULL) {
+ priv = (struct eth1394_priv *)hi->dev->priv;
+ priv->bc_state = ETHER1394_BC_CLOSED;
unregister_netdev (hi->dev);
kfree (hi->dev);
list_del (&hi->list);
* about the sending machine. */
if (hdr->uf.ether_type == __constant_htons (ETH_P_ARP)) {
unsigned long flags;
- u16 phy_id = srcid & NODE_MASK;
+ u16 phy_id = NODEID_TO_NODE(srcid);
struct eth1394_priv *priv =
(struct eth1394_priv *)dev->priv;
struct eth1394_arp arp1394;
return RCODE_COMPLETE;
}
+static void ether1394_iso(struct hpsb_iso *iso)
+{
+ struct sk_buff *skb;
+ quadlet_t *data;
+ char *buf;
+ int flags;
+ struct net_device *dev = ether1394_find_dev(iso->host);
+ struct eth1394_priv *priv;
+ unsigned int len;
+ u32 specifier_id;
+ u16 source_id;
+ int i;
+ int nready;
+
+ if (dev == NULL) {
+ ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n",
+ iso->host->driver->name);
+ return;
+ }
+
+ nready = hpsb_iso_n_ready(iso);
+ for(i = 0; i < nready; i++) {
+ struct hpsb_iso_packet_info *info = &iso->infos[iso->first_packet + i];
+ data = (quadlet_t*) (iso->data_buf.kvirt + info->offset);
+
+ /* skip over GASP header */
+ buf = (char *)data + 8;
+ len = info->len - 8;
+
+ specifier_id = (((be32_to_cpu(data[0]) & 0xffff) << 8) |
+ ((be32_to_cpu(data[1]) & 0xff000000) >> 24));
+ source_id = be32_to_cpu(data[0]) >> 16;
+
+ priv = (struct eth1394_priv *)dev->priv;
+
+ if (info->channel != priv->broadcast_channel ||
+ specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
+ /* This packet is not for us */
+ continue;
+ }
+
+ /* A packet has been received by the ieee1394 bus. Build an skbuff
+ * around it so we can pass it to the high level network layer. */
+ skb = dev_alloc_skb (len + dev->hard_header_len + 15);
+ if (!skb) {
+ HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n");
+ priv->stats.rx_dropped++;
+ break;
+ }
+
+ skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
+
+ memcpy (skb_put (skb, len), buf, len);
+
+ /* Write metadata, and then pass to the receive level */
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */
+
+ /* Parse the encapsulation header. This actually does the job of
+ * converting to an ethernet frame header, aswell as arp
+ * conversion if needed. ARP conversion is easier in this
+ * direction, since we are using ethernet as our backend. */
+ skb->protocol = ether1394_parse_encap (skb, dev, source_id,
+ LOCAL_BUS | ALL_NODES);
+
+ spin_lock_irqsave (&priv->lock, flags);
+ if (!skb->protocol) {
+ priv->stats.rx_errors++;
+ priv->stats.rx_dropped++;
+ dev_kfree_skb_any(skb);
+ goto bad_proto;
+ }
+
+ netif_stop_queue(dev);
+ if (netif_rx (skb) == NET_RX_DROP) {
+ priv->stats.rx_errors++;
+ priv->stats.rx_dropped++;
+ goto bad_proto;
+ }
+
+ /* Statistics */
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += skb->len;
+
+ bad_proto:
+ spin_unlock_irqrestore (&priv->lock, flags);
+ }
+
+ hpsb_iso_recv_release_packets(iso, i);
+
+ netif_start_queue(dev);
+
+ dev->last_rx = jiffies;
+
+ return;
+}
+
+
/* This function is our scheduled write */
static void hpsb_write_sched (void *__ptask)
{
struct sk_buff *skb = ptask->skb;
struct net_device *dev = ptask->skb->dev;
struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
- unsigned long flags;
+ unsigned long flags;
+ int status;
+
+ if (ptask->tx_type == ETH1394_GASP) {
+ status = hpsb_send_gasp(priv->host, priv->broadcast_channel,
+ get_hpsb_generation(priv->host),
+ (quadlet_t *)skb->data, skb->len,
+ ETHER1394_GASP_SPECIFIER_ID,
+ ETHER1394_GASP_VERSION);
+ } else {
+ status = hpsb_write(priv->host, ptask->dest_node,
+ get_hpsb_generation(priv->host),
+ ptask->addr, (quadlet_t *)skb->data,
+ skb->len);
+ }
+
/* Statistics */
spin_lock_irqsave (&priv->lock, flags);
- if (!hpsb_write(priv->host, ptask->dest_node,
- get_hpsb_generation(priv->host),
- ptask->addr, (quadlet_t *)skb->data, skb->len)) {
+ if (!status) {
priv->stats.tx_bytes += skb->len;
priv->stats.tx_packets++;
} else {
struct packet_task *ptask = NULL;
int ret = 0;
+ spin_lock_irqsave (&priv->lock, flags);
+ if (priv->bc_state == ETHER1394_BC_CLOSED) {
+ ETH1394_PRINT(KERN_ERR, dev->name,
+ "Cannot send packet, no broadcast channel available.");
+ ret = -EAGAIN;
+ goto fail;
+ }
+
+ /* First time sending? Need a broadcast channel for ARP and for
+ * listening on */
+ if (priv->bc_state == ETHER1394_BC_CHECK) {
+ quadlet_t bc;
+
+ /* Get the local copy of the broadcast channel and check its
+ * validity (the IRM should validate it for us) */
+
+ bc = priv->host->csr.broadcast_channel;
+
+ if ((bc & 0xc0000000) != 0xc0000000) {
+ /* broadcast channel not validated yet */
+ ETH1394_PRINT(KERN_WARNING, dev->name,
+ "Error BROADCAST_CHANNEL register valid "
+ "bit not set, can't send IP traffic\n");
+ hpsb_iso_shutdown(priv->iso);
+ priv->bc_state = ETHER1394_BC_CLOSED;
+ ret = -EAGAIN;
+ spin_unlock_irqrestore (&priv->lock, flags);
+ goto fail;
+ }
+ if (priv->broadcast_channel != (bc & 0x3f)) {
+ /* This really shouldn't be possible, but just in case
+ * the IEEE 1394 spec changes regarding broadcast
+ * channels in the future. */
+ hpsb_iso_shutdown(priv->iso);
+
+ priv->broadcast_channel = bc & 0x3f;
+ ETH1394_PRINT(KERN_WARNING, dev->name,
+ "Changing to broadcast channel %d...\n",
+ priv->broadcast_channel);
+
+ priv->iso = hpsb_iso_recv_init(priv->host, 8 * 4096,
+ 8, priv->broadcast_channel,
+ 1, ether1394_iso);
+ if (priv->iso == NULL) {
+ ret = -EAGAIN;
+ goto fail;
+ }
+ }
+ if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) {
+ ETH1394_PRINT(KERN_ERR, dev->name,
+ "Could not start async reception\n");
+ hpsb_iso_shutdown(priv->iso);
+ priv->bc_state = ETHER1394_BC_CLOSED;
+ ret = -EAGAIN;
+ spin_unlock_irqrestore (&priv->lock, flags);
+ goto fail;
+ }
+ priv->bc_state = ETHER1394_BC_OPENED;
+ }
+ spin_unlock_irqrestore (&priv->lock, flags);
+
if ((skb = skb_share_check (skb, kmflags)) == NULL) {
ret = -ENOMEM;
goto fail;
if (proto == __constant_htons (ETH_P_ARP))
ether1394_arp_to_1394arp (skb, dev);
+ ptask = kmem_cache_alloc(packet_task_cache, kmflags);
+ if (ptask == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
/* Now add our encapsulation header */
- ether1394_encapsulate (skb, dev, proto);
+ ether1394_encapsulate (skb, dev, proto, ptask);
/* TODO: The above encapsulate function needs to recognize when a
* packet needs to be split for a specified node. It should create
* need this hack. */
spin_lock_irqsave (&priv->lock, flags);
- addr = (u64)priv->fifo_hi[dest_node & NODE_MASK] << 32 |
- priv->fifo_lo[dest_node & NODE_MASK];
+ addr = (u64)priv->fifo_hi[NODEID_TO_NODE(dest_node)] << 32 |
+ priv->fifo_lo[NODEID_TO_NODE(dest_node)];
spin_unlock_irqrestore (&priv->lock, flags);
if (!addr)
addr = ETHER1394_REGION_ADDR;
- ptask = kmem_cache_alloc(packet_task_cache, kmflags);
- if (ptask == NULL) {
- ret = -ENOMEM;
- goto fail;
- }
-
ptask->skb = skb;
ptask->addr = addr;
ptask->dest_node = dest_node;
netif_wake_queue (dev);
spin_unlock_irqrestore (&priv->lock, flags);
- return ret;
+ return 0; /* returning non-zero causes serious problems */
}
/* Function for incoming 1394 packets */
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);
}
#define ETHER1394_REGION_ADDR 0xfffff0200000ULL
#define ETHER1394_REGION_ADDR_END (ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN)
+/* GASP identifier numbers for IPv4 over IEEE 1394 */
+#define ETHER1394_GASP_SPECIFIER_ID 0x00005E
+#define ETHER1394_GASP_VERSION 1
+
/* Node set == 64 */
#define NODE_SET (ALL_NODES + 1)
+enum eth1394_bc_states { ETHER1394_BC_CLOSED, ETHER1394_BC_OPENED,
+ ETHER1394_BC_CHECK };
+
/* Private structure for our ethernet driver */
struct eth1394_priv {
struct net_device_stats stats; /* Device stats */
u32 fifo_lo[ALL_NODES]; /* 32bit lo fifo offset per node */
u64 eui[ALL_NODES]; /* EUI-64 per node */
spinlock_t lock; /* Private lock */
+ int broadcast_channel; /* Async stream Broadcast Channel */
+ enum eth1394_bc_states bc_state; /* broadcast channel state */
+ struct hpsb_iso *iso; /* Async stream recv handle */
};
struct host_info {
struct net_device *dev;
};
+typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
+
/* This is our task struct. It's used for the packet complete callback. */
struct packet_task {
struct sk_buff *skb; /* Socket buffer we are sending */
nodeid_t dest_node; /* Destination of the packet */
u64 addr; /* Address */
struct hpsb_queue_struct tq; /* The task */
+ eth1394_tx_type tx_type; /* Send data via GASP or Write Req. */
};
/* IP1394 headers */
list_for_each(lh, &hosts) {
if (host == list_entry(lh, struct hpsb_host, host_list)) {
if (try_module_get(host->driver->owner)) {
- /* we're doing this twice and don't seem
- to undo it.. --hch */
- (void)try_module_get(host->driver->owner);
host->refcount++;
retval = 1;
}
#ifndef __IEEE1394_IOCTL_H
#define __IEEE1394_IOCTL_H
-#include <asm/ioctl.h>
-#include <asm/types.h>
+#include <linux/ioctl.h>
+#include <linux/types.h>
/* AMDTP Gets 6 */
#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL \
_IOW ('#', 0x23, unsigned char)
#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK \
- _IOW ('#', 0x24, u64)
+ _IOW ('#', 0x24, __u64)
#define RAW1394_IOC_ISO_RECV_PACKETS \
_IOW ('#', 0x25, struct raw1394_iso_packets)
#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS \
host->topology_map[host->selfid_count++] = sid;
} else {
HPSB_NOTICE("Spurious SelfID packet (0x%08x) received from bus %d",
- sid, (host->node_id & BUS_MASK) >> 6);
+ sid, NODEID_TO_BUS(host->node_id));
}
}
/* irm_id is kept up to date by check_selfids() */
if (host->irm_id == host->node_id) {
host->is_irm = 1;
- host->is_busmgr = 1;
- host->busmgr_id = host->node_id;
- host->csr.bus_manager_id = host->node_id;
} else {
host->is_busmgr = 0;
host->is_irm = 0;
if (packet->type == hpsb_async && packet->node_id != ALL_NODES) {
packet->speed_code =
- host->speed_map[(host->node_id & NODE_MASK) * 64
- + (packet->node_id & NODE_MASK)];
+ host->speed_map[NODEID_TO_NODE(host->node_id) * 64
+ + NODEID_TO_NODE(packet->node_id)];
}
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
addr, 4, flags);
if (!write_acked
- && (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
+ && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
&& (rcode >= 0)) {
/* not a broadcast write, reply */
PREP_REPLY_PACKET(0);
addr, data[3]>>16, flags);
if (!write_acked
- && (((data[0] >> 16) & NODE_MASK) != NODE_MASK)
+ && (NODEID_TO_NODE(data[0] >> 16) != NODE_MASK)
&& (rcode >= 0)) {
/* not a broadcast write, reply */
PREP_REPLY_PACKET(0);
EXPORT_SYMBOL(hpsb_write);
EXPORT_SYMBOL(hpsb_lock);
EXPORT_SYMBOL(hpsb_lock64);
+EXPORT_SYMBOL(hpsb_send_gasp);
EXPORT_SYMBOL(hpsb_packet_success);
/** highlevel.c **/
packet->speed_code = SPEED_100; /* Force speed to be 100Mbps */
}
+static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
+ int channel, int tag, int sync)
+{
+ packet->header[0] = (length << 16) | (tag << 14) | (channel << 8)
+ | (TCODE_STREAM_DATA << 4) | sync;
+
+ packet->header_size = 4;
+ packet->data_size = length;
+ packet->type = hpsb_async;
+ packet->tcode = TCODE_ISO_DATA;
+}
/**
* hpsb_get_tlabel - allocate a transaction label
}
-/* We need a hpsb_lock64 function for the 64 bit equivalent. Probably. */
int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
{
return retval;
}
+
+int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
+ quadlet_t *buffer, size_t length, u32 specifier_id,
+ unsigned int version)
+{
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+ int i;
+#endif
+
+ struct hpsb_packet *packet;
+ int retval = 0;
+ u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8;
+ u8 specifier_id_lo = specifier_id & 0xff;
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+ HPSB_DEBUG("Send GASP: channel = %d, length = %d", channel, length);
+#endif
+
+ length += 8;
+
+ packet = alloc_hpsb_packet(length + (length % 4 ? 4 - (length % 4) : 0));
+ if (!packet)
+ return -ENOMEM;
+
+ if (length % 4) {
+ packet->data[length / 4] = 0;
+ }
+
+ packet->host = host;
+ fill_async_stream_packet(packet, length, channel, 3, 0);
+
+ packet->data[0] = cpu_to_be32((host->node_id << 16) | specifier_id_hi);
+ packet->data[1] = cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff));
+
+ memcpy(&(packet->data[2]), buffer, length - 4);
+
+#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
+ HPSB_DEBUG("GASP: packet->header_size = %d", packet->header_size);
+ HPSB_DEBUG("GASP: packet->data_size = %d", packet->data_size);
+
+ for(i=0; i<(packet->data_size/4); i++)
+ HPSB_DEBUG("GASP: data[%d]: 0x%08x", i*4, be32_to_cpu(packet->data[i]));
+#endif
+
+ packet->generation = generation;
+
+ packet->no_waiter = 1;
+
+ if (!hpsb_send_packet(packet)) {
+ free_hpsb_packet(packet);
+ retval = -EINVAL;
+ }
+
+ return retval;
+}
u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
int hpsb_lock64(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, int extcode, octlet_t *data, octlet_t arg);
+int hpsb_send_gasp(struct hpsb_host *host, int channel, unsigned int generation,
+ quadlet_t *buffer, size_t length, u32 specifier_id,
+ unsigned int version);
#endif /* _IEEE1394_TRANSACTIONS_H */
typedef u16 arm_length_t;
#define BUS_MASK 0xffc0
+#define BUS_SHIFT 6
#define NODE_MASK 0x003f
#define LOCAL_BUS 0xffc0
#define ALL_NODES 0x003f
+#define NODEID_TO_BUS(nodeid) ((nodeid & BUS_MASK) >> BUS_SHIFT)
+#define NODEID_TO_NODE(nodeid) (nodeid & NODE_MASK)
+
/* Can be used to consistently print a node/bus ID. */
-#define NODE_BUS_FMT "%02d:%04d"
-#define NODE_BUS_ARGS(nodeid) \
- (nodeid & NODE_MASK), ((nodeid & BUS_MASK) >> 6)
+#define NODE_BUS_FMT "%02d:%04d"
+#define NODE_BUS_ARGS(nodeid) NODEID_TO_NODE(nodeid), NODEID_TO_BUS(nodeid)
#define HPSB_PRINT(level, fmt, args...) printk(level "ieee1394: " fmt "\n" , ## args)
return;
}
+/* 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). */
+static void nodemgr_do_irm_duties(struct hpsb_host *host)
+{
+ quadlet_t bc;
+
+ if (!host->is_irm)
+ return;
+
+ host->csr.broadcast_channel |= 0x40000000; /* set validity bit */
+
+ bc = cpu_to_be32(host->csr.broadcast_channel);
+
+ hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host),
+ (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
+ &bc,
+ sizeof(quadlet_t));
+}
+
+/* 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)
+{
+ quadlet_t bc;
+ int status;
+
+ if (host->is_irm)
+ return 1;
+
+ status = hpsb_read(host, LOCAL_BUS | (host->irm_id),
+ get_hpsb_generation(host),
+ (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
+ &bc, sizeof(quadlet_t));
+
+ if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {
+ /* The root node does not have a valid BROADCAST_CHANNEL
+ * register and we do, so reset the bus with force_root set */
+ HPSB_INFO("Remote root is not IRM capable, resetting...");
+ hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
+ return 0;
+ }
+ return 1;
+}
+
static int nodemgr_host_thread(void *__hi)
{
struct host_info *hi = (struct host_info *)__hi;
/* No userlevel access needed */
daemonize("knodemgrd");
allow_signal(SIGTERM);
-
+
/* Sit and wait for a signal to probe the nodes on the bus. This
* happens when we get a bus reset. */
while (!down_interruptible(&hi->reset_sem) &&
!down_interruptible(&nodemgr_serialize)) {
+
+ if (!nodemgr_check_root_capability(hi->host)) {
+ /* Do nothing, we are resetting */
+ up(&nodemgr_serialize);
+ continue;
+ }
+
nodemgr_node_probe(hi->host);
+ nodemgr_do_irm_duties(hi->host);
+
up(&nodemgr_serialize);
}
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
*
* Things implemented, but still in test phase:
* . Iso Transmit
+ * . Async Stream Packets Transmit (Receive done via Iso interface)
*
* Things not implemented:
- * . Async Stream Packets
* . DMA error recovery
*
* Known bugs:
printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
static char version[] __devinitdata =
- "$Rev: 762 $ Ben Collins <bcollins@debian.org>";
+ "$Rev: 801 $ Ben Collins <bcollins@debian.org>";
/* Module Parameters */
MODULE_PARM(phys_dma,"i");
} else {
d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
(packet->header[0] & 0xFFFF);
- d->prg_cpu[idx]->data[1] =
- (packet->header[1] & 0xFFFF) |
- (packet->header[0] & 0xFFFF0000);
- d->prg_cpu[idx]->data[2] = packet->header[2];
- d->prg_cpu[idx]->data[3] = packet->header[3];
+
+ if (packet->tcode == TCODE_ISO_DATA) {
+ /* Sending an async stream packet */
+ d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
+ } else {
+ /* Sending a normal async request or response */
+ d->prg_cpu[idx]->data[1] =
+ (packet->header[1] & 0xFFFF) |
+ (packet->header[0] & 0xFFFF0000);
+ d->prg_cpu[idx]->data[2] = packet->header[2];
+ d->prg_cpu[idx]->data[3] = packet->header[3];
+ }
packet_swab(d->prg_cpu[idx]->data, packet->tcode);
}
if (packet->data_size) { /* block transmit */
- d->prg_cpu[idx]->begin.control =
- cpu_to_le32(DMA_CTL_OUTPUT_MORE |
- DMA_CTL_IMMEDIATE | 0x10);
+ if (packet->tcode == TCODE_STREAM_DATA){
+ d->prg_cpu[idx]->begin.control =
+ cpu_to_le32(DMA_CTL_OUTPUT_MORE |
+ DMA_CTL_IMMEDIATE | 0x8);
+ } else {
+ d->prg_cpu[idx]->begin.control =
+ cpu_to_le32(DMA_CTL_OUTPUT_MORE |
+ DMA_CTL_IMMEDIATE | 0x10);
+ }
d->prg_cpu[idx]->end.control =
cpu_to_le32(DMA_CTL_OUTPUT_LAST |
DMA_CTL_IRQ |
/* Decide whether we have an iso, a request, or a response packet */
if (packet->type == hpsb_raw)
d = &ohci->at_req_context;
- else if (packet->tcode == TCODE_ISO_DATA) {
+ else if ((packet->tcode == TCODE_ISO_DATA) && (packet->type == hpsb_iso)) {
/* The legacy IT DMA context is initialized on first
* use. However, the alloc cannot be run from
* interrupt context, so we bail out if that is the
}
d = &ohci->it_legacy_context;
- } else if (packet->tcode & 0x02)
+ } else if ((packet->tcode & 0x02) && (packet->tcode != TCODE_ISO_DATA))
d = &ohci->at_resp_context;
else
d = &ohci->at_req_context;
u32 *prev_branch = NULL;
for (blk = 0; blk < recv->nblocks; blk++) {
+ u32 control;
+
/* the DMA descriptor */
struct dma_cmd *cmd = &recv->block[blk];
unsigned long buf_offset = blk * recv->buf_stride;
if (recv->dma_mode == BUFFER_FILL_MODE) {
- cmd->control = 2 << 28; /* INPUT_MORE */
+ control = 2 << 28; /* INPUT_MORE */
} else {
- cmd->control = 3 << 28; /* INPUT_LAST */
+ control = 3 << 28; /* INPUT_LAST */
}
- cmd->control |= 8 << 24; /* s = 1, update xferStatus and resCount */
+ control |= 8 << 24; /* s = 1, update xferStatus and resCount */
/* interrupt on last block, and at intervals */
if (blk == recv->nblocks-1 || (blk % recv->block_irq_interval) == 0) {
- cmd->control |= 3 << 20; /* want interrupt */
+ control |= 3 << 20; /* want interrupt */
}
- cmd->control |= 3 << 18; /* enable branch to address */
- cmd->control |= recv->buf_stride;
+ control |= 3 << 18; /* enable branch to address */
+ control |= recv->buf_stride;
- cmd->address = dma_region_offset_to_bus(&iso->data_buf, buf_offset);
+ cmd->control = cpu_to_le32(control);
+ cmd->address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, buf_offset));
cmd->branchAddress = 0; /* filled in on next loop */
- cmd->status = recv->buf_stride;
+ cmd->status = cpu_to_le32(recv->buf_stride);
/* link the previous descriptor to this one */
if (prev_branch) {
- *prev_branch = dma_prog_region_offset_to_bus(&recv->prog, prog_offset);
- *prev_branch |= 1; /* set Z=1 */
+ *prev_branch = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog, prog_offset) | 1);
}
prev_branch = &cmd->branchAddress;
/* 'next' becomes the new end of the DMA chain,
so disable branch and enable interrupt */
next->branchAddress = 0;
- next->control |= 3 << 20;
+ next->control |= cpu_to_le32(3 << 20);
/* link prev to next */
- prev->branchAddress = dma_prog_region_offset_to_bus(&recv->prog,
- sizeof(struct dma_cmd) * next_i)
- | 1; /* Z=1 */
+ prev->branchAddress = cpu_to_le32(dma_prog_region_offset_to_bus(&recv->prog,
+ sizeof(struct dma_cmd) * next_i)
+ | 1); /* Z=1 */
/* disable interrupt on previous DMA descriptor, except at intervals */
if((prev_i % recv->block_irq_interval) == 0) {
- prev->control |= 3 << 20; /* enable interrupt */
+ prev->control |= cpu_to_le32(3 << 20); /* enable interrupt */
} else {
- prev->control &= ~(3<<20); /* disable interrupt */
+ prev->control &= cpu_to_le32(~(3<<20)); /* disable interrupt */
}
wmb();
struct dma_cmd *il = ((struct dma_cmd*) recv->prog.kvirt) + iso->pkt_dma;
/* check the DMA descriptor for new writes to xferStatus */
- u16 xferstatus = il->status >> 16;
- u16 rescount = il->status & 0xFFFF;
+ u16 xferstatus = le32_to_cpu(il->status) >> 16;
+ u16 rescount = le32_to_cpu(il->status) & 0xFFFF;
unsigned char event = xferstatus & 0x1F;
struct iso_xmit_cmd *cmd = dma_region_i(&xmit->prog, struct iso_xmit_cmd, iso->pkt_dma);
/* check for new writes to xferStatus */
- u16 xferstatus = cmd->output_last.status >> 16;
+ u16 xferstatus = le32_to_cpu(cmd->output_last.status) >> 16;
u8 event = xferstatus & 0x1F;
if(!event) {
wake = 1;
/* parse cycle */
- cycle = cmd->output_last.status & 0x1FFF;
+ cycle = le32_to_cpu(cmd->output_last.status) & 0x1FFF;
/* tell the subsystem the packet has gone out */
hpsb_iso_packet_sent(iso, cycle, event != 0x11);
/* set up the OUTPUT_MORE_IMMEDIATE descriptor */
memset(next, 0, sizeof(struct iso_xmit_cmd));
- next->output_more_immediate.control = 0x02000008;
+ next->output_more_immediate.control = cpu_to_le32(0x02000008);
/* ISO packet header is embedded in the OUTPUT_MORE_IMMEDIATE */
next->iso_hdr[7] = len >> 8;
/* set up the OUTPUT_LAST */
- next->output_last.control = 1 << 28;
- next->output_last.control |= 1 << 27; /* update timeStamp */
- next->output_last.control |= 3 << 20; /* want interrupt */
- next->output_last.control |= 3 << 18; /* enable branch */
- next->output_last.control |= len;
+ next->output_last.control = cpu_to_le32(1 << 28);
+ next->output_last.control |= cpu_to_le32(1 << 27); /* update timeStamp */
+ next->output_last.control |= cpu_to_le32(3 << 20); /* want interrupt */
+ next->output_last.control |= cpu_to_le32(3 << 18); /* enable branch */
+ next->output_last.control |= cpu_to_le32(len);
/* payload bus address */
- next->output_last.address = dma_region_offset_to_bus(&iso->data_buf, offset);
+ next->output_last.address = cpu_to_le32(dma_region_offset_to_bus(&iso->data_buf, offset));
/* leave branchAddress at zero for now */
/* re-write the previous DMA descriptor to chain to this one */
/* set prev branch address to point to next (Z=3) */
- prev->output_last.branchAddress =
- dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3;
+ prev->output_last.branchAddress = cpu_to_le32(
+ dma_prog_region_offset_to_bus(&xmit->prog, sizeof(struct iso_xmit_cmd) * next_i) | 3);
/* disable interrupt, unless required by the IRQ interval */
if(prev_i % iso->irq_interval) {
- prev->output_last.control &= ~(3 << 20); /* no interrupt */
+ prev->output_last.control &= cpu_to_le32(~(3 << 20)); /* no interrupt */
} else {
- prev->output_last.control |= 3 << 20; /* enable interrupt */
+ prev->output_last.control |= cpu_to_le32(3 << 20); /* enable interrupt */
}
wmb();
static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
{
- .class = PCI_CLASS_FIREWIRE_OHCI,
- .class_mask = 0x00ffffff,
- .vendor = PCI_ANY_ID,
- .device = PCI_ANY_ID,
+ .class = PCI_CLASS_FIREWIRE_OHCI,
+ .class_mask = ~0,
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
list_del(&hi->list);
host_count--;
/*
- FIXME: addressranges should be removed
+ FIXME: address ranges should be removed
and fileinfo states should be initialized
(including setting generation to
internal-generation ...)
req->req.misc = (host->node_id << 16)
| host->node_count;
if (fi->protocol_version > 3) {
- req->req.misc |= ((host->irm_id
- & NODE_MASK) << 8);
+ req->req.misc |= (NODEID_TO_NODE(host->irm_id)
+ << 8);
}
queue_complete_req(req);
req->req.misc = (fi->host->node_id << 16)
| fi->host->node_count;
if (fi->protocol_version > 3) {
- req->req.misc |=
- (fi->host->irm_id & NODE_MASK) << 8;
+ req->req.misc |= NODEID_TO_NODE(fi->host->irm_id) << 8;
}
} else {
req->req.error = RAW1394_ERROR_INVALID_ARG;
* driver. It also registers as a SCSI lower-level driver in order to accept
* SCSI commands for transport using SBP-2.
*
- *
- * Driver Loading:
- *
- * Currently, the SBP-2 driver is supported only as a module. Because the
- * Linux SCSI stack is not Plug-N-Play aware, module load order is
- * important. Assuming the SCSI core drivers are either built into the
- * kernel or already loaded as modules, you should load the IEEE-1394 modules
- * in the following order:
- *
- * ieee1394 (e.g. insmod ieee1394)
- * ohci1394 (e.g. insmod ohci1394)
- * sbp2 (e.g. insmod sbp2)
- *
- * The SBP-2 driver will attempt to discover any attached SBP-2 devices when first
- * loaded, or after any IEEE-1394 bus reset (e.g. a hot-plug). It will then print
- * out a debug message indicating if it was able to discover a SBP-2 device.
- *
- * Currently, the SBP-2 driver will catch any attached SBP-2 devices during the
- * initial scsi bus scan (when the driver is first loaded). To add or remove
- * SBP-2 devices "after" this initial scan (i.e. if you plug-in or un-plug a
- * device after the SBP-2 driver is loaded), you must either use the scsi procfs
- * add-single-device, remove-single-device, or a shell script such as
- * rescan-scsi-bus.sh.
- *
* The easiest way to add/detect new SBP-2 devices is to run the shell script
* rescan-scsi-bus.sh (or re-load the SBP-2 driver). This script may be
* found at:
* - Error Handling: SCSI aborts and bus reset requests are handled somewhat
* but the code needs additional debugging.
*
- * - Module: The SBP-2 driver is currently only supported as a module. It would not take
- * much work to allow it to be compiled into the kernel, but you'd have to
- * add some init code to the kernel to support this... and modules are much
- * more flexible anyway. ;-)
- *
- * - Hot-plugging: Interaction with the SCSI stack and support for hot-plugging could
- * stand some improvement.
- *
*
* History:
*
* 04/23/02 - Fix for Sony CD-ROM drives. Only send fetch agent reset to sbp2 device if it
* returns the dead bit in status. Thanks to Chandan (chandan@toad.net) for this one.
* 04/27/02 - Fix sbp2 login problem on SMP systems, enable real spinlocks by default. (JSG)
- * 06/09/02 - Don't force 36-bute SCSI inquiry, but leave in a define for badly behaved devices. (JSG)
+ * 06/09/02 - Don't force 36-byte SCSI inquiry, but leave in a define for badly behaved devices. (JSG)
* 02/04/03 - Fixed a SMP deadlock (don't hold sbp2_command_lock while calling sbp2scsi_complete_command).
* Also save/restore irq flags in sbp2scsi_complete_command - Sancho Dauskardt <sda@bdit.de>
* 02/06/03 - Removed spinlock debugging; use kernel stuff instead (sda)
+ * 02/10/03 - Adopt to new hot-plug aware SCSI inferface (hch@lst.de)
*
*/
#include "sbp2.h"
static char version[] __devinitdata =
- "$Rev: 779 $ James Goodwin <jamesg@filanet.com>";
+ "$Rev: 797 $ James Goodwin <jamesg@filanet.com>";
/*
* Module load parameter definitions
* Globals
*/
+static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi,
+ struct scsi_id_instance_data *scsi_id,
+ u32 status);
+
+static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi,
+ struct scsi_id_instance_data *scsi_id,
+ u32 scsi_status, Scsi_Cmnd *SCpnt,
+ void (*done)(Scsi_Cmnd *));
+
static Scsi_Host_Template scsi_driver_template;
static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };
{
struct sbp2scsi_host_info *hi;
- hi = (struct sbp2scsi_host_info *) command->Current_SCpnt->device->host->hostdata[0];
+ hi = (struct sbp2scsi_host_info *)&command->Current_SCpnt->device->host->hostdata;
if (hi == NULL) {
printk(KERN_ERR "%s: hi == NULL\n", __FUNCTION__);
* IEEE-1394 core driver stack related section
*********************************************/
-/*
- * This function is called at SCSI init in order to register our driver
- * with the IEEE-1394 stack.
- */
-int sbp2_init(void)
-{
- SBP2_DEBUG("sbp2_init");
-
- /*
- * Register our high level driver with 1394 stack
- */
- sbp2_hl_handle = hpsb_register_highlevel(SBP2_DEVICE_NAME, &sbp2_hl_ops);
-
- if (sbp2_hl_handle == NULL) {
- SBP2_ERR("sbp2 failed to register with ieee1394 highlevel");
- return(-ENOMEM);
- }
-
- /*
- * Register our sbp2 status address space...
- */
- hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS,
- SBP2_STATUS_FIFO_ADDRESS +
- SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1));
-
- /*
- * Handle data movement if physical dma is not enabled/supported on host controller
- */
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
- hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL);
-#endif
-
- hpsb_register_protocol(&sbp2_driver);
-
- return 0;
-}
-
-/*
- * This function is called from cleanup module, or during shut-down, in
- * order to unregister our driver.
- */
-void sbp2_cleanup(void)
-{
- SBP2_DEBUG("sbp2_cleanup");
-
- hpsb_unregister_protocol(&sbp2_driver);
-
- if (sbp2_hl_handle) {
- hpsb_unregister_highlevel(sbp2_hl_handle);
- sbp2_hl_handle = NULL;
- }
-}
-
static int sbp2_probe(struct unit_directory *ud)
{
struct sbp2scsi_host_info *hi;
{
struct sbp2scsi_host_info *hi;
unsigned long flags;
+ struct Scsi_Host *scsi_host;
SBP2_DEBUG("sbp2_add_host");
- /* Allocate some memory for our host info structure */
- hi = (struct sbp2scsi_host_info *)kmalloc(sizeof(struct sbp2scsi_host_info),
- in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
-
- if (hi == NULL) {
- SBP2_ERR("out of memory in sbp2_add_host");
+ /* Register our host with the SCSI stack. */
+ scsi_host = scsi_register (&scsi_driver_template, sizeof(struct sbp2scsi_host_info));
+ if (!scsi_host) {
+ SBP2_ERR("failed to register scsi host");
return;
}
- /* Initialize some host stuff */
+ hi = (struct sbp2scsi_host_info *)&scsi_host->hostdata;
memset(hi, 0, sizeof(struct sbp2scsi_host_info));
+
+ 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);
- /* Register our host with the SCSI stack. */
- hi->scsi_host = scsi_register (&scsi_driver_template, sizeof(void *));
- if (hi->scsi_host) {
- hi->scsi_host->hostdata[0] = (unsigned long)hi;
- hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS;
+ /*
+ * XXX(hch): Hopefully the ieee1394 code will be converted
+ * to the driver model at some point. Until that happens
+ * we'll have to pass in NULL here.
+ */
+ 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);
}
- scsi_driver_template.present++;
return;
}
SBP2_DEBUG("sbp2_remove_host");
spin_lock_irqsave(&sbp2_host_info_lock, flags);
-
hi = sbp2_find_host_info(host);
- if (hi != NULL) {
+ if (hi)
list_del(&hi->list);
- kfree(hi);
- }
- else
- SBP2_ERR("attempt to remove unknown host %p", host);
-
spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
+
+ if (hi) {
+ scsi_remove_host(hi->scsi_host);
+ scsi_unregister(hi->scsi_host);
+ }
}
/*
static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_directory *ud)
{
struct scsi_id_instance_data *scsi_id = NULL;
+ struct scsi_device *sdev;
struct node_entry *ne;
int i;
/*
* Find an empty spot to stick our scsi id instance data.
*/
- for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) {
+ for (i = 0; i < hi->scsi_host->max_id; i++) {
if (!hi->scsi_id[i]) {
hi->scsi_id[i] = scsi_id;
scsi_id->id = i;
/*
* Make sure we are not out of space
*/
- if (i == SBP2SCSI_MAX_SCSI_IDS) {
+ if (i == hi->scsi_host->max_id) {
SBP2_ERR("No slots left for SBP-2 device");
sbp2_remove_device(hi, scsi_id);
return -EBUSY;
*/
sbp2_max_speed_and_size(hi, scsi_id);
+ /* Add this device to the scsi layer now */
+ sdev = scsi_add_device(hi->scsi_host, 0, scsi_id->id, 0);
+ if (IS_ERR(sdev)) {
+ SBP2_ERR("scsi_add_device failed");
+ return PTR_ERR(sdev);
+ }
+
return 0;
}
static void sbp2_remove_device(struct sbp2scsi_host_info *hi,
struct scsi_id_instance_data *scsi_id)
{
+ struct scsi_device *sdev = scsi_find_device(hi->scsi_host, 0, scsi_id->id, 0);
+
SBP2_DEBUG("sbp2_remove_device");
/* Complete any pending commands with selection timeout */
sbp2scsi_complete_all_commands(hi, scsi_id, DID_NO_CONNECT);
-
+
+ /* Remove it from the scsi layer now */
+ if (scsi_remove_device(sdev))
+ SBP2_ERR("scsi_remove_device failed");
+
sbp2util_remove_command_orb_pool(scsi_id, hi);
+ hi->scsi_id[scsi_id->id] = NULL;
+
if (scsi_id->login_response) {
pci_free_consistent(hi->host->pdev,
sizeof(struct sbp2_login_response),
}
SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id);
- hi->scsi_id[scsi_id->id] = NULL;
+
kfree(scsi_id);
}
SBP2_DEBUG("sbp2_max_speed_and_size");
/* Initial setting comes from the hosts speed map */
- scsi_id->speed_code = hi->host->speed_map[(hi->host->node_id & NODE_MASK) * 64
- + (scsi_id->ne->nodeid & NODE_MASK)];
+ scsi_id->speed_code = hi->host->speed_map[NODEID_TO_NODE(hi->host->node_id) * 64
+ + NODEID_TO_NODE(scsi_id->ne->nodeid)];
/* Bump down our speed if the user requested it */
if (scsi_id->speed_code > sbp2_max_speed) {
/*
* Pull our host info and scsi id instance data from the scsi command
*/
- hi = (struct sbp2scsi_host_info *) SCpnt->device->host->hostdata[0];
+ hi = (struct sbp2scsi_host_info *) &SCpnt->device->host->hostdata;
if (!hi) {
SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!");
*
* This can be called in interrupt context.
*/
-static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status,
- Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi,
+ struct scsi_id_instance_data *scsi_id,
+ u32 scsi_status, Scsi_Cmnd *SCpnt,
+ void (*done)(Scsi_Cmnd *))
{
unsigned long flags;
*/
static int sbp2scsi_abort (Scsi_Cmnd *SCpnt)
{
- struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->device->host->hostdata[0];
+ struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)&SCpnt->device->host->hostdata;
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[0];
+ struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *)&SCpnt->device->host->hostdata;
struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->device->id];
SBP2_ERR("reset requested");
return(SUCCESS);
}
-/*
- * Called by scsi stack to get bios parameters (used by fdisk, and at boot).
- */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,43)
-static int sbp2scsi_biosparam (struct scsi_device *sdev,
- struct block_device *dev, sector_t capacity, int geom[])
+static const char *sbp2scsi_info (struct Scsi_Host *host)
{
-#else
-static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[])
+ return "SCSI emulation for for IEEE-1394 Storage Devices";
+}
+
+/* Called for contents of procfs */
+#define SPRINTF(args...) \
+ do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
+
+static int sbp2scsi_proc_info(char *buffer, char **start, off_t offset,
+ int length, int hostno, int inout)
{
- unsigned capacity = disk->capacity;
-#endif
- int heads, sectors, cylinders;
+ Scsi_Device *scd;
+ struct Scsi_Host *host;
+ struct sbp2scsi_host_info *hi;
+ char *pos = buffer;
- SBP2_DEBUG("Request for bios parameters");
+ /* if someone is sending us data, just throw it away */
+ if (inout)
+ return length;
- heads = 64;
- sectors = 32;
- cylinders = (int)capacity / (heads * sectors);
+ host = scsi_host_hn_get(hostno);
+ if (!host) /* if we couldn't find it, we return an error */
+ return -ESRCH;
- if (cylinders > 1024) {
- heads = 255;
- sectors = 63;
- cylinders = (int)capacity / (heads * sectors);
- }
+ hi = sbp2_find_host_info_scsi(host);
+ if (!hi) /* shouldn't happen, but... */
+ return -ESRCH;
- geom[0] = heads;
- geom[1] = sectors;
- geom[2] = cylinders;
+ SPRINTF("Host scsi%d : SBP-2 IEEE-1394 (%s)\n", hostno,
+ hi->host->driver->name);
+ SPRINTF("Driver version : %s\n", version);
- return(0);
-}
+ SPRINTF("\nModule options :\n");
+ SPRINTF(" sbp2_max_speed : %s\n", hpsb_speedto_str[sbp2_max_speed]);
+ SPRINTF(" sbp2_max_sectors : %d\n", sbp2_max_sectors);
+ SPRINTF(" sbp2_serialize_io : %s\n", sbp2_serialize_io ? "yes" : "no");
+ SPRINTF(" sbp2_exclusive_login : %s\n", sbp2_exclusive_login ? "yes" : "no");
-/*
- * Called by scsi stack after scsi driver is registered
- */
-static int sbp2scsi_detect (Scsi_Host_Template *tpnt)
-{
- SBP2_DEBUG("sbp2scsi_detect");
+ SPRINTF("\nAttached devices : %s\n", !list_empty(&host->my_devices) ?
+ "" : "none");
- /*
- * Call sbp2_init to register with the ieee1394 stack. This
- * results in a callback to sbp2_add_host for each ieee1394
- * host controller currently registered, and for each of those
- * we register a scsi host with the scsi stack.
- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- spin_unlock_irq(&io_request_lock);
- sbp2_init();
- spin_lock_irq(&io_request_lock);
-#else
- sbp2_init();
-#endif
+ list_for_each_entry (scd, &host->my_devices, siblings) {
+ int i;
- /* We return the number of hosts registered. */
- return scsi_driver_template.present;
-}
+ SPRINTF(" [Channel: %02d, Id: %02d, Lun: %02d] ", scd->channel,
+ scd->id, scd->lun);
+ SPRINTF("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
+ scsi_device_types[(short) scd->type] : "Unknown device");
+ for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++)
+ SPRINTF("%c", scd->vendor[i]);
-/*
- * Called for contents of procfs
- */
-static const char *sbp2scsi_info (struct Scsi_Host *host)
-{
- struct sbp2scsi_host_info *hi = sbp2_find_host_info_scsi(host);
- static char info[1024];
+ SPRINTF(" ");
- if (!hi) /* shouldn't happen, but... */
- return "IEEE-1394 SBP-2 protocol driver";
-
- sprintf(info, "IEEE-1394 SBP-2 protocol driver (host: %s)\n%s\n"
- "SBP-2 module load options:\n"
- "- Max speed supported: %s\n"
- "- Max sectors per I/O supported: %d\n"
- "- Serialized I/O (debug): %s\n"
- "- Exclusive login: %s",
- hi->host->driver->name,
- version,
- hpsb_speedto_str[sbp2_max_speed],
- sbp2_max_sectors,
- sbp2_serialize_io ? "yes" : "no",
- sbp2_exclusive_login ? "yes" : "no");
-
- return info;
-}
+ for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++)
+ SPRINTF("%c", scd->model[i]);
+ SPRINTF("\n");
+ }
+
+ SPRINTF("\n");
+
+ /* release the reference count on this host */
+ scsi_host_put(host);
+ /* Calculate start of next buffer, and return value. */
+ *start = buffer + offset;
+
+ if ((pos - buffer) < offset)
+ return (0);
+ else if ((pos - buffer - offset) < length)
+ return (pos - buffer - offset);
+ else
+ return (length);
+}
MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
/* SCSI host template */
static Scsi_Host_Template scsi_driver_template = {
- .name = "IEEE-1394 SBP-2 protocol driver",
- .info = sbp2scsi_info,
- .detect = sbp2scsi_detect,
- .queuecommand = sbp2scsi_queuecommand,
- .eh_abort_handler = sbp2scsi_abort,
- .eh_device_reset_handler =sbp2scsi_reset,
- .eh_bus_reset_handler = sbp2scsi_reset,
- .eh_host_reset_handler =sbp2scsi_reset,
- .bios_param = sbp2scsi_biosparam,
- .this_id = -1,
- .sg_tablesize = SG_ALL,
- .use_clustering = ENABLE_CLUSTERING,
- .cmd_per_lun = SBP2_MAX_CMDS_PER_LUN,
- .can_queue = SBP2_MAX_SCSI_QUEUE,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- .use_new_eh_code = TRUE,
-#endif
- .emulated = 1,
- .proc_name = SBP2_DEVICE_NAME,
+ .module = THIS_MODULE,
+ .name = "SBP-2 IEEE-1394",
+ .proc_name = SBP2_DEVICE_NAME,
+ .info = sbp2scsi_info,
+ .proc_info = sbp2scsi_proc_info,
+ .queuecommand = sbp2scsi_queuecommand,
+ .eh_abort_handler = sbp2scsi_abort,
+ .eh_device_reset_handler = sbp2scsi_reset,
+ .eh_bus_reset_handler = sbp2scsi_reset,
+ .eh_host_reset_handler = sbp2scsi_reset,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .use_clustering = ENABLE_CLUSTERING,
+ .cmd_per_lun = SBP2_MAX_CMDS_PER_LUN,
+ .can_queue = SBP2_MAX_SCSI_QUEUE,
+ .emulated = 1,
+ .highmem_io = 1,
};
static int sbp2_module_init(void)
*/
scsi_driver_template.max_sectors = sbp2_max_sectors;
+
/*
- * Ideally we would register our scsi_driver_template with the
- * scsi stack and after that register with the ieee1394 stack
- * and process the add_host callbacks. However, the detect
- * function in the scsi host template requires that we find at
- * least one host, so we "nest" the registrations by calling
- * sbp2_init from the detect function.
+ * Register our high level driver with 1394 stack
*/
- scsi_driver_template.module = THIS_MODULE;
- if (SCSI_REGISTER_HOST(&scsi_driver_template) ||
- !scsi_driver_template.present) {
- SBP2_ERR("Please load the lower level IEEE-1394 driver "
- "(e.g. ohci1394) before sbp2...");
- sbp2_cleanup();
- return -ENODEV;
+ sbp2_hl_handle = hpsb_register_highlevel(SBP2_DEVICE_NAME,
+ &sbp2_hl_ops);
+ if (!sbp2_hl_handle) {
+ SBP2_ERR("sbp2 failed to register with ieee1394 highlevel");
+ return(-ENOMEM);
}
+ /*
+ * Register our sbp2 status address space...
+ */
+ hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops,
+ SBP2_STATUS_FIFO_ADDRESS,
+ SBP2_STATUS_FIFO_ADDRESS +
+ SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(
+ SBP2SCSI_MAX_SCSI_IDS+1));
+
+ /*
+ * Handle data movement if physical dma is not enabled/supported
+ * on host controller
+ */
+#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
+ hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops,
+ 0x0ULL, 0xfffffffcULL);
+#endif
+
+ hpsb_register_protocol(&sbp2_driver);
return 0;
}
{
SBP2_DEBUG("sbp2_module_exit");
- /*
- * On module unload we unregister with the ieee1394 stack
- * which results in remove_host callbacks for all ieee1394
- * host controllers. In the callbacks we unregister the
- * corresponding scsi hosts.
- */
- sbp2_cleanup();
-
- if (SCSI_UNREGISTER_HOST(&scsi_driver_template))
- SBP2_ERR("sbp2_module_exit: couldn't unregister scsi driver");
-
+ hpsb_unregister_protocol(&sbp2_driver);
+ if (sbp2_hl_handle)
+ hpsb_unregister_highlevel(sbp2_hl_handle);
}
module_init(sbp2_module_init);
#ifndef SBP2_H
#define SBP2_H
-/* Some compatibility code */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#define SCSI_REGISTER_HOST(tmpl) scsi_register_module(MODULE_SCSI_HA, tmpl)
-#define SCSI_UNREGISTER_HOST(tmpl) scsi_unregister_module(MODULE_SCSI_HA, tmpl)
-#else
-#define SCSI_REGISTER_HOST(tmpl) scsi_register_host(tmpl)
-#define SCSI_UNREGISTER_HOST(tmpl) scsi_unregister_host(tmpl)
-#endif
-
#define SBP2_DEVICE_NAME "sbp2"
/*
static void 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);
-int sbp2_init(void);
-void sbp2_cleanup(void);
static int sbp2_probe(struct unit_directory *ud);
static void sbp2_disconnect(struct unit_directory *ud);
static void sbp2_update(struct unit_directory *ud);
static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
-/*
- * Scsi interface related prototypes
- */
-static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
-static const char *sbp2scsi_info (struct Scsi_Host *host);
-void sbp2scsi_setup(char *str, int *ints);
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,44)
-static int sbp2scsi_biosparam (struct scsi_device *sdev, struct block_device *dev, sector_t capacity, int geom[]);
-#else
-static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
-#endif
-static int sbp2scsi_abort (Scsi_Cmnd *SCpnt);
-static int sbp2scsi_reset (Scsi_Cmnd *SCpnt);
-static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
-static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
- u32 status);
-static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
- u32 scsi_status, Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
-
#endif /* SBP2_H */
#include <linux/vmalloc.h>
#include <linux/timex.h>
#include <linux/mm.h>
+#include <linux/ioctl32.h>
+#include <linux/compat.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
MODULE_SUPPORTED_DEVICE(VIDEO1394_DRIVER_NAME);
MODULE_LICENSE("GPL");
+#ifdef CONFIG_COMPAT
+
+#define VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER \
+ _IOW ('#', 0x12, struct video1394_wait32)
+#define VIDEO1394_IOC32_LISTEN_WAIT_BUFFER \
+ _IOWR('#', 0x13, struct video1394_wait32)
+#define VIDEO1394_IOC32_TALK_WAIT_BUFFER \
+ _IOW ('#', 0x17, struct video1394_wait32)
+#define VIDEO1394_IOC32_LISTEN_POLL_BUFFER \
+ _IOWR('#', 0x18, struct video1394_wait32)
+
+struct video1394_wait32 {
+ u32 channel;
+ u32 buffer;
+ struct compat_timeval filltime;
+};
+
+static int video1394_wr_wait32(unsigned int fd, unsigned int cmd, unsigned long arg,
+ struct file *file)
+{
+ struct video1394_wait32 wait32;
+ struct video1394_wait wait;
+ mm_segment_t old_fs;
+ int ret;
+
+ if (file->f_op->ioctl != video1394_ioctl)
+ return -EFAULT;
+
+ if (copy_from_user(&wait32, (void *)arg, sizeof(wait32)))
+ return -EFAULT;
+
+ wait.channel = wait32.channel;
+ wait.buffer = wait32.buffer;
+ wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
+ wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ if (cmd == VIDEO1394_IOC32_LISTEN_WAIT_BUFFER)
+ ret = video1394_ioctl(file->f_dentry->d_inode, file,
+ VIDEO1394_IOC_LISTEN_WAIT_BUFFER,
+ (unsigned long) &wait);
+ else
+ ret = video1394_ioctl(file->f_dentry->d_inode, file,
+ VIDEO1394_IOC_LISTEN_POLL_BUFFER,
+ (unsigned long) &wait);
+ set_fs(old_fs);
+
+ if (!ret) {
+ wait32.channel = wait.channel;
+ wait32.buffer = wait.buffer;
+ wait32.filltime.tv_sec = (int)wait.filltime.tv_sec;
+ wait32.filltime.tv_usec = (int)wait.filltime.tv_usec;
+
+ if (copy_to_user((struct video1394_wait32 *)arg, &wait32, sizeof(wait32)))
+ ret = -EFAULT;
+ }
+
+ return ret;
+}
+
+static int video1394_w_wait32(unsigned int fd, unsigned int cmd, unsigned long arg,
+ struct file *file)
+{
+ struct video1394_wait32 wait32;
+ struct video1394_wait wait;
+ mm_segment_t old_fs;
+ int ret;
+
+ if (file->f_op->ioctl != video1394_ioctl)
+ return -EFAULT;
+
+ if (copy_from_user(&wait32, (void *)arg, sizeof(wait32)))
+ return -EFAULT;
+
+ wait.channel = wait32.channel;
+ wait.buffer = wait32.buffer;
+ wait.filltime.tv_sec = (time_t)wait32.filltime.tv_sec;
+ wait.filltime.tv_usec = (suseconds_t)wait32.filltime.tv_usec;
+
+ old_fs = get_fs();
+ set_fs(KERNEL_DS);
+ if (cmd == VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER)
+ ret = video1394_ioctl(file->f_dentry->d_inode, file,
+ VIDEO1394_IOC_LISTEN_QUEUE_BUFFER,
+ (unsigned long) &wait);
+ else
+ ret = video1394_ioctl(file->f_dentry->d_inode, file,
+ VIDEO1394_IOC_TALK_WAIT_BUFFER,
+ (unsigned long) &wait);
+ set_fs(old_fs);
+
+ return ret;
+}
+
+static int video1394_queue_buf32(unsigned int fd, unsigned int cmd, unsigned long arg,
+ struct file *file)
+{
+ if (file->f_op->ioctl != video1394_ioctl)
+ return -EFAULT;
+
+ return -EFAULT;
+
+ return video1394_ioctl(file->f_dentry->d_inode, file,
+ VIDEO1394_IOC_TALK_QUEUE_BUFFER, arg);
+}
+
+#endif /* CONFIG_COMPAT */
+
static void __exit video1394_exit_module (void)
{
+#ifdef CONFIG_COMPAT
+ int ret;
+
+ ret = unregister_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL);
+ ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_UNLISTEN_CHANNEL);
+ ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_TALK_CHANNEL);
+ ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_UNTALK_CHANNEL);
+ ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER);
+ ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER);
+ ret |= unregister_ioctl32_conversion(VIDEO1394_IOC_TALK_QUEUE_BUFFER);
+ ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_TALK_WAIT_BUFFER);
+ ret |= unregister_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_POLL_BUFFER);
+ if (ret)
+ PRINT_G(KERN_INFO, "Error unregistering ioctl32 translations");
+#endif
+
hpsb_unregister_highlevel (hl_handle);
devfs_unregister(devfs_handle);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394);
-
+
PRINT_G(KERN_INFO, "Removed " VIDEO1394_DRIVER_NAME " module");
}
static int __init video1394_init_module (void)
{
- if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394,
- THIS_MODULE, &video1394_fops)) {
+ int ret;
+
+ ret = ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_VIDEO1394,
+ THIS_MODULE, &video1394_fops);
+ if (ret) {
PRINT_G(KERN_ERR, "video1394: unable to get minor device block");
- return -EIO;
- }
-
+ return -EIO;
+ }
+
devfs_handle = devfs_mk_dir(NULL, VIDEO1394_DRIVER_NAME, NULL);
hl_handle = hpsb_register_highlevel (VIDEO1394_DRIVER_NAME, &hl_ops);
return -ENOMEM;
}
+#ifdef CONFIG_COMPAT
+ /* First the compatible ones */
+ ret = register_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL, NULL);
+ ret |= register_ioctl32_conversion(VIDEO1394_IOC_UNLISTEN_CHANNEL, NULL);
+ ret |= register_ioctl32_conversion(VIDEO1394_IOC_TALK_CHANNEL, NULL);
+ ret |= register_ioctl32_conversion(VIDEO1394_IOC_UNTALK_CHANNEL, NULL);
+
+ /* These need translation */
+ ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_QUEUE_BUFFER,
+ video1394_w_wait32);
+ ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_WAIT_BUFFER,
+ video1394_wr_wait32);
+ ret |= register_ioctl32_conversion(VIDEO1394_IOC_TALK_QUEUE_BUFFER,
+ video1394_queue_buf32);
+ ret |= register_ioctl32_conversion(VIDEO1394_IOC32_TALK_WAIT_BUFFER,
+ video1394_w_wait32);
+ ret |= register_ioctl32_conversion(VIDEO1394_IOC32_LISTEN_POLL_BUFFER,
+ video1394_wr_wait32);
+ if (ret)
+ PRINT_G(KERN_INFO, "Error registering ioctl32 translations");
+#endif
+
PRINT_G(KERN_INFO, "Installed " VIDEO1394_DRIVER_NAME " module");
return 0;
}
+
module_init(video1394_init_module);
module_exit(video1394_exit_module);