Commit 0943dcc1 authored by Ben Collins's avatar Ben Collins Committed by Linus Torvalds

[PATCH] IEEE-1394 Updates

ieee1394 updates:
  - New drivers: eth1394, admtp
  - nodemgr cleanup
  - Fixes for ohci
  - fixed for node probes
  - small misc performance fixes
  - New /proc interface for subsystem, node listing, and dv1394
parent 83ea848f
......@@ -90,6 +90,31 @@ CONFIG_IEEE1394_RAWIO
say M here and read <file:Documentation/modules.txt>. The module
will be called raw1394.o.
CONFIG_IEEE1394_ETH1394
Extremely Experimental! This driver is a Linux specific way to use your
IEEE1394 Host as an Ethernet type device. This is _NOT_ IP1394.
CONFIG_IEEE1394_AMDTP
This option enables the Audio & Music Data Transmission Protocol
(IEC61883-6) driver, which implements audio transmission over
IEEE1394.
The userspace interface is documented in amdtp.h.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called amdtp.o.
CONFIG_IEEE1394_CMP
This option enables the Connection Management Procedures
(IEC61883-1) driver, which implements input and output plugs.
If you want to compile this as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. The module
will be called amdtp.o.
CONFIG_IEEE1394_VERBOSEDEBUG
If you say Y here, you will get very verbose debugging logs from the
subsystem which includes a dump of the header of every sent and
......@@ -99,4 +124,3 @@ CONFIG_IEEE1394_VERBOSEDEBUG
Say Y if you really want or need the debugging output, everyone else
says N.
......@@ -19,8 +19,14 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
comment "Protocol Drivers"
dep_tristate ' OHCI-1394 Video support' CONFIG_IEEE1394_VIDEO1394 $CONFIG_IEEE1394_OHCI1394
dep_tristate ' SBP-2 support (Harddisks etc.)' CONFIG_IEEE1394_SBP2 $CONFIG_SCSI $CONFIG_IEEE1394
dep_tristate ' Ethernet over 1394' CONFIG_IEEE1394_ETH1394 $CONFIG_IEEE1394
dep_tristate ' OHCI-DV I/O support' CONFIG_IEEE1394_DV1394 $CONFIG_IEEE1394_OHCI1394
dep_tristate ' Raw IEEE1394 I/O support' CONFIG_IEEE1394_RAWIO $CONFIG_IEEE1394
dep_tristate ' IEC61883-1 Plug support' CONFIG_IEEE1394_CMP $CONFIG_IEEE1394
if [ "$CONFIG_IEEE1394_PCILYNX" != "n" ]; then
dep_tristate ' IEC61883-6 (Audio transmission) support' CONFIG_IEEE1394_AMDTP $CONFIG_IEEE1394_OHCI1394 $CONFIG_IEEE1394_CMP
fi
bool 'Excessive debugging output' CONFIG_IEEE1394_VERBOSEDEBUG
fi
......
......@@ -4,7 +4,7 @@
O_TARGET := ieee1394drv.o
export-objs := ieee1394_core.o ohci1394.o
export-objs := ieee1394_core.o ohci1394.o cmp.o
list-multi := ieee1394.o
ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
......@@ -17,6 +17,9 @@ obj-$(CONFIG_IEEE1394_VIDEO1394) += video1394.o
obj-$(CONFIG_IEEE1394_RAWIO) += raw1394.o
obj-$(CONFIG_IEEE1394_SBP2) += sbp2.o
obj-$(CONFIG_IEEE1394_DV1394) += dv1394.o
obj-$(CONFIG_IEEE1394_ETH1394) += eth1394.o
obj-$(CONFIG_IEEE1394_AMDTP) += amdtp.o
obj-$(CONFIG_IEEE1394_CMP) += cmp.o
include $(TOPDIR)/Rules.make
......
This diff is collapsed.
/* -*- c-basic-offset: 8 -*- */
#ifndef __AMDTP_H
#define __AMDTP_H
#include <asm/ioctl.h>
#include <asm/types.h>
/* The userspace interface for the Audio & Music Data Transmission
* Protocol driver is really simple. First, open /dev/amdtp, use the
* ioctl to configure format, rate, dimension and either plug or
* channel, then start writing samples.
*
* The formats supported by the driver are listed below.
* AMDTP_FORMAT_RAW corresponds to the AM824 raw format, which can
* carry any number of channels, so use this if you're streaming
* multichannel audio. The AMDTP_FORMAT_IEC958_PCM corresponds to the
* AM824 IEC958 encapsulation without the IEC958 data bit set, using
* AMDTP_FORMAT_IEC958_AC3 will transmit the samples with the data bit
* set, suitable for transmitting compressed AC-3 audio.
*
* The rate field specifies the transmission rate; supported values are
* AMDTP_RATE_32KHZ, AMDTP_RATE_44K1HZ and AMDTP_RATE_48KHZ.
*
* The dimension field specifies the dimension of the signal, that is,
* the number of audio channels. Only AMDTP_FORMAT_RAW supports
* settings greater than 2.
*
* The last thing to specify is either the isochronous channel to use
* or the output plug to connect to. If you know what channel the
* destination device will listen on, you can specify the channel
* directly and use the AMDTP_IOC_CHANNEL ioctl. However, if the
* destination device chooses the channel and uses the IEC61883-1 plug
* mechanism, you can specify an output plug to connect to. The
* driver will pick up the channel number from the plug once the
* destination device locks the output plug control register. In this
* case set the plug field and use the AMDTP_IOC_PLUG ioctl.
*
* Having configured the interface, the driver now accepts writes of
* regular 16 bit signed little endian samples, with the channels
* interleaved. For example, 4 channels would look like:
*
* | sample 0 | sample 1 ...
* | ch. 0 | ch. 1 | ch. 2 | ch. 3 | ch. 0 | ...
* | lsb | msb | lsb | msb | lsb | msb | lsb | msb | lsb | msb | ...
*
*/
/* We use '#' for our ioctl magic number because it's cool. */
#define AMDTP_IOC_CHANNEL _IOW('#', 0, sizeof (struct amdtp_ioctl))
#define AMDTP_IOC_PLUG _IOW('#', 1, sizeof (struct amdtp_ioctl))
#define AMDTP_IOC_PING _IOW('#', 2, sizeof (struct amdtp_ioctl))
#define AMDTP_IOC_ZAP _IO('#', 3)
enum {
AMDTP_FORMAT_RAW,
AMDTP_FORMAT_IEC958_PCM,
AMDTP_FORMAT_IEC958_AC3
};
enum {
AMDTP_RATE_32KHZ,
AMDTP_RATE_44K1HZ,
AMDTP_RATE_48KHZ,
};
struct amdtp_ioctl {
__u32 format;
__u32 rate;
__u32 dimension;
union { __u32 channel; __u32 plug; } u;
};
#endif /* __AMDTP_H */
/* -*- c-basic-offset: 8 -*-
*
* cmp.c - Connection Management Procedures
* Copyright (C) 2001 Kristian Hgsberg
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* TODO
* ----
*
* - Implement IEC61883-1 output plugs and connection management.
* This should probably be part of the general subsystem, as it could
* be shared with dv1394.
*
* - Add IEC61883 unit directory when loading this module. This
* requires a run-time changeable config rom.
*/
#include <linux/module.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/wait.h>
#include "hosts.h"
#include "highlevel.h"
#include "ieee1394.h"
#include "ieee1394_core.h"
#include "cmp.h"
struct plug {
union {
struct cmp_pcr pcr;
quadlet_t quadlet;
} u;
void (*update)(struct cmp_pcr *plug, void *data);
void *data;
};
struct cmp_host {
struct hpsb_host *host;
union {
struct cmp_mpr ompr;
quadlet_t ompr_quadlet;
} u;
struct plug opcr[2];
union {
struct cmp_mpr impr;
quadlet_t impr_quadlet;
} v;
struct plug ipcr[2];
struct list_head link;
};
enum {
CMP_P2P_CONNECTION,
CMP_BC_CONNECTION
};
#define CSR_PCR_MAP 0x900
#define CSR_PCR_MAP_END 0x9fc
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),
void *data)
{
struct cmp_host *ch;
struct plug *plug;
ch = lookup_cmp_host(host);
if (opcr_number >= ch->u.ompr.nplugs ||
ch->opcr[opcr_number].update != NULL)
return NULL;
plug = &ch->opcr[opcr_number];
plug->u.pcr.online = 1;
plug->u.pcr.bcast_count = 0;
plug->u.pcr.p2p_count = 0;
plug->u.pcr.overhead = 0;
plug->u.pcr.payload = payload;
plug->update = update;
plug->data = data;
return &plug->u.pcr;
}
void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *opcr)
{
struct cmp_host *ch;
struct plug *plug;
ch = lookup_cmp_host(host);
plug = (struct plug *)opcr;
if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG();
plug->u.pcr.online = 0;
plug->update = NULL;
}
static void reset_plugs(struct cmp_host *ch)
{
int i;
ch->u.ompr.non_persistent_ext = 0xff;
for (i = 0; i < ch->u.ompr.nplugs; i++) {
ch->opcr[i].u.pcr.bcast_count = 0;
ch->opcr[i].u.pcr.p2p_count = 0;
ch->opcr[i].u.pcr.overhead = 0;
}
}
static void cmp_add_host(struct hpsb_host *host)
{
struct cmp_host *ch;
ch = kmalloc(sizeof *ch, 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)
{
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);
kfree(ch);
}
static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
u64 addr, unsigned int length)
{
int csraddr = addr - CSR_REGISTER_BASE;
int plug;
struct cmp_host *ch;
if (length != 4)
return RCODE_TYPE_ERROR;
ch = lookup_cmp_host(host);
if (csraddr == 0x900) {
*buf = cpu_to_be32(ch->u.ompr_quadlet);
return RCODE_COMPLETE;
}
else if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
plug = (csraddr - 0x904) / 4;
*buf = cpu_to_be32(ch->opcr[plug].u.quadlet);
return RCODE_COMPLETE;
}
else if (csraddr < 0x980) {
return RCODE_ADDRESS_ERROR;
}
else if (csraddr == 0x980) {
*buf = cpu_to_be32(ch->v.impr_quadlet);
return RCODE_COMPLETE;
}
else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
plug = (csraddr - 0x984) / 4;
*buf = cpu_to_be32(ch->ipcr[plug].u.quadlet);
return RCODE_COMPLETE;
}
else
return RCODE_ADDRESS_ERROR;
}
static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
u64 addr, quadlet_t data, quadlet_t arg, int extcode)
{
int csraddr = addr - CSR_REGISTER_BASE;
int plug;
struct cmp_host *ch;
ch = lookup_cmp_host(host);
if (extcode != EXTCODE_COMPARE_SWAP)
return RCODE_TYPE_ERROR;
if (csraddr == 0x900) {
/* FIXME: Ignore writes to bits 30-31 and 0-7 */
*store = cpu_to_be32(ch->u.ompr_quadlet);
if (arg == cpu_to_be32(ch->u.ompr_quadlet))
ch->u.ompr_quadlet = be32_to_cpu(data);
return RCODE_COMPLETE;
}
if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
plug = (csraddr - 0x904) / 4;
*store = cpu_to_be32(ch->opcr[plug].u.quadlet);
if (arg == *store)
ch->opcr[plug].u.quadlet = be32_to_cpu(data);
if (be32_to_cpu(*store) != ch->opcr[plug].u.quadlet &&
ch->opcr[plug].update != NULL)
ch->opcr[plug].update(&ch->opcr[plug].u.pcr,
ch->opcr[plug].data);
return RCODE_COMPLETE;
}
else if (csraddr < 0x980) {
return RCODE_ADDRESS_ERROR;
}
else if (csraddr == 0x980) {
/* FIXME: Ignore writes to bits 24-31 and 0-7 */
*store = cpu_to_be32(ch->u.ompr_quadlet);
if (arg == cpu_to_be32(ch->u.ompr_quadlet))
ch->u.ompr_quadlet = be32_to_cpu(data);
return RCODE_COMPLETE;
}
else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
plug = (csraddr - 0x984) / 4;
*store = cpu_to_be32(ch->ipcr[plug].u.quadlet);
if (arg == *store)
ch->ipcr[plug].u.quadlet = be32_to_cpu(data);
if (be32_to_cpu(*store) != ch->ipcr[plug].u.quadlet &&
ch->ipcr[plug].update != NULL)
ch->ipcr[plug].update(&ch->ipcr[plug].u.pcr,
ch->ipcr[plug].data);
return RCODE_COMPLETE;
}
else
return RCODE_ADDRESS_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 struct hpsb_address_ops pcr_ops = {
read: pcr_read,
lock: pcr_lock,
};
/* Module interface */
MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");
MODULE_DESCRIPTION("Connection Management Procedures (CMP)");
MODULE_SUPPORTED_DEVICE("cmp");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(cmp_register_opcr);
EXPORT_SYMBOL(cmp_unregister_opcr);
static int __init cmp_init_module (void)
{
cmp_highlevel = hpsb_register_highlevel ("cmp",
&cmp_highlevel_ops);
if (cmp_highlevel == NULL) {
HPSB_ERR("cmp: unable to register highlevel ops");
return -EIO;
}
hpsb_register_addrspace(cmp_highlevel, &pcr_ops,
CSR_REGISTER_BASE + CSR_PCR_MAP,
CSR_REGISTER_BASE + CSR_PCR_MAP_END);
HPSB_INFO("Loaded CMP driver");
return 0;
}
static void __exit cmp_exit_module (void)
{
hpsb_unregister_highlevel(cmp_highlevel);
HPSB_INFO("Unloaded CMP driver");
}
module_init(cmp_init_module);
module_exit(cmp_exit_module);
#ifndef __CMP_H
#define __CMP_H
struct cmp_mpr {
u32 nplugs:5;
u32 reserved:3;
u32 persistent_ext:8;
u32 non_persistent_ext:8;
u32 bcast_channel_base:6;
u32 rate:2;
} __attribute__((packed));
struct cmp_pcr {
u32 payload:10;
u32 overhead:4;
u32 speed:2;
u32 channel:6;
u32 reserved:2;
u32 p2p_count:6;
u32 bcast_count:1;
u32 online:1;
} __attribute__((packed));
struct cmp_pcr *cmp_register_opcr(struct hpsb_host *host, int plug,
int payload,
void (*update)(struct cmp_pcr *plug,
void *data),
void *data);
void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *plug);
#endif /* __CMP_H */
......@@ -412,6 +412,10 @@ static inline dma_addr_t dma_offset_to_bus(struct dma_region *dma, unsigned long
/* struct video_card contains all data associated with one instance
of the dv1394 driver
*/
enum modes {
MODE_RECEIVE,
MODE_TRANSMIT
};
struct video_card {
......@@ -574,6 +578,7 @@ struct video_card {
unsigned int current_packet;
int first_frame; /* received first start frame marker? */
enum modes mode;
};
/*
......
This diff is collapsed.
This diff is collapsed.
/*
* eth1394.h -- Ethernet driver for Linux IEEE-1394 Subsystem
*
* Copyright (C) 2000 Bonin Franck <boninf@free.fr>
* (C) 2001 Ben Collins <bcollins@debian.org>
*
* Mainly based on work by Emanuel Pirker and Andreas E. Bombe
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __ETH1394_H
#define __ETH1394_H
/* Register for incoming packets. This is 8192 bytes, which supports up to
* 1600mbs. We'll need to change this if that ever becomes "small" :) */
#define ETHER1394_REGION_ADDR_LEN 8192
#define ETHER1394_REGION_ADDR 0xfffff0200000ULL
#define ETHER1394_REGION_ADDR_END (ETHER1394_REGION_ADDR + ETHER1394_REGION_ADDR_LEN)
/* Node set == 64 */
#define NODE_SET (ALL_NODES + 1)
/* Private structure for our ethernet driver */
struct eth1394_priv {
struct net_device_stats stats; /* Device stats */
struct hpsb_host *host; /* The card for this dev */
unsigned char max_rec[NODE_SET];/* Max payload per node */
unsigned char sspd[NODE_SET]; /* Max speed per node */
u16 fifo_hi[ALL_NODES]; /* 16bit hi fifo offset per node */
u32 fifo_lo[ALL_NODES]; /* 32bit lo fifo offset per node */
u64 eui[ALL_NODES]; /* EUI-64 per node */
spinlock_t lock; /* Private lock */
};
struct host_info {
struct list_head list;
struct hpsb_host *host;
struct net_device *dev;
};
/* This is our task struct. It's used for the complete_tq 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 tq_struct tq; /* The task */
};
/* IP1394 headers */
#include <asm/byteorder.h>
/* Unfragmented */
#if defined __BIG_ENDIAN_BITFIELD
struct eth1394_uf_hdr {
u8 lf:2;
u16 res:14;
u16 ether_type; /* Ethernet packet type */
} __attribute__((packed));
#elif defined __LITTLE_ENDIAN_BITFIELD
struct eth1394_uf_hdr {
u16 res:14;
u8 lf:2;
u16 ether_type;
} __attribute__((packed));
#else
#error Unknown bit field type
#endif
/* First fragment */
#if defined __BIG_ENDIAN_BITFIELD
struct eth1394_ff_hdr {
u8 lf:2;
u8 res1:2;
u16 dg_size:12; /* Datagram size */
u16 ether_type; /* Ethernet packet type */
u16 dgl; /* Datagram label */
u16 res2;
} __attribute__((packed));
#elif defined __LITTLE_ENDIAN_BITFIELD
struct eth1394_ff_hdr {
u16 dg_size:12;
u8 res1:2;
u8 lf:2;
u16 ether_type;
u16 dgl;
u16 res2;
} __attribute__((packed));
#else
#error Unknown bit field type
#endif
/* XXX: Subsequent fragments, including last */
#if defined __BIG_ENDIAN_BITFIELD
struct eth1394_sf_hdr {
u8 lf:2;
u8 res1:2;
u16 dg_size:12; /* Datagram size */
u8 res2:6;
u16 fg_off:10; /* Fragment offset */
u16 dgl; /* Datagram label */
u16 res3;
} __attribute__((packed));
#elif defined __LITTLE_ENDIAN_BITFIELD
struct eth1394_sf_hdr {
u16 dg_size:12;
u8 res1:2;
u8 lf:2;
u16 fg_off:10;
u8 res2:6;
u16 dgl;
u16 res3;
} __attribute__((packed));
#else
#error Unknown bit field type
#endif
#if defined __BIG_ENDIAN_BITFIELD
struct eth1394_common_hdr {
u8 lf:2;
u16 pad1:14;
} __attribute__((packed));
#elif defined __LITTLE_ENDIAN_BITFIELD
struct eth1394_common_hdr {
u16 pad1:14;
u8 lf:2;
} __attribute__((packed));
#else
#error Unknown bit field type
#endif
struct eth1394_hdr_words {
u16 word1;
u16 word2;
u16 word3;
u16 word4;
};
union eth1394_hdr {
struct eth1394_common_hdr common;
struct eth1394_uf_hdr uf;
struct eth1394_ff_hdr ff;
struct eth1394_sf_hdr sf;
struct eth1394_hdr_words words;
};
/* End of IP1394 headers */
/* Fragment types */
#define ETH1394_HDR_LF_UF 0 /* unfragmented */
#define ETH1394_HDR_LF_FF 1 /* first fragment */
#define ETH1394_HDR_LF_LF 2 /* last fragment */
#define ETH1394_HDR_LF_IF 3 /* interior fragment */
#define IP1394_HW_ADDR_LEN 16 /* As per RFC */
/* Our arp packet (ARPHRD_IEEE1394) */
struct eth1394_arp {
u16 hw_type; /* 0x0018 */
u16 proto_type; /* 0x0806 */
u8 hw_addr_len; /* 16 */
u8 ip_addr_len; /* 4 */
u16 opcode; /* ARP Opcode */
/* Above is exactly the same format as struct arphdr */
u64 s_uniq_id; /* Sender's 64bit EUI */
u8 max_rec; /* Sender's max packet size */
u8 sspd; /* Sender's max speed */
u16 fifo_hi; /* hi 16bits of sender's FIFO addr */
u32 fifo_lo; /* lo 32bits of sender's FIFO addr */
u32 sip; /* Sender's IP Address */
u32 tip; /* IP Address of requested hw addr */
};
/* Network timeout */
#define ETHER1394_TIMEOUT 100000
#endif /* __ETH1394_H */
......@@ -43,6 +43,16 @@ static struct hpsb_host_operations dummy_ops = {
devctl: dummy_devctl
};
/**
* hpsb_ref_host - increase reference count for host controller.
* @host: the host controller
*
* Increase the reference count for the specified host controller.
* When holding a reference to a host, the memory allocated for the
* host struct will not be freed and the host is guaranteed to be in a
* consistent state. The driver may be unloaded or the controller may
* be removed (PCMCIA), but the host struct will remain valid.
*/
int hpsb_ref_host(struct hpsb_host *host)
{
......@@ -53,18 +63,26 @@ int hpsb_ref_host(struct hpsb_host *host)
spin_lock_irqsave(&hosts_lock, flags);
list_for_each(lh, &hosts) {
if (host == list_entry(lh, struct hpsb_host, host_list)) {
if (host->ops->devctl(host, MODIFY_USAGE, 1)) {
host->refcount++;
retval = 1;
}
host->ops->devctl(host, MODIFY_USAGE, 1);
host->refcount++;
retval = 1;
break;
}
}
}
spin_unlock_irqrestore(&hosts_lock, flags);
return retval;
}
/**
* hpsb_unref_host - decrease reference count for host controller.
* @host: the host controller
*
* Decrease the reference count for the specified host controller.
* When the reference count reaches zero, the memory allocated for the
* &hpsb_host will be freed.
*/
void hpsb_unref_host(struct hpsb_host *host)
{
unsigned long flags;
......@@ -74,23 +92,44 @@ void hpsb_unref_host(struct hpsb_host *host)
spin_lock_irqsave(&hosts_lock, flags);
host->refcount--;
if (!host->refcount && !host->is_shutdown)
if (!host->refcount && host->is_shutdown)
kfree(host);
spin_unlock_irqrestore(&hosts_lock, flags);
}
/**
* hpsb_alloc_host - allocate a new host controller.
* @drv: the driver that will manage the host controller
* @extra: number of extra bytes to allocate for the driver
*
* Allocate a &hpsb_host and initialize the general subsystem specific
* fields. If the driver needs to store per host data, as drivers
* usually do, the amount of memory required can be specified by the
* @extra parameter. Once allocated, the driver should initialize the
* driver specific parts, enable the controller and make it available
* to the general subsystem using hpsb_add_host().
*
* The &hpsb_host is allocated with an single initial reference
* belonging to the driver. Once the driver is done with the struct,
* for example, when the driver is unloaded, it should release this
* reference using hpsb_unref_host().
*
* Return Value: a pointer to the &hpsb_host if succesful, %NULL if
* no memory was available.
*/
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra)
{
struct hpsb_host *h;
h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL);
if (!h) return NULL;
memset(h, 0, sizeof(struct hpsb_host));
memset(h, 0, sizeof(struct hpsb_host) + extra);
h->hostdata = h + 1;
h->driver = drv;
h->ops = drv->ops;
h->hostdata = h + 1;
h->refcount = 1;
INIT_LIST_HEAD(&h->pending_packets);
spin_lock_init(&h->pending_pkt_lock);
......@@ -134,9 +173,7 @@ void hpsb_remove_host(struct hpsb_host *host)
spin_lock_irqsave(&hosts_lock, flags);
list_del(&host->driver_list);
list_del(&host->host_list);
drv->number_of_hosts--;
if (!host->refcount) kfree(host);
spin_unlock_irqrestore(&hosts_lock, flags);
}
......
......@@ -36,6 +36,7 @@ struct hpsb_host {
int node_count; /* number of identified nodes on this bus */
int selfid_count; /* total number of SelfIDs received */
int nodes_active; /* number of nodes that are actually active */
nodeid_t node_id; /* node ID of this host */
nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
......
......@@ -41,6 +41,10 @@ MODULE_PARM(disable_nodemgr, "i");
MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
static int disable_nodemgr = 0;
MODULE_PARM(disable_hotplug, "i");
MODULE_PARM_DESC(disable_hotplug, "Disable hotplug for detected nodes.");
static int disable_hotplug = 0;
/* We are GPL, so treat us special */
MODULE_LICENSE("GPL");
......@@ -108,7 +112,7 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size)
packet->data_size = data_size;
}
INIT_TQ_HEAD(packet->complete_tq);
INIT_LIST_HEAD(&packet->complete_tq);
INIT_LIST_HEAD(&packet->list);
sema_init(&packet->state_change, 0);
packet->state = hpsb_unused;
......@@ -177,6 +181,8 @@ static int check_selfids(struct hpsb_host *host)
struct ext_selfid *esid;
int esid_seq = 23;
host->nodes_active = 0;
while (rest_of_selfids--) {
if (!sid->extended) {
nodeid++;
......@@ -188,9 +194,11 @@ static int check_selfids(struct hpsb_host *host)
return 0;
}
if (sid->contender && sid->link_active) {
host->irm_id = LOCAL_BUS | sid->phy_id;
}
if (sid->link_active) {
host->nodes_active++;
if (sid->contender)
host->irm_id = LOCAL_BUS | sid->phy_id;
}
} else {
esid = (struct ext_selfid *)sid;
......@@ -224,7 +232,8 @@ static int check_selfids(struct hpsb_host *host)
return 0;
}
return nodeid + 1;
host->node_count = nodeid + 1;
return 1;
}
static void build_speed_map(struct hpsb_host *host, int nodecount)
......@@ -322,8 +331,7 @@ void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot)
host->node_id = LOCAL_BUS | phyid;
host->is_root = isroot;
host->node_count = check_selfids(host);
if (!host->node_count) {
if (!check_selfids(host)) {
if (host->reset_retries++ < 20) {
/* selfid stage did not complete without error */
HPSB_NOTICE("Error in SelfID stage, resetting");
......@@ -803,8 +811,8 @@ static rwlock_t ieee1394_chardevs_lock = RW_LOCK_UNLOCKED;
static int ieee1394_dispatch_open(struct inode *inode, struct file *file);
static struct file_operations ieee1394_chardev_ops = {
OWNER_THIS_MODULE
open: ieee1394_dispatch_open,
owner: THIS_MODULE,
open: ieee1394_dispatch_open,
};
devfs_handle_t ieee1394_devfs_handle;
......@@ -828,8 +836,6 @@ int ieee1394_register_chardev(int blocknum,
ieee1394_chardevs[blocknum].module = module;
retval = 0;
V22_COMPAT_MOD_INC_USE_COUNT;
} else {
/* block already taken */
retval = -EBUSY;
......@@ -851,7 +857,6 @@ void ieee1394_unregister_chardev(int blocknum)
if(ieee1394_chardevs[blocknum].file_ops) {
ieee1394_chardevs[blocknum].file_ops = NULL;
ieee1394_chardevs[blocknum].module = NULL;
V22_COMPAT_MOD_DEC_USE_COUNT;
}
write_unlock(&ieee1394_chardevs_lock);
......@@ -868,12 +873,6 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
/*
Maintaining correct module reference counts is tricky here!
For Linux v2.2:
The task-specific driver is expected to maintain its own
reference count via V22_COMPAT_MOD_[INC,DEC]_USE_COUNT.
We don't need to do anything special.
For Linux v2.4 and later:
The key thing to remember is that the VFS increments the
......@@ -894,17 +893,10 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
/* 2.2 */
#define INCREF(mod) do {} while (0)
#define DECREF(mod) do {} while (0)
#else
/* 2.4 */
#define INCREF(mod_) do { struct module *mod = (struct module*) mod_; \
if(mod != NULL) __MOD_INC_USE_COUNT(mod); } while(0)
#define DECREF(mod_) do { struct module *mod = (struct module*) mod_; \
if(mod != NULL) __MOD_DEC_USE_COUNT(mod); } while(0)
#endif
/* shift away lower four bits of the minor
to get the index of the ieee1394_driver
......@@ -1013,7 +1005,7 @@ static int __init ieee1394_init(void)
init_hpsb_highlevel();
init_csr();
if (!disable_nodemgr)
init_ieee1394_nodemgr();
init_ieee1394_nodemgr(disable_hotplug);
else
HPSB_INFO("nodemgr functionality disabled");
......@@ -1099,8 +1091,10 @@ EXPORT_SYMBOL(highlevel_host_reset);
EXPORT_SYMBOL(hpsb_guid_get_entry);
EXPORT_SYMBOL(hpsb_nodeid_get_entry);
EXPORT_SYMBOL(hpsb_get_host_by_ne);
EXPORT_SYMBOL(hpsb_guid_fill_packet);
EXPORT_SYMBOL(hpsb_node_fill_packet);
EXPORT_SYMBOL(hpsb_node_read);
EXPORT_SYMBOL(hpsb_node_write);
EXPORT_SYMBOL(hpsb_node_lock);
EXPORT_SYMBOL(hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
EXPORT_SYMBOL(hpsb_release_unit_directory);
......
......@@ -415,8 +415,8 @@ struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
* avoid in kernel buffers for user space callers
*/
int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
quadlet_t *buffer, size_t length)
int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t *buffer, size_t length)
{
struct hpsb_packet *packet;
int retval = 0;
......@@ -447,7 +447,7 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
return -ENOMEM;
}
packet->generation = get_hpsb_generation(host);
packet->generation = generation;
if (!hpsb_send_packet(packet)) {
retval = -EINVAL;
goto hpsb_read_fail;
......@@ -496,8 +496,8 @@ struct hpsb_packet *hpsb_make_packet (struct hpsb_host *host, nodeid_t node,
return packet;
}
int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
quadlet_t *buffer, size_t length)
int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t *buffer, size_t length)
{
struct hpsb_packet *packet;
int retval;
......@@ -522,7 +522,7 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
if (!packet)
return -ENOMEM;
packet->generation = get_hpsb_generation(host);
packet->generation = generation;
if (!hpsb_send_packet(packet)) {
retval = -EINVAL;
goto hpsb_write_fail;
......@@ -541,8 +541,8 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
/* We need a hpsb_lock64 function for the 64 bit equivalent. Probably. */
int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
quadlet_t *data, quadlet_t arg)
int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
{
struct hpsb_packet *packet;
int retval = 0, length;
......@@ -588,7 +588,7 @@ int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
}
fill_async_lock(packet, addr, extcode, length);
packet->generation = get_hpsb_generation(host);
packet->generation = generation;
if (!hpsb_send_packet(packet)) {
retval = -EINVAL;
goto hpsb_lock_fail;
......
......@@ -63,14 +63,16 @@ int hpsb_packet_success(struct hpsb_packet *packet);
* The generic read, write and lock functions. All recognize the local node ID
* and act accordingly. Read and write automatically use quadlet commands if
* length == 4 and and block commands otherwise (however, they do not yet
* support lengths that are not a multiple of 4).
* support lengths that are not a multiple of 4). You must explicitly specifiy
* the generation for which the node ID is valid, to avoid sending packets to
* the wrong nodes when we race with a bus reset.
*/
int hpsb_read(struct hpsb_host *host, nodeid_t node, u64 addr,
quadlet_t *buffer, size_t length);
int hpsb_write(struct hpsb_host *host, nodeid_t node, u64 addr,
quadlet_t *buffer, size_t length);
int hpsb_lock(struct hpsb_host *host, nodeid_t node, u64 addr, int extcode,
quadlet_t *data, quadlet_t arg);
int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t *buffer, size_t length);
int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t *buffer, size_t length);
int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
/* Generic packet creation. Used by hpsb_write. Also useful for protocol
* drivers that want to implement their own hpsb_write replacement. */
......
......@@ -10,17 +10,6 @@
#include <asm/byteorder.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
#include "linux22compat.h"
#else
#define V22_COMPAT_MOD_INC_USE_COUNT do {} while (0)
#define V22_COMPAT_MOD_DEC_USE_COUNT do {} while (0)
#define OWNER_THIS_MODULE owner: THIS_MODULE,
#define INIT_TQ_LINK(tq) INIT_LIST_HEAD(&(tq).list)
#define INIT_TQ_HEAD(tq) INIT_LIST_HEAD(&(tq))
#endif
/* The great kdev_t changeover in 2.5.x */
#include <linux/kdev_t.h>
#ifndef minor
......@@ -48,11 +37,7 @@
#endif /* Linux version < 2.4.12 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
#include <asm/spinlock.h>
#else
#include <linux/spinlock.h>
#endif
#ifndef list_for_each_safe
#define list_for_each_safe(pos, n, head) \
......@@ -61,6 +46,10 @@
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5)
#define pte_offset_kernel pte_offset
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
......@@ -78,7 +67,8 @@ typedef u16 nodeid_t;
#define LOCAL_BUS 0xffc0
#define ALL_NODES 0x003f
#define NODE_BUS_FMT "%d:%d"
/* 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)
......
This diff is collapsed.
......@@ -125,7 +125,7 @@ struct node_entry {
struct hpsb_host *host; /* Host this node is attached to */
nodeid_t nodeid; /* NodeID */
struct bus_options busopt; /* Bus Options */
atomic_t generation; /* Synced with hpsb generation */
unsigned int generation; /* Synced with hpsb generation */
/* The following is read from the config rom */
u32 vendor_id;
......@@ -138,7 +138,7 @@ struct node_entry {
static inline int hpsb_node_entry_valid(struct node_entry *ne)
{
return atomic_read(&ne->generation) == get_hpsb_generation(ne->host);
return ne->generation == get_hpsb_generation(ne->host);
}
/*
......@@ -170,10 +170,17 @@ struct hpsb_host *hpsb_get_host_by_ne(struct node_entry *ne);
* number). It will at least reliably fail so that you don't accidentally and
* unknowingly send your packet to the wrong node.
*/
int hpsb_guid_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt);
void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *pkt);
int hpsb_node_read(struct node_entry *ne, u64 addr,
quadlet_t *buffer, size_t length);
int hpsb_node_write(struct node_entry *ne, u64 addr,
quadlet_t *buffer, size_t length);
int hpsb_node_lock(struct node_entry *ne, u64 addr,
int extcode, quadlet_t *data, quadlet_t arg);
void init_ieee1394_nodemgr(void);
void init_ieee1394_nodemgr(int disable_hotplug);
void cleanup_ieee1394_nodemgr(void);
#endif /* _IEEE1394_NODEMGR_H */
......@@ -96,7 +96,6 @@
#include <linux/poll.h>
#include <asm/byteorder.h>
#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/tqueue.h>
#include <linux/delay.h>
......@@ -161,7 +160,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
static char version[] __devinitdata =
"$Revision: 1.91 $ Ben Collins <bcollins@debian.org>";
"$Revision: 1.101 $ Ben Collins <bcollins@debian.org>";
/* Module Parameters */
MODULE_PARM(attempt_root,"i");
......@@ -487,7 +486,6 @@ static void ohci_init_config_rom(struct ti_ohci *ohci);
/* Global initialization */
static void ohci_initialize(struct ti_ohci *ohci)
{
int i;
quadlet_t buf;
spin_lock_init(&ohci->phy_reg_lock);
......@@ -535,14 +533,6 @@ static void ohci_initialize(struct ti_ohci *ohci)
/* Don't accept phy packets into AR request context */
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
/* Initialize IR dma */
for (i=0;i<ohci->nb_iso_rcv_ctx;i++) {
reg_write(ohci, OHCI1394_IsoRcvContextControlClear+32*i,
0xffffffff);
reg_write(ohci, OHCI1394_IsoRcvContextMatch+32*i, 0);
reg_write(ohci, OHCI1394_IsoRcvCommandPtr+32*i, 0);
}
/* Set bufferFill, isochHeader, multichannel for IR context */
reg_write(ohci, OHCI1394_IsoRcvContextControlSet, 0xd0000000);
......@@ -553,13 +543,6 @@ static void ohci_initialize(struct ti_ohci *ohci)
reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 0xffffffff);
reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 0xffffffff);
/* Initialize IT dma */
for (i=0;i<ohci->nb_iso_xmit_ctx;i++) {
reg_write(ohci, OHCI1394_IsoXmitContextControlClear+32*i,
0xffffffff);
reg_write(ohci, OHCI1394_IsoXmitCommandPtr+32*i, 0);
}
/* Clear the interrupt mask */
reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 0xffffffff);
reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
......@@ -615,7 +598,8 @@ static void ohci_initialize(struct ti_ohci *ohci)
OHCI1394_respTxComplete |
OHCI1394_reqTxComplete |
OHCI1394_isochRx |
OHCI1394_isochTx);
OHCI1394_isochTx |
OHCI1394_cycleInconsistent);
/* Enable link */
reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
......@@ -936,6 +920,7 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
} else {
MOD_DEC_USE_COUNT;
}
retval = 1;
break;
case ISO_LISTEN_CHANNEL:
......@@ -1098,6 +1083,14 @@ static void ohci_irq_handler(int irq, void *dev_id,
return;
}
if (event & OHCI1394_cycleInconsistent) {
/* We subscribe to the cycleInconsistent event only to
* clear the corresponding event bit... otherwise,
* isochronous cycleMatch DMA wont work. */
DBGMSG(ohci->id, "OHCI1394_cycleInconsistent");
event &= ~OHCI1394_cycleInconsistent;
}
if (event & OHCI1394_busReset) {
/* The busReset event bit can't be cleared during the
* selfID phase, so we disable busReset interrupts, to
......@@ -1265,8 +1258,8 @@ static void ohci_irq_handler(int irq, void *dev_id,
/* Finally, we clear the busReset event and reenable
* the busReset interrupt. */
spin_lock_irqsave(&ohci->event_lock, flags);
reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
reg_write(ohci, OHCI1394_IntMaskSet, OHCI1394_busReset);
spin_unlock_irqrestore(&ohci->event_lock, flags);
event &= ~OHCI1394_selfIDComplete;
}
......@@ -1509,6 +1502,15 @@ static void dma_trm_tasklet (unsigned long data)
/* this packet hasn't been sent yet*/
break;
if (!(ack & 0x10)) {
/* XXX: This is an OHCI evt_* code. We need to handle
* this specially! For right now, we just fake an
* ackx_send_error. */
PRINT(KERN_DEBUG, ohci->id, "Received OHCI evt_* error 0x%x",
ack & 0xf);
ack = (ack & 0xffe0) | ACK_BUSY_A;
}
#ifdef OHCI1394_DEBUG
if (datasize)
DBGMSG(ohci->id,
......@@ -1942,7 +1944,8 @@ static void ohci_init_config_rom(struct ti_ohci *ohci)
/* Root directory */
cf_unit_begin(&cr, 1);
cf_put_keyval(&cr, 0x03, 0x00005e); /* Vendor ID */
/* Vendor ID */
cf_put_keyval(&cr, 0x03, reg_read(ohci,OHCI1394_VendorID) & 0xFFFFFF);
cf_put_refer(&cr, 0x81, 2); /* Textual description unit */
cf_put_keyval(&cr, 0x0c, 0x0083c0); /* Node capabilities */
/* NOTE: Add other unit referers here, and append at bottom */
......@@ -2287,7 +2290,7 @@ static void __devexit ohci1394_pci_remove(struct pci_dev *pdev)
#endif /* CONFIG_ALL_PPC */
pci_set_drvdata(ohci->dev, NULL);
kfree(ohci);
hpsb_unref_host(ohci->host);
}
#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
......
......@@ -22,6 +22,7 @@
#define _OHCI1394_H
#include "ieee1394_types.h"
#include <asm/io.h>
#define OHCI1394_DRIVER_NAME "ohci1394"
......@@ -192,7 +193,7 @@ struct ti_ohci {
/* IRQ hooks, for video1394 and dv1394 */
#define OHCI1394_MAX_IRQ_HOOKS 4
#define OHCI1394_MAX_IRQ_HOOKS 16
struct ohci1394_irq_hook {
void (*irq_handler) (int card, quadlet_t isoRecvEvent,
......@@ -314,7 +315,7 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
#define OHCI1394_AsRspRcvCommandPtr 0x1EC
/* Isochronous transmit registers */
/* Add (32 * n) for context n */
/* Add (16 * n) for context n */
#define OHCI1394_IsoXmitContextBase 0x200
#define OHCI1394_IsoXmitContextControlSet 0x200
#define OHCI1394_IsoXmitContextControlClear 0x204
......@@ -363,6 +364,28 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
#define DMA_CTL_BRANCH 0x000c0000
#define DMA_CTL_WAIT 0x00030000
/* OHCI evt_* error types, table 3-2 of the OHCI 1.1 spec. */
#define EVT_NO_STATUS 0x0 /* No event status */
#define EVT_RESERVED 0x1 /* Reserved, not used !!! */
#define EVT_LONG_PACKET 0x2 /* The revc data was longer than the buf */
#define EVT_MISSING_ACK 0x3 /* A subaction gap was detected before an ack
arrived, or recv'd ack had a parity error */
#define EVT_UNDERRUN 0x4 /* Underrun on corresponding FIFO, packet
truncated */
#define EVT_OVERRUN 0x5 /* A recv FIFO overflowed on reception of ISO
packet */
#define EVT_DESCRIPTOR_READ 0x6 /* An unrecoverable error occured while host was
reading a descriptor block */
#define EVT_DATA_READ 0x7 /* An error occured while host controller was
attempting to read from host memory in the data
stage of descriptor processing */
#define EVT_DATA_WRITE 0x8 /* An error occured while host controller was
attempting to write either during the data stage
of descriptor processing, or when processing a single
16-bit host memory write */
#define EVT_BUS_RESET 0x9 /* Identifies a PHY packet in the recv buffer as
being a synthesized bus reset packet */
#define OHCI1394_TCODE_PHY 0xE
void ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
......
......@@ -29,7 +29,6 @@
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/smp_lock.h>
#include <asm/byteorder.h>
#include <asm/atomic.h>
#include <asm/io.h>
......@@ -56,6 +55,7 @@
#define PRINTD(level, card, fmt, args...) do {} while (0)
#endif
static struct hpsb_host_driver *lynx_driver;
static unsigned int card_id;
......@@ -614,7 +614,7 @@ static ssize_t mem_write(struct file*, const char*, size_t, loff_t*);
static struct file_operations aux_ops = {
OWNER_THIS_MODULE
owner: THIS_MODULE,
read: mem_read,
write: mem_write,
poll: aux_poll,
......@@ -639,42 +639,31 @@ static int mem_open(struct inode *inode, struct file *file)
enum { t_rom, t_aux, t_ram } type;
struct memdata *md;
V22_COMPAT_MOD_INC_USE_COUNT;
if (cid < PCILYNX_MINOR_AUX_START) {
/* just for completeness */
V22_COMPAT_MOD_DEC_USE_COUNT;
return -ENXIO;
} else if (cid < PCILYNX_MINOR_ROM_START) {
cid -= PCILYNX_MINOR_AUX_START;
if (cid >= num_of_cards || !cards[cid].aux_port) {
V22_COMPAT_MOD_DEC_USE_COUNT;
if (cid >= num_of_cards || !cards[cid].aux_port)
return -ENXIO;
}
type = t_aux;
} else if (cid < PCILYNX_MINOR_RAM_START) {
cid -= PCILYNX_MINOR_ROM_START;
if (cid >= num_of_cards || !cards[cid].local_rom) {
V22_COMPAT_MOD_DEC_USE_COUNT;
if (cid >= num_of_cards || !cards[cid].local_rom)
return -ENXIO;
}
type = t_rom;
} else {
/* WARNING: Know what you are doing when opening RAM.
* It is currently used inside the driver! */
cid -= PCILYNX_MINOR_RAM_START;
if (cid >= num_of_cards || !cards[cid].local_ram) {
V22_COMPAT_MOD_DEC_USE_COUNT;
if (cid >= num_of_cards || !cards[cid].local_ram)
return -ENXIO;
}
type = t_ram;
}
md = (struct memdata *)kmalloc(sizeof(struct memdata), SLAB_KERNEL);
if (md == NULL) {
V22_COMPAT_MOD_DEC_USE_COUNT;
if (md == NULL)
return -ENOMEM;
}
md->lynx = &cards[cid];
md->cid = cid;
......@@ -700,11 +689,7 @@ static int mem_open(struct inode *inode, struct file *file)
static int mem_release(struct inode *inode, struct file *file)
{
struct memdata *md = (struct memdata *)file->private_data;
kfree(md);
V22_COMPAT_MOD_DEC_USE_COUNT;
kfree(file->private_data);
return 0;
}
......@@ -732,9 +717,8 @@ static unsigned int aux_poll(struct file *file, poll_table *pt)
loff_t mem_llseek(struct file *file, loff_t offs, int orig)
{
loff_t newoffs = -1;
loff_t newoffs;
lock_kernel();
switch (orig) {
case 0:
newoffs = offs;
......@@ -744,14 +728,13 @@ loff_t mem_llseek(struct file *file, loff_t offs, int orig)
break;
case 2:
newoffs = PCILYNX_MAX_MEMORY + 1 + offs;
}
if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) {
unlock_kernel();
break;
default:
return -EINVAL;
}
unlock_kernel();
if (newoffs < 0 || newoffs > PCILYNX_MAX_MEMORY + 1) return -EINVAL;
file->f_pos = newoffs;
return newoffs;
}
......@@ -1229,7 +1212,7 @@ static void remove_card(struct pci_dev *dev)
}
tasklet_kill(&lynx->iso_rcv.tq);
kfree(lynx);
hpsb_unref_host(lynx->host);
}
......
......@@ -21,10 +21,7 @@
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
#include <linux/devfs_fs_kernel.h>
#endif
#include "ieee1394.h"
#include "ieee1394_types.h"
......@@ -919,13 +916,9 @@ static int raw1394_open(struct inode *inode, struct file *file)
return -ENXIO;
}
V22_COMPAT_MOD_INC_USE_COUNT;
fi = kmalloc(sizeof(struct file_info), SLAB_KERNEL);
if (fi == NULL) {
V22_COMPAT_MOD_DEC_USE_COUNT;
if (fi == NULL)
return -ENOMEM;
}
memset(fi, 0, sizeof(struct file_info));
......@@ -988,7 +981,6 @@ static int raw1394_release(struct inode *inode, struct file *file)
kfree(fi);
V22_COMPAT_MOD_DEC_USE_COUNT;
return 0;
}
......@@ -1001,12 +993,12 @@ static struct hpsb_highlevel_ops hl_ops = {
};
static struct file_operations file_ops = {
OWNER_THIS_MODULE
read: raw1394_read,
write: raw1394_write,
poll: raw1394_poll,
open: raw1394_open,
release: raw1394_release,
owner: THIS_MODULE,
read: raw1394_read,
write: raw1394_write,
poll: raw1394_poll,
open: raw1394_open,
release: raw1394_release,
};
static int __init init_raw1394(void)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment