Merge branch 'ieee1394-removal' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6
* 'ieee1394-removal' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: ieee1394: remove the old IEEE 1394 driver stack ieee1394: move init_ohci1394_dma to drivers/firewire/ Fix trivial change/delete conflict: drivers/ieee1394/eth1394.c is getting removed, but was modified by the networking merge.
This commit is contained in:
commit
b7d41a9fbb
|
@ -1,9 +0,0 @@
|
|||
What: dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
|
||||
Contact: linux1394-devel@lists.sourceforge.net
|
||||
Description:
|
||||
New application development should use raw1394 + userspace libraries
|
||||
instead, notably libiec61883 which is functionally equivalent.
|
||||
|
||||
Users:
|
||||
ffmpeg/libavformat (used by a variety of media players)
|
||||
dvgrab v1.x (replaced by dvgrab2 on top of raw1394 and resp. libraries)
|
|
@ -0,0 +1,14 @@
|
|||
What: dv1394 (a.k.a. "OHCI-DV I/O support" for FireWire)
|
||||
Date: May 2010 (scheduled), finally removed in kernel v2.6.37
|
||||
Contact: linux1394-devel@lists.sourceforge.net
|
||||
Description:
|
||||
/dev/dv1394/* were character device files, one for each FireWire
|
||||
controller and for NTSC and PAL respectively, from which DV data
|
||||
could be received by read() or transmitted by write(). A few
|
||||
ioctl()s allowed limited control.
|
||||
This special-purpose interface has been superseded by libraw1394 +
|
||||
libiec61883 which are functionally equivalent, support HDV, and
|
||||
transparently work on top of the newer firewire kernel drivers.
|
||||
|
||||
Users:
|
||||
ffmpeg/libavformat (if configured for DV1394)
|
|
@ -0,0 +1,15 @@
|
|||
What: raw1394 (a.k.a. "Raw IEEE1394 I/O support" for FireWire)
|
||||
Date: May 2010 (scheduled), finally removed in kernel v2.6.37
|
||||
Contact: linux1394-devel@lists.sourceforge.net
|
||||
Description:
|
||||
/dev/raw1394 was a character device file that allowed low-level
|
||||
access to FireWire buses. Its major drawbacks were its inability
|
||||
to implement sensible device security policies, and its low level
|
||||
of abstraction that required userspace clients do duplicate much
|
||||
of the kernel's ieee1394 core functionality.
|
||||
Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
|
||||
firewire-core.
|
||||
|
||||
Users:
|
||||
libraw1394 (works with firewire-cdev too, transparent to library ABI
|
||||
users)
|
|
@ -1,16 +0,0 @@
|
|||
What: legacy isochronous ABI of raw1394 (1st generation iso ABI)
|
||||
Date: June 2007 (scheduled), removed in kernel v2.6.23
|
||||
Contact: linux1394-devel@lists.sourceforge.net
|
||||
Description:
|
||||
The two request types RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN have
|
||||
been deprecated for quite some time. They are very inefficient as they
|
||||
come with high interrupt load and several layers of callbacks for each
|
||||
packet. Because of these deficiencies, the video1394 and dv1394 drivers
|
||||
and the 3rd-generation isochronous ABI in raw1394 (rawiso) were created.
|
||||
|
||||
Users:
|
||||
libraw1394 users via the long deprecated API raw1394_iso_write,
|
||||
raw1394_start_iso_write, raw1394_start_iso_rcv, raw1394_stop_iso_rcv
|
||||
|
||||
libdc1394, which optionally uses these old libraw1394 calls
|
||||
alternatively to the more efficient video1394 ABI
|
|
@ -0,0 +1,16 @@
|
|||
What: video1394 (a.k.a. "OHCI-1394 Video support" for FireWire)
|
||||
Date: May 2010 (scheduled), finally removed in kernel v2.6.37
|
||||
Contact: linux1394-devel@lists.sourceforge.net
|
||||
Description:
|
||||
/dev/video1394/* were character device files, one for each FireWire
|
||||
controller, which were used for isochronous I/O. It was added as an
|
||||
alternative to raw1394's isochronous I/O functionality which had
|
||||
performance issues in its first generation. Any video1394 user had
|
||||
to use raw1394 + libraw1394 too because video1394 did not provide
|
||||
asynchronous I/O for device discovery and configuration.
|
||||
Replaced by /dev/fw*, i.e. the <linux/firewire-cdev.h> ABI of
|
||||
firewire-core.
|
||||
|
||||
Users:
|
||||
libdc1394 (works with firewire-cdev too, transparent to library ABI
|
||||
users)
|
|
@ -502,16 +502,6 @@ Who: Thomas Gleixner <tglx@linutronix.de>
|
|||
|
||||
----------------------------
|
||||
|
||||
What: old ieee1394 subsystem (CONFIG_IEEE1394)
|
||||
When: 2.6.37
|
||||
Files: drivers/ieee1394/ except init_ohci1394_dma.c
|
||||
Why: superseded by drivers/firewire/ (CONFIG_FIREWIRE) which offers more
|
||||
features, better performance, and better security, all with smaller
|
||||
and more modern code base
|
||||
Who: Stefan Richter <stefanr@s5r6.in-berlin.de>
|
||||
|
||||
----------------------------
|
||||
|
||||
What: The acpi_sleep=s4_nonvs command line option
|
||||
When: 2.6.37
|
||||
Files: arch/x86/kernel/acpi/sleep.c
|
||||
|
|
|
@ -51,7 +51,6 @@ obj-y += net/
|
|||
obj-$(CONFIG_ATM) += atm/
|
||||
obj-$(CONFIG_FUSION) += message/
|
||||
obj-y += firewire/
|
||||
obj-y += ieee1394/
|
||||
obj-$(CONFIG_UIO) += uio/
|
||||
obj-y += cdrom/
|
||||
obj-y += auxdisplay/
|
||||
|
|
|
@ -3,9 +3,6 @@ menu "IEEE 1394 (FireWire) support"
|
|||
# firewire-core does not depend on PCI but is
|
||||
# not useful without PCI controller driver
|
||||
|
||||
comment "You can enable one or both FireWire driver stacks."
|
||||
comment "The newer stack is recommended."
|
||||
|
||||
config FIREWIRE
|
||||
tristate "FireWire driver stack"
|
||||
select CRC_ITU_T
|
||||
|
@ -64,8 +61,6 @@ config FIREWIRE_NET
|
|||
To compile this driver as a module, say M here: The module will be
|
||||
called firewire-net.
|
||||
|
||||
source "drivers/ieee1394/Kconfig"
|
||||
|
||||
config FIREWIRE_NOSY
|
||||
tristate "Nosy - a FireWire traffic sniffer for PCILynx cards"
|
||||
depends on PCI
|
||||
|
|
|
@ -13,3 +13,4 @@ obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o
|
|||
obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
|
||||
obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o
|
||||
obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o
|
||||
obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
|
||||
|
|
|
@ -32,23 +32,41 @@
|
|||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h> /* for ohci1394.h */
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h> /* for PCI defines */
|
||||
#include <linux/init_ohci1394_dma.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/pci-direct.h> /* for direct PCI config space access */
|
||||
#include <asm/fixmap.h>
|
||||
|
||||
#include "ieee1394_types.h"
|
||||
#include "ohci1394.h"
|
||||
#include <linux/init_ohci1394_dma.h>
|
||||
#include "ohci.h"
|
||||
|
||||
int __initdata init_ohci1394_dma_early;
|
||||
|
||||
struct ohci {
|
||||
void __iomem *registers;
|
||||
};
|
||||
|
||||
static inline void reg_write(const struct ohci *ohci, int offset, u32 data)
|
||||
{
|
||||
writel(data, ohci->registers + offset);
|
||||
}
|
||||
|
||||
static inline u32 reg_read(const struct ohci *ohci, int offset)
|
||||
{
|
||||
return readl(ohci->registers + offset);
|
||||
}
|
||||
|
||||
#define OHCI_LOOP_COUNT 100 /* Number of loops for reg read waits */
|
||||
|
||||
/* Reads a PHY register of an OHCI-1394 controller */
|
||||
static inline u8 __init get_phy_reg(struct ti_ohci *ohci, u8 addr)
|
||||
static inline u8 __init get_phy_reg(struct ohci *ohci, u8 addr)
|
||||
{
|
||||
int i;
|
||||
quadlet_t r;
|
||||
u32 r;
|
||||
|
||||
reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | 0x00008000);
|
||||
|
||||
|
@ -63,22 +81,22 @@ static inline u8 __init get_phy_reg(struct ti_ohci *ohci, u8 addr)
|
|||
}
|
||||
|
||||
/* Writes to a PHY register of an OHCI-1394 controller */
|
||||
static inline void __init set_phy_reg(struct ti_ohci *ohci, u8 addr, u8 data)
|
||||
static inline void __init set_phy_reg(struct ohci *ohci, u8 addr, u8 data)
|
||||
{
|
||||
int i;
|
||||
|
||||
reg_write(ohci, OHCI1394_PhyControl, (addr << 8) | data | 0x00004000);
|
||||
|
||||
for (i = 0; i < OHCI_LOOP_COUNT; i++) {
|
||||
u32 r = reg_read(ohci, OHCI1394_PhyControl);
|
||||
if (!(r & 0x00004000))
|
||||
if (!(reg_read(ohci, OHCI1394_PhyControl) & 0x00004000))
|
||||
break;
|
||||
mdelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Resets an OHCI-1394 controller (for sane state before initialization) */
|
||||
static inline void __init init_ohci1394_soft_reset(struct ti_ohci *ohci) {
|
||||
static inline void __init init_ohci1394_soft_reset(struct ohci *ohci)
|
||||
{
|
||||
int i;
|
||||
|
||||
reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
|
||||
|
@ -91,10 +109,14 @@ static inline void __init init_ohci1394_soft_reset(struct ti_ohci *ohci) {
|
|||
}
|
||||
}
|
||||
|
||||
#define OHCI1394_MAX_AT_REQ_RETRIES 0xf
|
||||
#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
|
||||
#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
|
||||
|
||||
/* Basic OHCI-1394 register and port inititalization */
|
||||
static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
|
||||
static inline void __init init_ohci1394_initialize(struct ohci *ohci)
|
||||
{
|
||||
quadlet_t bus_options;
|
||||
u32 bus_options;
|
||||
int num_ports, i;
|
||||
|
||||
/* Put some defaults to these undefined bus options */
|
||||
|
@ -116,7 +138,7 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
|
|||
|
||||
/* enable phys */
|
||||
reg_write(ohci, OHCI1394_LinkControlSet,
|
||||
OHCI1394_LinkControl_RcvPhyPkt);
|
||||
OHCI1394_LinkControl_rcvPhyPkt);
|
||||
|
||||
/* Don't accept phy packets into AR request context */
|
||||
reg_write(ohci, OHCI1394_LinkControlClear, 0x00000400);
|
||||
|
@ -128,7 +150,7 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
|
|||
reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 0xffffffff);
|
||||
|
||||
/* Accept asyncronous transfer requests from all nodes for now */
|
||||
reg_write(ohci,OHCI1394_AsReqFilterHiSet, 0x80000000);
|
||||
reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
|
||||
|
||||
/* Specify asyncronous transfer retries */
|
||||
reg_write(ohci, OHCI1394_ATRetries,
|
||||
|
@ -137,7 +159,8 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
|
|||
(OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
|
||||
|
||||
/* We don't want hardware swapping */
|
||||
reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
|
||||
reg_write(ohci, OHCI1394_HCControlClear,
|
||||
OHCI1394_HCControl_noByteSwapData);
|
||||
|
||||
/* Enable link */
|
||||
reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
|
||||
|
@ -164,11 +187,11 @@ static inline void __init init_ohci1394_initialize(struct ti_ohci *ohci)
|
|||
* has to be enabled after each bus reset when needed. We resort
|
||||
* to polling here because on early boot, we have no interrupts.
|
||||
*/
|
||||
static inline void __init init_ohci1394_wait_for_busresets(struct ti_ohci *ohci)
|
||||
static inline void __init init_ohci1394_wait_for_busresets(struct ohci *ohci)
|
||||
{
|
||||
int i, events;
|
||||
|
||||
for (i=0; i < 9; i++) {
|
||||
for (i = 0; i < 9; i++) {
|
||||
mdelay(200);
|
||||
events = reg_read(ohci, OHCI1394_IntEventSet);
|
||||
if (events & OHCI1394_busReset)
|
||||
|
@ -182,18 +205,18 @@ static inline void __init init_ohci1394_wait_for_busresets(struct ti_ohci *ohci)
|
|||
* This enables remote DMA access over IEEE1394 from every host for the low
|
||||
* 4GB of address space. DMA accesses above 4GB are not available currently.
|
||||
*/
|
||||
static inline void __init init_ohci1394_enable_physical_dma(struct ti_ohci *hci)
|
||||
static inline void __init init_ohci1394_enable_physical_dma(struct ohci *ohci)
|
||||
{
|
||||
reg_write(hci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
|
||||
reg_write(hci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
|
||||
reg_write(hci, OHCI1394_PhyUpperBound, 0xffff0000);
|
||||
reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 0xffffffff);
|
||||
reg_write(ohci, OHCI1394_PhyReqFilterLoSet, 0xffffffff);
|
||||
reg_write(ohci, OHCI1394_PhyUpperBound, 0xffff0000);
|
||||
}
|
||||
|
||||
/**
|
||||
* init_ohci1394_reset_and_init_dma - init controller and enable DMA
|
||||
* This initializes the given controller and enables physical DMA engine in it.
|
||||
*/
|
||||
static inline void __init init_ohci1394_reset_and_init_dma(struct ti_ohci *ohci)
|
||||
static inline void __init init_ohci1394_reset_and_init_dma(struct ohci *ohci)
|
||||
{
|
||||
/* Start off with a soft reset, clears everything to a sane state. */
|
||||
init_ohci1394_soft_reset(ohci);
|
||||
|
@ -225,7 +248,7 @@ static inline void __init init_ohci1394_reset_and_init_dma(struct ti_ohci *ohci)
|
|||
static inline void __init init_ohci1394_controller(int num, int slot, int func)
|
||||
{
|
||||
unsigned long ohci_base;
|
||||
struct ti_ohci ohci;
|
||||
struct ohci ohci;
|
||||
|
||||
printk(KERN_INFO "init_ohci1394_dma: initializing OHCI-1394"
|
||||
" at %02x:%02x.%x\n", num, slot, func);
|
||||
|
@ -235,7 +258,7 @@ static inline void __init init_ohci1394_controller(int num, int slot, int func)
|
|||
|
||||
set_fixmap_nocache(FIX_OHCI1394_BASE, ohci_base);
|
||||
|
||||
ohci.registers = (void *)fix_to_virt(FIX_OHCI1394_BASE);
|
||||
ohci.registers = (void __iomem *)fix_to_virt(FIX_OHCI1394_BASE);
|
||||
|
||||
init_ohci1394_reset_and_init_dma(&ohci);
|
||||
}
|
||||
|
@ -247,6 +270,7 @@ static inline void __init init_ohci1394_controller(int num, int slot, int func)
|
|||
void __init init_ohci1394_dma_on_all_controllers(void)
|
||||
{
|
||||
int num, slot, func;
|
||||
u32 class;
|
||||
|
||||
if (!early_pci_allowed())
|
||||
return;
|
||||
|
@ -255,9 +279,9 @@ void __init init_ohci1394_dma_on_all_controllers(void)
|
|||
for (num = 0; num < 32; num++) {
|
||||
for (slot = 0; slot < 32; slot++) {
|
||||
for (func = 0; func < 8; func++) {
|
||||
u32 class = read_pci_config(num,slot,func,
|
||||
class = read_pci_config(num, slot, func,
|
||||
PCI_CLASS_REVISION);
|
||||
if ((class == 0xffffffff))
|
||||
if (class == 0xffffffff)
|
||||
continue; /* No device at this func */
|
||||
|
||||
if (class>>8 != PCI_CLASS_SERIAL_FIREWIRE_OHCI)
|
|
@ -1,182 +0,0 @@
|
|||
config IEEE1394
|
||||
tristate "Legacy alternative FireWire driver stack"
|
||||
depends on PCI || BROKEN
|
||||
help
|
||||
IEEE 1394 describes a high performance serial bus, which is also
|
||||
known as FireWire(tm) or i.Link(tm) and is used for connecting all
|
||||
sorts of devices (most notably digital video cameras) to your
|
||||
computer.
|
||||
|
||||
If you have FireWire hardware and want to use it, say Y here. This
|
||||
is the core support only, you will also need to select a driver for
|
||||
your IEEE 1394 adapter.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called ieee1394.
|
||||
|
||||
NOTE:
|
||||
ieee1394 is superseded by the newer firewire-core driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
config IEEE1394_OHCI1394
|
||||
tristate "OHCI-1394 controllers"
|
||||
depends on PCI && IEEE1394
|
||||
help
|
||||
Enable this driver if you have an IEEE 1394 controller based on the
|
||||
OHCI-1394 specification. The current driver is only tested with OHCI
|
||||
chipsets made by Texas Instruments and NEC. Most third-party vendors
|
||||
use one of these chipsets. It should work with any OHCI-1394
|
||||
compliant card, however.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called ohci1394.
|
||||
|
||||
NOTE:
|
||||
ohci1394 is superseded by the newer firewire-ohci driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
If you want to install firewire-ohci and ohci1394 together, you
|
||||
should configure them only as modules and blacklist the driver(s)
|
||||
which you don't want to have auto-loaded. Add either
|
||||
|
||||
blacklist ohci1394
|
||||
blacklist video1394
|
||||
blacklist dv1394
|
||||
or
|
||||
blacklist firewire-ohci
|
||||
|
||||
to /etc/modprobe.conf or /etc/modprobe.d/* and update modprobe.conf
|
||||
depending on your distribution.
|
||||
|
||||
comment "PCILynx controller requires I2C"
|
||||
depends on IEEE1394 && I2C=n
|
||||
|
||||
config IEEE1394_PCILYNX
|
||||
tristate "PCILynx controller"
|
||||
depends on PCI && IEEE1394 && I2C
|
||||
select I2C_ALGOBIT
|
||||
help
|
||||
Say Y here if you have an IEEE-1394 controller with the Texas
|
||||
Instruments PCILynx chip. Note: this driver is written for revision
|
||||
2 of this chip and may not work with revision 0.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called pcilynx.
|
||||
|
||||
Only some old and now very rare PCI and CardBus cards and
|
||||
PowerMacs G3 B&W contain the PCILynx controller. Therefore
|
||||
almost everybody can say N here.
|
||||
|
||||
comment "SBP-2 support (for storage devices) requires SCSI"
|
||||
depends on IEEE1394 && SCSI=n
|
||||
|
||||
config IEEE1394_SBP2
|
||||
tristate "Storage devices (SBP-2 protocol)"
|
||||
depends on IEEE1394 && SCSI
|
||||
help
|
||||
This option enables you to use SBP-2 devices connected to an IEEE
|
||||
1394 bus. SBP-2 devices include storage devices like harddisks and
|
||||
DVD drives, also some other FireWire devices like scanners.
|
||||
|
||||
You should also enable support for disks, CD-ROMs, etc. in the SCSI
|
||||
configuration section.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called sbp2.
|
||||
|
||||
NOTE:
|
||||
sbp2 is superseded by the newer firewire-sbp2 driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
config IEEE1394_SBP2_PHYS_DMA
|
||||
bool "Enable replacement for physical DMA in SBP2"
|
||||
depends on IEEE1394_SBP2 && VIRT_TO_BUS && EXPERIMENTAL
|
||||
help
|
||||
This builds sbp2 for use with non-OHCI host adapters which do not
|
||||
support physical DMA or for when ohci1394 is run with phys_dma=0.
|
||||
Physical DMA is data movement without assistance of the drivers'
|
||||
interrupt handlers. This option includes the interrupt handlers
|
||||
that are required in absence of this hardware feature.
|
||||
|
||||
This option is buggy and currently broken on some architectures.
|
||||
If unsure, say N.
|
||||
|
||||
config IEEE1394_ETH1394_ROM_ENTRY
|
||||
depends on IEEE1394
|
||||
bool
|
||||
default n
|
||||
|
||||
config IEEE1394_ETH1394
|
||||
tristate "IP networking over 1394 (experimental)"
|
||||
depends on IEEE1394 && EXPERIMENTAL && INET
|
||||
select IEEE1394_ETH1394_ROM_ENTRY
|
||||
help
|
||||
This driver implements a functional majority of RFC 2734: IPv4 over
|
||||
1394. It will provide IP connectivity with implementations of RFC
|
||||
2734 found on other operating systems. It will not communicate with
|
||||
older versions of this driver found in stock kernels prior to 2.6.3.
|
||||
This driver is still considered experimental. It does not yet support
|
||||
MCAP, therefore multicast support is significantly limited.
|
||||
|
||||
The module is called eth1394 although it does not emulate Ethernet.
|
||||
|
||||
NOTE:
|
||||
eth1394 is superseded by the newer firewire-net driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
config IEEE1394_RAWIO
|
||||
tristate "raw1394 userspace interface"
|
||||
depends on IEEE1394
|
||||
help
|
||||
This option adds support for the raw1394 device file which enables
|
||||
direct communication of user programs with IEEE 1394 devices
|
||||
(isochronous and asynchronous). Almost all application programs
|
||||
which access FireWire require this option.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called raw1394.
|
||||
|
||||
NOTE:
|
||||
raw1394 is superseded by the newer firewire-core driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
config IEEE1394_VIDEO1394
|
||||
tristate "video1394 userspace interface"
|
||||
depends on IEEE1394 && IEEE1394_OHCI1394
|
||||
help
|
||||
This option adds support for the video1394 device files which enable
|
||||
isochronous communication of user programs with IEEE 1394 devices,
|
||||
especially video capture or export. This interface is used by all
|
||||
libdc1394 based programs and by several other programs, in addition to
|
||||
the raw1394 interface. It is generally not required for DV capture.
|
||||
|
||||
To compile this driver as a module, say M here: the module will be
|
||||
called video1394.
|
||||
|
||||
NOTE:
|
||||
video1394 is superseded by the newer firewire-core driver. See
|
||||
http://ieee1394.wiki.kernel.org/index.php/Juju_Migration for
|
||||
further information on how to switch to the new FireWire drivers.
|
||||
|
||||
config IEEE1394_DV1394
|
||||
tristate "dv1394 userspace interface (deprecated)"
|
||||
depends on IEEE1394 && IEEE1394_OHCI1394
|
||||
help
|
||||
The dv1394 driver is unsupported and may be removed from Linux in a
|
||||
future release. Its functionality is now provided by either
|
||||
raw1394 or firewire-core together with libraries such as libiec61883.
|
||||
|
||||
config IEEE1394_VERBOSEDEBUG
|
||||
bool "Excessive debugging output"
|
||||
depends on IEEE1394
|
||||
help
|
||||
If you say Y here, you will get very verbose debugging logs from the
|
||||
ieee1394 drivers, including sent and received packet headers. This
|
||||
will quickly result in large amounts of data sent to the system log.
|
||||
|
||||
Say Y if you really need the debugging output. Everyone else says N.
|
|
@ -1,18 +0,0 @@
|
|||
#
|
||||
# Makefile for the Linux IEEE 1394 implementation
|
||||
#
|
||||
|
||||
ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
|
||||
highlevel.o csr.o nodemgr.o dma.o iso.o \
|
||||
csr1212.o config_roms.o
|
||||
|
||||
obj-$(CONFIG_IEEE1394) += ieee1394.o
|
||||
obj-$(CONFIG_IEEE1394_PCILYNX) += pcilynx.o
|
||||
obj-$(CONFIG_IEEE1394_OHCI1394) += ohci1394.o
|
||||
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_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
|
|
@ -1,194 +0,0 @@
|
|||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* ConfigROM entries
|
||||
*
|
||||
* Copyright (C) 2004 Ben Collins
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "csr1212.h"
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_types.h"
|
||||
#include "hosts.h"
|
||||
#include "ieee1394_core.h"
|
||||
#include "highlevel.h"
|
||||
#include "csr.h"
|
||||
#include "config_roms.h"
|
||||
|
||||
struct hpsb_config_rom_entry {
|
||||
const char *name;
|
||||
|
||||
/* Base initialization, called at module load */
|
||||
int (*init)(void);
|
||||
|
||||
/* Cleanup called at module exit */
|
||||
void (*cleanup)(void);
|
||||
|
||||
/* The flag added to host->config_roms */
|
||||
unsigned int flag;
|
||||
};
|
||||
|
||||
/* The default host entry. This must succeed. */
|
||||
int hpsb_default_host_entry(struct hpsb_host *host)
|
||||
{
|
||||
struct csr1212_keyval *root;
|
||||
struct csr1212_keyval *vend_id = NULL;
|
||||
struct csr1212_keyval *text = NULL;
|
||||
char csr_name[128];
|
||||
int ret;
|
||||
|
||||
sprintf(csr_name, "Linux - %s", host->driver->name);
|
||||
root = host->csr.rom->root_kv;
|
||||
|
||||
vend_id = csr1212_new_immediate(CSR1212_KV_ID_VENDOR, host->csr.guid_hi >> 8);
|
||||
text = csr1212_new_string_descriptor_leaf(csr_name);
|
||||
|
||||
if (!vend_id || !text) {
|
||||
if (vend_id)
|
||||
csr1212_release_keyval(vend_id);
|
||||
if (text)
|
||||
csr1212_release_keyval(text);
|
||||
csr1212_destroy_csr(host->csr.rom);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
csr1212_associate_keyval(vend_id, text);
|
||||
csr1212_release_keyval(text);
|
||||
ret = csr1212_attach_keyval_to_directory(root, vend_id);
|
||||
csr1212_release_keyval(vend_id);
|
||||
if (ret != CSR1212_SUCCESS) {
|
||||
csr1212_destroy_csr(host->csr.rom);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
host->update_config_rom = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
|
||||
#include "eth1394.h"
|
||||
|
||||
static struct csr1212_keyval *ip1394_ud;
|
||||
|
||||
static int config_rom_ip1394_init(void)
|
||||
{
|
||||
struct csr1212_keyval *spec_id = NULL;
|
||||
struct csr1212_keyval *spec_desc = NULL;
|
||||
struct csr1212_keyval *ver = NULL;
|
||||
struct csr1212_keyval *ver_desc = NULL;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
ip1394_ud = csr1212_new_directory(CSR1212_KV_ID_UNIT);
|
||||
|
||||
spec_id = csr1212_new_immediate(CSR1212_KV_ID_SPECIFIER_ID,
|
||||
ETHER1394_GASP_SPECIFIER_ID);
|
||||
spec_desc = csr1212_new_string_descriptor_leaf("IANA");
|
||||
ver = csr1212_new_immediate(CSR1212_KV_ID_VERSION,
|
||||
ETHER1394_GASP_VERSION);
|
||||
ver_desc = csr1212_new_string_descriptor_leaf("IPv4");
|
||||
|
||||
if (!ip1394_ud || !spec_id || !spec_desc || !ver || !ver_desc)
|
||||
goto ip1394_fail;
|
||||
|
||||
csr1212_associate_keyval(spec_id, spec_desc);
|
||||
csr1212_associate_keyval(ver, ver_desc);
|
||||
if (csr1212_attach_keyval_to_directory(ip1394_ud, spec_id)
|
||||
== CSR1212_SUCCESS &&
|
||||
csr1212_attach_keyval_to_directory(ip1394_ud, ver)
|
||||
== CSR1212_SUCCESS)
|
||||
ret = 0;
|
||||
|
||||
ip1394_fail:
|
||||
if (ret && ip1394_ud) {
|
||||
csr1212_release_keyval(ip1394_ud);
|
||||
ip1394_ud = NULL;
|
||||
}
|
||||
|
||||
if (spec_id)
|
||||
csr1212_release_keyval(spec_id);
|
||||
if (spec_desc)
|
||||
csr1212_release_keyval(spec_desc);
|
||||
if (ver)
|
||||
csr1212_release_keyval(ver);
|
||||
if (ver_desc)
|
||||
csr1212_release_keyval(ver_desc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void config_rom_ip1394_cleanup(void)
|
||||
{
|
||||
if (ip1394_ud) {
|
||||
csr1212_release_keyval(ip1394_ud);
|
||||
ip1394_ud = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int hpsb_config_rom_ip1394_add(struct hpsb_host *host)
|
||||
{
|
||||
if (!ip1394_ud)
|
||||
return -ENODEV;
|
||||
|
||||
if (csr1212_attach_keyval_to_directory(host->csr.rom->root_kv,
|
||||
ip1394_ud) != CSR1212_SUCCESS)
|
||||
return -ENOMEM;
|
||||
|
||||
host->config_roms |= HPSB_CONFIG_ROM_ENTRY_IP1394;
|
||||
host->update_config_rom = 1;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_add);
|
||||
|
||||
void hpsb_config_rom_ip1394_remove(struct hpsb_host *host)
|
||||
{
|
||||
csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, ip1394_ud);
|
||||
host->config_roms &= ~HPSB_CONFIG_ROM_ENTRY_IP1394;
|
||||
host->update_config_rom = 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hpsb_config_rom_ip1394_remove);
|
||||
|
||||
static struct hpsb_config_rom_entry ip1394_entry = {
|
||||
.name = "ip1394",
|
||||
.init = config_rom_ip1394_init,
|
||||
.cleanup = config_rom_ip1394_cleanup,
|
||||
.flag = HPSB_CONFIG_ROM_ENTRY_IP1394,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_IEEE1394_ETH1394_ROM_ENTRY */
|
||||
|
||||
static struct hpsb_config_rom_entry *const config_rom_entries[] = {
|
||||
#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
|
||||
&ip1394_entry,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Initialize all config roms */
|
||||
int hpsb_init_config_roms(void)
|
||||
{
|
||||
int i, error = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
|
||||
if (config_rom_entries[i]->init()) {
|
||||
HPSB_ERR("Failed to initialize config rom entry `%s'",
|
||||
config_rom_entries[i]->name);
|
||||
error = -1;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Cleanup all config roms */
|
||||
void hpsb_cleanup_config_roms(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(config_rom_entries); i++)
|
||||
config_rom_entries[i]->cleanup();
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef _IEEE1394_CONFIG_ROMS_H
|
||||
#define _IEEE1394_CONFIG_ROMS_H
|
||||
|
||||
struct hpsb_host;
|
||||
|
||||
int hpsb_default_host_entry(struct hpsb_host *host);
|
||||
int hpsb_init_config_roms(void);
|
||||
void hpsb_cleanup_config_roms(void);
|
||||
|
||||
/* List of flags to check if a host contains a certain extra config rom
|
||||
* entry. Available in the host->config_roms member. */
|
||||
#define HPSB_CONFIG_ROM_ENTRY_IP1394 0x00000001
|
||||
|
||||
#ifdef CONFIG_IEEE1394_ETH1394_ROM_ENTRY
|
||||
int hpsb_config_rom_ip1394_add(struct hpsb_host *host);
|
||||
void hpsb_config_rom_ip1394_remove(struct hpsb_host *host);
|
||||
#endif
|
||||
|
||||
#endif /* _IEEE1394_CONFIG_ROMS_H */
|
|
@ -1,843 +0,0 @@
|
|||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* CSR implementation, iso/bus manager implementation.
|
||||
*
|
||||
* Copyright (C) 1999 Andreas E. Bombe
|
||||
* 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*
|
||||
*
|
||||
* Contributions:
|
||||
*
|
||||
* Manfred Weihs <weihs@ict.tuwien.ac.at>
|
||||
* configuration ROM manipulation
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "csr1212.h"
|
||||
#include "ieee1394_types.h"
|
||||
#include "hosts.h"
|
||||
#include "ieee1394.h"
|
||||
#include "highlevel.h"
|
||||
#include "ieee1394_core.h"
|
||||
|
||||
/* Module Parameters */
|
||||
/* this module parameter can be used to disable mapping of the FCP registers */
|
||||
|
||||
static int fcp = 1;
|
||||
module_param(fcp, int, 0444);
|
||||
MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
|
||||
|
||||
static struct csr1212_keyval *node_cap = NULL;
|
||||
|
||||
static void add_host(struct hpsb_host *host);
|
||||
static void remove_host(struct hpsb_host *host);
|
||||
static void host_reset(struct hpsb_host *host);
|
||||
static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
|
||||
u64 addr, size_t length, u16 fl);
|
||||
static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
|
||||
quadlet_t *data, u64 addr, size_t length, u16 flags);
|
||||
static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
|
||||
u64 addr, size_t length, u16 flags);
|
||||
static int write_regs(struct hpsb_host *host, int nodeid, int destid,
|
||||
quadlet_t *data, u64 addr, size_t length, u16 flags);
|
||||
static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl);
|
||||
static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
|
||||
u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl);
|
||||
static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
|
||||
u64 addr, size_t length, u16 fl);
|
||||
static u64 allocate_addr_range(u64 size, u32 alignment, void *__host);
|
||||
static void release_addr_range(u64 addr, void *__host);
|
||||
|
||||
static struct hpsb_highlevel csr_highlevel = {
|
||||
.name = "standard registers",
|
||||
.add_host = add_host,
|
||||
.remove_host = remove_host,
|
||||
.host_reset = host_reset,
|
||||
};
|
||||
|
||||
static const struct hpsb_address_ops map_ops = {
|
||||
.read = read_maps,
|
||||
};
|
||||
|
||||
static const struct hpsb_address_ops fcp_ops = {
|
||||
.write = write_fcp,
|
||||
};
|
||||
|
||||
static const struct hpsb_address_ops reg_ops = {
|
||||
.read = read_regs,
|
||||
.write = write_regs,
|
||||
.lock = lock_regs,
|
||||
.lock64 = lock64_regs,
|
||||
};
|
||||
|
||||
static const struct hpsb_address_ops config_rom_ops = {
|
||||
.read = read_config_rom,
|
||||
};
|
||||
|
||||
struct csr1212_bus_ops csr_bus_ops = {
|
||||
.allocate_addr_range = allocate_addr_range,
|
||||
.release_addr = release_addr_range,
|
||||
};
|
||||
|
||||
|
||||
static u16 csr_crc16(unsigned *data, int length)
|
||||
{
|
||||
int check=0, i;
|
||||
int shift, sum, next=0;
|
||||
|
||||
for (i = length; i; i--) {
|
||||
for (next = check, shift = 28; shift >= 0; shift -= 4 ) {
|
||||
sum = ((next >> 12) ^ (be32_to_cpu(*data) >> shift)) & 0xf;
|
||||
next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
|
||||
}
|
||||
check = next & 0xffff;
|
||||
data++;
|
||||
}
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
static void host_reset(struct hpsb_host *host)
|
||||
{
|
||||
host->csr.state &= 0x300;
|
||||
|
||||
host->csr.bus_manager_id = 0x3f;
|
||||
host->csr.bandwidth_available = 4915;
|
||||
host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */
|
||||
host->csr.channels_available_lo = ~0;
|
||||
host->csr.broadcast_channel = 0x80000000 | 31;
|
||||
|
||||
if (host->is_irm) {
|
||||
if (host->driver->hw_csr_reg) {
|
||||
host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
|
||||
}
|
||||
}
|
||||
|
||||
host->csr.node_ids = host->node_id << 16;
|
||||
|
||||
if (!host->is_root) {
|
||||
/* clear cmstr bit */
|
||||
host->csr.state &= ~0x100;
|
||||
}
|
||||
|
||||
be32_add_cpu(&host->csr.topology_map[1], 1);
|
||||
host->csr.topology_map[2] = cpu_to_be32(host->node_count << 16
|
||||
| host->selfid_count);
|
||||
host->csr.topology_map[0] =
|
||||
cpu_to_be32((host->selfid_count + 2) << 16
|
||||
| csr_crc16(host->csr.topology_map + 1,
|
||||
host->selfid_count + 2));
|
||||
|
||||
be32_add_cpu(&host->csr.speed_map[1], 1);
|
||||
host->csr.speed_map[0] = cpu_to_be32(0x3f1 << 16
|
||||
| csr_crc16(host->csr.speed_map+1,
|
||||
0x3f1));
|
||||
}
|
||||
|
||||
/*
|
||||
* HI == seconds (bits 0:2)
|
||||
* LO == fractions of a second in units of 125usec (bits 19:31)
|
||||
*
|
||||
* Convert SPLIT_TIMEOUT to jiffies.
|
||||
* The default and minimum as per 1394a-2000 clause 8.3.2.2.6 is 100ms.
|
||||
*/
|
||||
static inline void calculate_expire(struct csr_control *csr)
|
||||
{
|
||||
unsigned int usecs = (csr->split_timeout_hi & 7) * 1000000 +
|
||||
(csr->split_timeout_lo >> 19) * 125;
|
||||
|
||||
csr->expire = usecs_to_jiffies(usecs > 100000 ? usecs : 100000);
|
||||
HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%u", csr->expire, HZ);
|
||||
}
|
||||
|
||||
|
||||
static void add_host(struct hpsb_host *host)
|
||||
{
|
||||
struct csr1212_keyval *root;
|
||||
quadlet_t bus_info[CSR_BUS_INFO_SIZE];
|
||||
|
||||
hpsb_register_addrspace(&csr_highlevel, host, ®_ops,
|
||||
CSR_REGISTER_BASE,
|
||||
CSR_REGISTER_BASE + CSR_CONFIG_ROM);
|
||||
hpsb_register_addrspace(&csr_highlevel, host, &config_rom_ops,
|
||||
CSR_REGISTER_BASE + CSR_CONFIG_ROM,
|
||||
CSR_REGISTER_BASE + CSR_CONFIG_ROM_END);
|
||||
if (fcp) {
|
||||
hpsb_register_addrspace(&csr_highlevel, host, &fcp_ops,
|
||||
CSR_REGISTER_BASE + CSR_FCP_COMMAND,
|
||||
CSR_REGISTER_BASE + CSR_FCP_END);
|
||||
}
|
||||
hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
|
||||
CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP,
|
||||
CSR_REGISTER_BASE + CSR_TOPOLOGY_MAP_END);
|
||||
hpsb_register_addrspace(&csr_highlevel, host, &map_ops,
|
||||
CSR_REGISTER_BASE + CSR_SPEED_MAP,
|
||||
CSR_REGISTER_BASE + CSR_SPEED_MAP_END);
|
||||
|
||||
spin_lock_init(&host->csr.lock);
|
||||
|
||||
host->csr.state = 0;
|
||||
host->csr.node_ids = 0;
|
||||
host->csr.split_timeout_hi = 0;
|
||||
host->csr.split_timeout_lo = 800 << 19;
|
||||
calculate_expire(&host->csr);
|
||||
host->csr.cycle_time = 0;
|
||||
host->csr.bus_time = 0;
|
||||
host->csr.bus_manager_id = 0x3f;
|
||||
host->csr.bandwidth_available = 4915;
|
||||
host->csr.channels_available_hi = 0xfffffffe; /* pre-alloc ch 31 per 1394a-2000 */
|
||||
host->csr.channels_available_lo = ~0;
|
||||
host->csr.broadcast_channel = 0x80000000 | 31;
|
||||
|
||||
if (host->is_irm) {
|
||||
if (host->driver->hw_csr_reg) {
|
||||
host->driver->hw_csr_reg(host, 2, 0xfffffffe, ~0);
|
||||
}
|
||||
}
|
||||
|
||||
if (host->csr.max_rec >= 9)
|
||||
host->csr.max_rom = 2;
|
||||
else if (host->csr.max_rec >= 5)
|
||||
host->csr.max_rom = 1;
|
||||
else
|
||||
host->csr.max_rom = 0;
|
||||
|
||||
host->csr.generation = 2;
|
||||
|
||||
bus_info[1] = IEEE1394_BUSID_MAGIC;
|
||||
bus_info[2] = cpu_to_be32((hpsb_disable_irm ? 0 : 1 << CSR_IRMC_SHIFT) |
|
||||
(1 << CSR_CMC_SHIFT) |
|
||||
(1 << CSR_ISC_SHIFT) |
|
||||
(0 << CSR_BMC_SHIFT) |
|
||||
(0 << CSR_PMC_SHIFT) |
|
||||
(host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
|
||||
(host->csr.max_rec << CSR_MAX_REC_SHIFT) |
|
||||
(host->csr.max_rom << CSR_MAX_ROM_SHIFT) |
|
||||
(host->csr.generation << CSR_GENERATION_SHIFT) |
|
||||
host->csr.lnk_spd);
|
||||
|
||||
bus_info[3] = cpu_to_be32(host->csr.guid_hi);
|
||||
bus_info[4] = cpu_to_be32(host->csr.guid_lo);
|
||||
|
||||
/* The hardware copy of the bus info block will be set later when a
|
||||
* bus reset is issued. */
|
||||
|
||||
csr1212_init_local_csr(host->csr.rom, bus_info, host->csr.max_rom);
|
||||
|
||||
root = host->csr.rom->root_kv;
|
||||
|
||||
if(csr1212_attach_keyval_to_directory(root, node_cap) != CSR1212_SUCCESS) {
|
||||
HPSB_ERR("Failed to attach Node Capabilities to root directory");
|
||||
}
|
||||
|
||||
host->update_config_rom = 1;
|
||||
}
|
||||
|
||||
static void remove_host(struct hpsb_host *host)
|
||||
{
|
||||
quadlet_t bus_info[CSR_BUS_INFO_SIZE];
|
||||
|
||||
bus_info[1] = IEEE1394_BUSID_MAGIC;
|
||||
bus_info[2] = cpu_to_be32((0 << CSR_IRMC_SHIFT) |
|
||||
(0 << CSR_CMC_SHIFT) |
|
||||
(0 << CSR_ISC_SHIFT) |
|
||||
(0 << CSR_BMC_SHIFT) |
|
||||
(0 << CSR_PMC_SHIFT) |
|
||||
(host->csr.cyc_clk_acc << CSR_CYC_CLK_ACC_SHIFT) |
|
||||
(host->csr.max_rec << CSR_MAX_REC_SHIFT) |
|
||||
(0 << CSR_MAX_ROM_SHIFT) |
|
||||
(0 << CSR_GENERATION_SHIFT) |
|
||||
host->csr.lnk_spd);
|
||||
|
||||
bus_info[3] = cpu_to_be32(host->csr.guid_hi);
|
||||
bus_info[4] = cpu_to_be32(host->csr.guid_lo);
|
||||
|
||||
csr1212_detach_keyval_from_directory(host->csr.rom->root_kv, node_cap);
|
||||
|
||||
csr1212_init_local_csr(host->csr.rom, bus_info, 0);
|
||||
host->update_config_rom = 1;
|
||||
}
|
||||
|
||||
|
||||
int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
|
||||
size_t buffersize, unsigned char rom_version)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
HPSB_NOTICE("hpsb_update_config_rom() is deprecated");
|
||||
|
||||
spin_lock_irqsave(&host->csr.lock, flags);
|
||||
if (rom_version != host->csr.generation)
|
||||
ret = -1;
|
||||
else if (buffersize > host->csr.rom->cache_head->size)
|
||||
ret = -2;
|
||||
else {
|
||||
/* Just overwrite the generated ConfigROM image with new data,
|
||||
* it can be regenerated later. */
|
||||
memcpy(host->csr.rom->cache_head->data, new_rom, buffersize);
|
||||
host->csr.rom->cache_head->len = buffersize;
|
||||
|
||||
if (host->driver->set_hw_config_rom)
|
||||
host->driver->set_hw_config_rom(host, host->csr.rom->bus_info_data);
|
||||
/* Increment the generation number to keep some sort of sync
|
||||
* with the newer ConfigROM manipulation method. */
|
||||
host->csr.generation++;
|
||||
if (host->csr.generation > 0xf || host->csr.generation < 2)
|
||||
host->csr.generation = 2;
|
||||
ret=0;
|
||||
}
|
||||
spin_unlock_irqrestore(&host->csr.lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Read topology / speed maps and configuration ROM */
|
||||
static int read_maps(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
|
||||
u64 addr, size_t length, u16 fl)
|
||||
{
|
||||
unsigned long flags;
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
const char *src;
|
||||
|
||||
spin_lock_irqsave(&host->csr.lock, flags);
|
||||
|
||||
if (csraddr < CSR_SPEED_MAP) {
|
||||
src = ((char *)host->csr.topology_map) + csraddr
|
||||
- CSR_TOPOLOGY_MAP;
|
||||
} else {
|
||||
src = ((char *)host->csr.speed_map) + csraddr - CSR_SPEED_MAP;
|
||||
}
|
||||
|
||||
memcpy(buffer, src, length);
|
||||
spin_unlock_irqrestore(&host->csr.lock, flags);
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
|
||||
#define out if (--length == 0) break
|
||||
|
||||
static int read_regs(struct hpsb_host *host, int nodeid, quadlet_t *buf,
|
||||
u64 addr, size_t length, u16 flags)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
int oldcycle;
|
||||
quadlet_t ret;
|
||||
|
||||
if ((csraddr | length) & 0x3)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
length /= 4;
|
||||
|
||||
switch (csraddr) {
|
||||
case CSR_STATE_CLEAR:
|
||||
*(buf++) = cpu_to_be32(host->csr.state);
|
||||
out;
|
||||
case CSR_STATE_SET:
|
||||
*(buf++) = cpu_to_be32(host->csr.state);
|
||||
out;
|
||||
case CSR_NODE_IDS:
|
||||
*(buf++) = cpu_to_be32(host->csr.node_ids);
|
||||
out;
|
||||
|
||||
case CSR_RESET_START:
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
/* address gap - handled by default below */
|
||||
|
||||
case CSR_SPLIT_TIMEOUT_HI:
|
||||
*(buf++) = cpu_to_be32(host->csr.split_timeout_hi);
|
||||
out;
|
||||
case CSR_SPLIT_TIMEOUT_LO:
|
||||
*(buf++) = cpu_to_be32(host->csr.split_timeout_lo);
|
||||
out;
|
||||
|
||||
/* address gap */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_CYCLE_TIME:
|
||||
oldcycle = host->csr.cycle_time;
|
||||
host->csr.cycle_time =
|
||||
host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
|
||||
|
||||
if (oldcycle > host->csr.cycle_time) {
|
||||
/* cycle time wrapped around */
|
||||
host->csr.bus_time += 1 << 7;
|
||||
}
|
||||
*(buf++) = cpu_to_be32(host->csr.cycle_time);
|
||||
out;
|
||||
case CSR_BUS_TIME:
|
||||
oldcycle = host->csr.cycle_time;
|
||||
host->csr.cycle_time =
|
||||
host->driver->devctl(host, GET_CYCLE_COUNTER, 0);
|
||||
|
||||
if (oldcycle > host->csr.cycle_time) {
|
||||
/* cycle time wrapped around */
|
||||
host->csr.bus_time += (1 << 7);
|
||||
}
|
||||
*(buf++) = cpu_to_be32(host->csr.bus_time
|
||||
| (host->csr.cycle_time >> 25));
|
||||
out;
|
||||
|
||||
/* address gap */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_BUSY_TIMEOUT:
|
||||
/* not yet implemented */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_BUS_MANAGER_ID:
|
||||
if (host->driver->hw_csr_reg)
|
||||
ret = host->driver->hw_csr_reg(host, 0, 0, 0);
|
||||
else
|
||||
ret = host->csr.bus_manager_id;
|
||||
|
||||
*(buf++) = cpu_to_be32(ret);
|
||||
out;
|
||||
case CSR_BANDWIDTH_AVAILABLE:
|
||||
if (host->driver->hw_csr_reg)
|
||||
ret = host->driver->hw_csr_reg(host, 1, 0, 0);
|
||||
else
|
||||
ret = host->csr.bandwidth_available;
|
||||
|
||||
*(buf++) = cpu_to_be32(ret);
|
||||
out;
|
||||
case CSR_CHANNELS_AVAILABLE_HI:
|
||||
if (host->driver->hw_csr_reg)
|
||||
ret = host->driver->hw_csr_reg(host, 2, 0, 0);
|
||||
else
|
||||
ret = host->csr.channels_available_hi;
|
||||
|
||||
*(buf++) = cpu_to_be32(ret);
|
||||
out;
|
||||
case CSR_CHANNELS_AVAILABLE_LO:
|
||||
if (host->driver->hw_csr_reg)
|
||||
ret = host->driver->hw_csr_reg(host, 3, 0, 0);
|
||||
else
|
||||
ret = host->csr.channels_available_lo;
|
||||
|
||||
*(buf++) = cpu_to_be32(ret);
|
||||
out;
|
||||
|
||||
case CSR_BROADCAST_CHANNEL:
|
||||
*(buf++) = cpu_to_be32(host->csr.broadcast_channel);
|
||||
out;
|
||||
|
||||
/* address gap to end - fall through to default */
|
||||
default:
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
static int write_regs(struct hpsb_host *host, int nodeid, int destid,
|
||||
quadlet_t *data, u64 addr, size_t length, u16 flags)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
|
||||
if ((csraddr | length) & 0x3)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
length /= 4;
|
||||
|
||||
switch (csraddr) {
|
||||
case CSR_STATE_CLEAR:
|
||||
/* FIXME FIXME FIXME */
|
||||
printk("doh, someone wants to mess with state clear\n");
|
||||
out;
|
||||
case CSR_STATE_SET:
|
||||
printk("doh, someone wants to mess with state set\n");
|
||||
out;
|
||||
|
||||
case CSR_NODE_IDS:
|
||||
host->csr.node_ids &= NODE_MASK << 16;
|
||||
host->csr.node_ids |= be32_to_cpu(*(data++)) & (BUS_MASK << 16);
|
||||
host->node_id = host->csr.node_ids >> 16;
|
||||
host->driver->devctl(host, SET_BUS_ID, host->node_id >> 6);
|
||||
out;
|
||||
|
||||
case CSR_RESET_START:
|
||||
/* FIXME - perform command reset */
|
||||
out;
|
||||
|
||||
/* address gap */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_SPLIT_TIMEOUT_HI:
|
||||
host->csr.split_timeout_hi =
|
||||
be32_to_cpu(*(data++)) & 0x00000007;
|
||||
calculate_expire(&host->csr);
|
||||
out;
|
||||
case CSR_SPLIT_TIMEOUT_LO:
|
||||
host->csr.split_timeout_lo =
|
||||
be32_to_cpu(*(data++)) & 0xfff80000;
|
||||
calculate_expire(&host->csr);
|
||||
out;
|
||||
|
||||
/* address gap */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_CYCLE_TIME:
|
||||
/* should only be set by cycle start packet, automatically */
|
||||
host->csr.cycle_time = be32_to_cpu(*data);
|
||||
host->driver->devctl(host, SET_CYCLE_COUNTER,
|
||||
be32_to_cpu(*(data++)));
|
||||
out;
|
||||
case CSR_BUS_TIME:
|
||||
host->csr.bus_time = be32_to_cpu(*(data++)) & 0xffffff80;
|
||||
out;
|
||||
|
||||
/* address gap */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_BUSY_TIMEOUT:
|
||||
/* not yet implemented */
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
|
||||
case CSR_BUS_MANAGER_ID:
|
||||
case CSR_BANDWIDTH_AVAILABLE:
|
||||
case CSR_CHANNELS_AVAILABLE_HI:
|
||||
case CSR_CHANNELS_AVAILABLE_LO:
|
||||
/* these are not writable, only lockable */
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
case CSR_BROADCAST_CHANNEL:
|
||||
/* only the valid bit can be written */
|
||||
host->csr.broadcast_channel = (host->csr.broadcast_channel & ~0x40000000)
|
||||
| (be32_to_cpu(*data) & 0x40000000);
|
||||
out;
|
||||
|
||||
/* address gap to end - fall through */
|
||||
default:
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
#undef out
|
||||
|
||||
|
||||
static int lock_regs(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int extcode, u16 fl)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
unsigned long flags;
|
||||
quadlet_t *regptr = NULL;
|
||||
|
||||
if (csraddr & 0x3)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
if (csraddr < CSR_BUS_MANAGER_ID || csraddr > CSR_CHANNELS_AVAILABLE_LO
|
||||
|| extcode != EXTCODE_COMPARE_SWAP)
|
||||
goto unsupported_lockreq;
|
||||
|
||||
data = be32_to_cpu(data);
|
||||
arg = be32_to_cpu(arg);
|
||||
|
||||
/* Is somebody releasing the broadcast_channel on us? */
|
||||
if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x1)) {
|
||||
/* Note: this is may not be the right way to handle
|
||||
* the problem, so we should look into the proper way
|
||||
* eventually. */
|
||||
HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
|
||||
"broadcast channel 31. Ignoring.",
|
||||
NODE_BUS_ARGS(host, nodeid));
|
||||
|
||||
data &= ~0x1; /* keep broadcast channel allocated */
|
||||
}
|
||||
|
||||
if (host->driver->hw_csr_reg) {
|
||||
quadlet_t old;
|
||||
|
||||
old = host->driver->
|
||||
hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
|
||||
data, arg);
|
||||
|
||||
*store = cpu_to_be32(old);
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&host->csr.lock, flags);
|
||||
|
||||
switch (csraddr) {
|
||||
case CSR_BUS_MANAGER_ID:
|
||||
regptr = &host->csr.bus_manager_id;
|
||||
*store = cpu_to_be32(*regptr);
|
||||
if (*regptr == arg)
|
||||
*regptr = data;
|
||||
break;
|
||||
|
||||
case CSR_BANDWIDTH_AVAILABLE:
|
||||
{
|
||||
quadlet_t bandwidth;
|
||||
quadlet_t old;
|
||||
quadlet_t new;
|
||||
|
||||
regptr = &host->csr.bandwidth_available;
|
||||
old = *regptr;
|
||||
|
||||
/* bandwidth available algorithm adapted from IEEE 1394a-2000 spec */
|
||||
if (arg > 0x1fff) {
|
||||
*store = cpu_to_be32(old); /* change nothing */
|
||||
break;
|
||||
}
|
||||
data &= 0x1fff;
|
||||
if (arg >= data) {
|
||||
/* allocate bandwidth */
|
||||
bandwidth = arg - data;
|
||||
if (old >= bandwidth) {
|
||||
new = old - bandwidth;
|
||||
*store = cpu_to_be32(arg);
|
||||
*regptr = new;
|
||||
} else {
|
||||
*store = cpu_to_be32(old);
|
||||
}
|
||||
} else {
|
||||
/* deallocate bandwidth */
|
||||
bandwidth = data - arg;
|
||||
if (old + bandwidth < 0x2000) {
|
||||
new = old + bandwidth;
|
||||
*store = cpu_to_be32(arg);
|
||||
*regptr = new;
|
||||
} else {
|
||||
*store = cpu_to_be32(old);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CSR_CHANNELS_AVAILABLE_HI:
|
||||
{
|
||||
/* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
|
||||
quadlet_t affected_channels = arg ^ data;
|
||||
|
||||
regptr = &host->csr.channels_available_hi;
|
||||
|
||||
if ((arg & affected_channels) == (*regptr & affected_channels)) {
|
||||
*regptr ^= affected_channels;
|
||||
*store = cpu_to_be32(arg);
|
||||
} else {
|
||||
*store = cpu_to_be32(*regptr);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CSR_CHANNELS_AVAILABLE_LO:
|
||||
{
|
||||
/* Lock algorithm for CHANNELS_AVAILABLE as recommended by 1394a-2000 */
|
||||
quadlet_t affected_channels = arg ^ data;
|
||||
|
||||
regptr = &host->csr.channels_available_lo;
|
||||
|
||||
if ((arg & affected_channels) == (*regptr & affected_channels)) {
|
||||
*regptr ^= affected_channels;
|
||||
*store = cpu_to_be32(arg);
|
||||
} else {
|
||||
*store = cpu_to_be32(*regptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&host->csr.lock, flags);
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
|
||||
unsupported_lockreq:
|
||||
switch (csraddr) {
|
||||
case CSR_STATE_CLEAR:
|
||||
case CSR_STATE_SET:
|
||||
case CSR_RESET_START:
|
||||
case CSR_NODE_IDS:
|
||||
case CSR_SPLIT_TIMEOUT_HI:
|
||||
case CSR_SPLIT_TIMEOUT_LO:
|
||||
case CSR_CYCLE_TIME:
|
||||
case CSR_BUS_TIME:
|
||||
case CSR_BROADCAST_CHANNEL:
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
case CSR_BUSY_TIMEOUT:
|
||||
/* not yet implemented - fall through */
|
||||
default:
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static int lock64_regs(struct hpsb_host *host, int nodeid, octlet_t * store,
|
||||
u64 addr, octlet_t data, octlet_t arg, int extcode, u16 fl)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
unsigned long flags;
|
||||
|
||||
data = be64_to_cpu(data);
|
||||
arg = be64_to_cpu(arg);
|
||||
|
||||
if (csraddr & 0x3)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
if (csraddr != CSR_CHANNELS_AVAILABLE
|
||||
|| extcode != EXTCODE_COMPARE_SWAP)
|
||||
goto unsupported_lock64req;
|
||||
|
||||
/* Is somebody releasing the broadcast_channel on us? */
|
||||
if (csraddr == CSR_CHANNELS_AVAILABLE_HI && (data & 0x100000000ULL)) {
|
||||
/* Note: this is may not be the right way to handle
|
||||
* the problem, so we should look into the proper way
|
||||
* eventually. */
|
||||
HPSB_WARN("Node [" NODE_BUS_FMT "] wants to release "
|
||||
"broadcast channel 31. Ignoring.",
|
||||
NODE_BUS_ARGS(host, nodeid));
|
||||
|
||||
data &= ~0x100000000ULL; /* keep broadcast channel allocated */
|
||||
}
|
||||
|
||||
if (host->driver->hw_csr_reg) {
|
||||
quadlet_t data_hi, data_lo;
|
||||
quadlet_t arg_hi, arg_lo;
|
||||
quadlet_t old_hi, old_lo;
|
||||
|
||||
data_hi = data >> 32;
|
||||
data_lo = data & 0xFFFFFFFF;
|
||||
arg_hi = arg >> 32;
|
||||
arg_lo = arg & 0xFFFFFFFF;
|
||||
|
||||
old_hi = host->driver->hw_csr_reg(host, (csraddr - CSR_BUS_MANAGER_ID) >> 2,
|
||||
data_hi, arg_hi);
|
||||
|
||||
old_lo = host->driver->hw_csr_reg(host, ((csraddr + 4) - CSR_BUS_MANAGER_ID) >> 2,
|
||||
data_lo, arg_lo);
|
||||
|
||||
*store = cpu_to_be64(((octlet_t)old_hi << 32) | old_lo);
|
||||
} else {
|
||||
octlet_t old;
|
||||
octlet_t affected_channels = arg ^ data;
|
||||
|
||||
spin_lock_irqsave(&host->csr.lock, flags);
|
||||
|
||||
old = ((octlet_t)host->csr.channels_available_hi << 32) | host->csr.channels_available_lo;
|
||||
|
||||
if ((arg & affected_channels) == (old & affected_channels)) {
|
||||
host->csr.channels_available_hi ^= (affected_channels >> 32);
|
||||
host->csr.channels_available_lo ^= (affected_channels & 0xffffffff);
|
||||
*store = cpu_to_be64(arg);
|
||||
} else {
|
||||
*store = cpu_to_be64(old);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&host->csr.lock, flags);
|
||||
}
|
||||
|
||||
/* Is somebody erroneously releasing the broadcast_channel on us? */
|
||||
if (host->csr.channels_available_hi & 0x1)
|
||||
host->csr.channels_available_hi &= ~0x1;
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
|
||||
unsupported_lock64req:
|
||||
switch (csraddr) {
|
||||
case CSR_STATE_CLEAR:
|
||||
case CSR_STATE_SET:
|
||||
case CSR_RESET_START:
|
||||
case CSR_NODE_IDS:
|
||||
case CSR_SPLIT_TIMEOUT_HI:
|
||||
case CSR_SPLIT_TIMEOUT_LO:
|
||||
case CSR_CYCLE_TIME:
|
||||
case CSR_BUS_TIME:
|
||||
case CSR_BUS_MANAGER_ID:
|
||||
case CSR_BROADCAST_CHANNEL:
|
||||
case CSR_BUSY_TIMEOUT:
|
||||
case CSR_BANDWIDTH_AVAILABLE:
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
default:
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
static int write_fcp(struct hpsb_host *host, int nodeid, int dest,
|
||||
quadlet_t *data, u64 addr, size_t length, u16 flags)
|
||||
{
|
||||
int csraddr = addr - CSR_REGISTER_BASE;
|
||||
|
||||
if (length > 512)
|
||||
return RCODE_TYPE_ERROR;
|
||||
|
||||
switch (csraddr) {
|
||||
case CSR_FCP_COMMAND:
|
||||
highlevel_fcp_request(host, nodeid, 0, (u8 *)data, length);
|
||||
break;
|
||||
case CSR_FCP_RESPONSE:
|
||||
highlevel_fcp_request(host, nodeid, 1, (u8 *)data, length);
|
||||
break;
|
||||
default:
|
||||
return RCODE_TYPE_ERROR;
|
||||
}
|
||||
|
||||
return RCODE_COMPLETE;
|
||||
}
|
||||
|
||||
static int read_config_rom(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
|
||||
u64 addr, size_t length, u16 fl)
|
||||
{
|
||||
u32 offset = addr - CSR1212_REGISTER_SPACE_BASE;
|
||||
|
||||
if (csr1212_read(host->csr.rom, offset, buffer, length) == CSR1212_SUCCESS)
|
||||
return RCODE_COMPLETE;
|
||||
else
|
||||
return RCODE_ADDRESS_ERROR;
|
||||
}
|
||||
|
||||
static u64 allocate_addr_range(u64 size, u32 alignment, void *__host)
|
||||
{
|
||||
struct hpsb_host *host = (struct hpsb_host*)__host;
|
||||
|
||||
return hpsb_allocate_and_register_addrspace(&csr_highlevel,
|
||||
host,
|
||||
&config_rom_ops,
|
||||
size, alignment,
|
||||
CSR1212_UNITS_SPACE_BASE,
|
||||
CSR1212_UNITS_SPACE_END);
|
||||
}
|
||||
|
||||
static void release_addr_range(u64 addr, void *__host)
|
||||
{
|
||||
struct hpsb_host *host = (struct hpsb_host*)__host;
|
||||
hpsb_unregister_addrspace(&csr_highlevel, host, addr);
|
||||
}
|
||||
|
||||
|
||||
int init_csr(void)
|
||||
{
|
||||
node_cap = csr1212_new_immediate(CSR1212_KV_ID_NODE_CAPABILITIES, 0x0083c0);
|
||||
if (!node_cap) {
|
||||
HPSB_ERR("Failed to allocate memory for Node Capabilties ConfigROM entry!");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hpsb_register_highlevel(&csr_highlevel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_csr(void)
|
||||
{
|
||||
if (node_cap)
|
||||
csr1212_release_keyval(node_cap);
|
||||
hpsb_unregister_highlevel(&csr_highlevel);
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
#ifndef _IEEE1394_CSR_H
|
||||
#define _IEEE1394_CSR_H
|
||||
|
||||
#include <linux/spinlock_types.h>
|
||||
|
||||
#include "csr1212.h"
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
#define CSR_REGISTER_BASE 0xfffff0000000ULL
|
||||
|
||||
/* register offsets relative to CSR_REGISTER_BASE */
|
||||
#define CSR_STATE_CLEAR 0x0
|
||||
#define CSR_STATE_SET 0x4
|
||||
#define CSR_NODE_IDS 0x8
|
||||
#define CSR_RESET_START 0xc
|
||||
#define CSR_SPLIT_TIMEOUT_HI 0x18
|
||||
#define CSR_SPLIT_TIMEOUT_LO 0x1c
|
||||
#define CSR_CYCLE_TIME 0x200
|
||||
#define CSR_BUS_TIME 0x204
|
||||
#define CSR_BUSY_TIMEOUT 0x210
|
||||
#define CSR_BUS_MANAGER_ID 0x21c
|
||||
#define CSR_BANDWIDTH_AVAILABLE 0x220
|
||||
#define CSR_CHANNELS_AVAILABLE 0x224
|
||||
#define CSR_CHANNELS_AVAILABLE_HI 0x224
|
||||
#define CSR_CHANNELS_AVAILABLE_LO 0x228
|
||||
#define CSR_BROADCAST_CHANNEL 0x234
|
||||
#define CSR_CONFIG_ROM 0x400
|
||||
#define CSR_CONFIG_ROM_END 0x800
|
||||
#define CSR_FCP_COMMAND 0xB00
|
||||
#define CSR_FCP_RESPONSE 0xD00
|
||||
#define CSR_FCP_END 0xF00
|
||||
#define CSR_TOPOLOGY_MAP 0x1000
|
||||
#define CSR_TOPOLOGY_MAP_END 0x1400
|
||||
#define CSR_SPEED_MAP 0x2000
|
||||
#define CSR_SPEED_MAP_END 0x3000
|
||||
|
||||
/* IEEE 1394 bus specific Configuration ROM Key IDs */
|
||||
#define IEEE1394_KV_ID_POWER_REQUIREMENTS (0x30)
|
||||
|
||||
/* IEEE 1394 Bus Information Block specifics */
|
||||
#define CSR_BUS_INFO_SIZE (5 * sizeof(quadlet_t))
|
||||
|
||||
#define CSR_IRMC_SHIFT 31
|
||||
#define CSR_CMC_SHIFT 30
|
||||
#define CSR_ISC_SHIFT 29
|
||||
#define CSR_BMC_SHIFT 28
|
||||
#define CSR_PMC_SHIFT 27
|
||||
#define CSR_CYC_CLK_ACC_SHIFT 16
|
||||
#define CSR_MAX_REC_SHIFT 12
|
||||
#define CSR_MAX_ROM_SHIFT 8
|
||||
#define CSR_GENERATION_SHIFT 4
|
||||
|
||||
static inline void csr_set_bus_info_generation(struct csr1212_csr *csr, u8 gen)
|
||||
{
|
||||
csr->bus_info_data[2] &= ~cpu_to_be32(0xf << CSR_GENERATION_SHIFT);
|
||||
csr->bus_info_data[2] |= cpu_to_be32((u32)gen << CSR_GENERATION_SHIFT);
|
||||
}
|
||||
|
||||
struct csr_control {
|
||||
spinlock_t lock;
|
||||
|
||||
quadlet_t state;
|
||||
quadlet_t node_ids;
|
||||
quadlet_t split_timeout_hi, split_timeout_lo;
|
||||
unsigned long expire; /* Calculated from split_timeout */
|
||||
quadlet_t cycle_time;
|
||||
quadlet_t bus_time;
|
||||
quadlet_t bus_manager_id;
|
||||
quadlet_t bandwidth_available;
|
||||
quadlet_t channels_available_hi, channels_available_lo;
|
||||
quadlet_t broadcast_channel;
|
||||
|
||||
/* Bus Info */
|
||||
quadlet_t guid_hi, guid_lo;
|
||||
u8 cyc_clk_acc;
|
||||
u8 max_rec;
|
||||
u8 max_rom;
|
||||
u8 generation; /* Only use values between 0x2 and 0xf */
|
||||
u8 lnk_spd;
|
||||
|
||||
unsigned long gen_timestamp[16];
|
||||
|
||||
struct csr1212_csr *rom;
|
||||
|
||||
quadlet_t topology_map[256];
|
||||
quadlet_t speed_map[1024];
|
||||
};
|
||||
|
||||
extern struct csr1212_bus_ops csr_bus_ops;
|
||||
|
||||
int init_csr(void);
|
||||
void cleanup_csr(void);
|
||||
|
||||
/* hpsb_update_config_rom() is deprecated */
|
||||
struct hpsb_host;
|
||||
int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
|
||||
size_t size, unsigned char rom_version);
|
||||
|
||||
#endif /* _IEEE1394_CSR_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,383 +0,0 @@
|
|||
/*
|
||||
* csr1212.h -- IEEE 1212 Control and Status Register support for Linux
|
||||
*
|
||||
* Copyright (C) 2003 Francois Retief <fgretief@sun.ac.za>
|
||||
* Steve Kinneberg <kinnebergsteve@acmsystems.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __CSR1212_H__
|
||||
#define __CSR1212_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#define CSR1212_MALLOC(size) kmalloc((size), GFP_KERNEL)
|
||||
#define CSR1212_FREE(ptr) kfree(ptr)
|
||||
|
||||
#define CSR1212_SUCCESS (0)
|
||||
|
||||
|
||||
/* CSR 1212 key types */
|
||||
#define CSR1212_KV_TYPE_IMMEDIATE 0
|
||||
#define CSR1212_KV_TYPE_CSR_OFFSET 1
|
||||
#define CSR1212_KV_TYPE_LEAF 2
|
||||
#define CSR1212_KV_TYPE_DIRECTORY 3
|
||||
|
||||
|
||||
/* CSR 1212 key ids */
|
||||
#define CSR1212_KV_ID_DESCRIPTOR 0x01
|
||||
#define CSR1212_KV_ID_BUS_DEPENDENT_INFO 0x02
|
||||
#define CSR1212_KV_ID_VENDOR 0x03
|
||||
#define CSR1212_KV_ID_HARDWARE_VERSION 0x04
|
||||
#define CSR1212_KV_ID_MODULE 0x07
|
||||
#define CSR1212_KV_ID_NODE_CAPABILITIES 0x0C
|
||||
#define CSR1212_KV_ID_EUI_64 0x0D
|
||||
#define CSR1212_KV_ID_UNIT 0x11
|
||||
#define CSR1212_KV_ID_SPECIFIER_ID 0x12
|
||||
#define CSR1212_KV_ID_VERSION 0x13
|
||||
#define CSR1212_KV_ID_DEPENDENT_INFO 0x14
|
||||
#define CSR1212_KV_ID_UNIT_LOCATION 0x15
|
||||
#define CSR1212_KV_ID_MODEL 0x17
|
||||
#define CSR1212_KV_ID_INSTANCE 0x18
|
||||
#define CSR1212_KV_ID_KEYWORD 0x19
|
||||
#define CSR1212_KV_ID_FEATURE 0x1A
|
||||
#define CSR1212_KV_ID_EXTENDED_ROM 0x1B
|
||||
#define CSR1212_KV_ID_EXTENDED_KEY_SPECIFIER_ID 0x1C
|
||||
#define CSR1212_KV_ID_EXTENDED_KEY 0x1D
|
||||
#define CSR1212_KV_ID_EXTENDED_DATA 0x1E
|
||||
#define CSR1212_KV_ID_MODIFIABLE_DESCRIPTOR 0x1F
|
||||
#define CSR1212_KV_ID_DIRECTORY_ID 0x20
|
||||
#define CSR1212_KV_ID_REVISION 0x21
|
||||
|
||||
|
||||
/* IEEE 1212 Address space map */
|
||||
#define CSR1212_ALL_SPACE_BASE (0x000000000000ULL)
|
||||
#define CSR1212_ALL_SPACE_SIZE (1ULL << 48)
|
||||
#define CSR1212_ALL_SPACE_END (CSR1212_ALL_SPACE_BASE + CSR1212_ALL_SPACE_SIZE)
|
||||
|
||||
#define CSR1212_MEMORY_SPACE_BASE (0x000000000000ULL)
|
||||
#define CSR1212_MEMORY_SPACE_SIZE ((256ULL * (1ULL << 40)) - (512ULL * (1ULL << 20)))
|
||||
#define CSR1212_MEMORY_SPACE_END (CSR1212_MEMORY_SPACE_BASE + CSR1212_MEMORY_SPACE_SIZE)
|
||||
|
||||
#define CSR1212_PRIVATE_SPACE_BASE (0xffffe0000000ULL)
|
||||
#define CSR1212_PRIVATE_SPACE_SIZE (256ULL * (1ULL << 20))
|
||||
#define CSR1212_PRIVATE_SPACE_END (CSR1212_PRIVATE_SPACE_BASE + CSR1212_PRIVATE_SPACE_SIZE)
|
||||
|
||||
#define CSR1212_REGISTER_SPACE_BASE (0xfffff0000000ULL)
|
||||
#define CSR1212_REGISTER_SPACE_SIZE (256ULL * (1ULL << 20))
|
||||
#define CSR1212_REGISTER_SPACE_END (CSR1212_REGISTER_SPACE_BASE + CSR1212_REGISTER_SPACE_SIZE)
|
||||
|
||||
#define CSR1212_CSR_ARCH_REG_SPACE_BASE (0xfffff0000000ULL)
|
||||
#define CSR1212_CSR_ARCH_REG_SPACE_SIZE (512)
|
||||
#define CSR1212_CSR_ARCH_REG_SPACE_END (CSR1212_CSR_ARCH_REG_SPACE_BASE + CSR1212_CSR_ARCH_REG_SPACE_SIZE)
|
||||
#define CSR1212_CSR_ARCH_REG_SPACE_OFFSET (CSR1212_CSR_ARCH_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
|
||||
|
||||
#define CSR1212_CSR_BUS_DEP_REG_SPACE_BASE (0xfffff0000200ULL)
|
||||
#define CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE (512)
|
||||
#define CSR1212_CSR_BUS_DEP_REG_SPACE_END (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE + CSR1212_CSR_BUS_DEP_REG_SPACE_SIZE)
|
||||
#define CSR1212_CSR_BUS_DEP_REG_SPACE_OFFSET (CSR1212_CSR_BUS_DEP_REG_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
|
||||
|
||||
#define CSR1212_CONFIG_ROM_SPACE_BASE (0xfffff0000400ULL)
|
||||
#define CSR1212_CONFIG_ROM_SPACE_SIZE (1024)
|
||||
#define CSR1212_CONFIG_ROM_SPACE_END (CSR1212_CONFIG_ROM_SPACE_BASE + CSR1212_CONFIG_ROM_SPACE_SIZE)
|
||||
#define CSR1212_CONFIG_ROM_SPACE_OFFSET (CSR1212_CONFIG_ROM_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
|
||||
|
||||
#define CSR1212_UNITS_SPACE_BASE (0xfffff0000800ULL)
|
||||
#define CSR1212_UNITS_SPACE_SIZE ((256ULL * (1ULL << 20)) - 2048)
|
||||
#define CSR1212_UNITS_SPACE_END (CSR1212_UNITS_SPACE_BASE + CSR1212_UNITS_SPACE_SIZE)
|
||||
#define CSR1212_UNITS_SPACE_OFFSET (CSR1212_UNITS_SPACE_BASE - CSR1212_REGISTER_SPACE_BASE)
|
||||
|
||||
#define CSR1212_INVALID_ADDR_SPACE -1
|
||||
|
||||
|
||||
/* Config ROM image structures */
|
||||
struct csr1212_bus_info_block_img {
|
||||
u8 length;
|
||||
u8 crc_length;
|
||||
u16 crc;
|
||||
|
||||
/* Must be last */
|
||||
u32 data[0]; /* older gcc can't handle [] which is standard */
|
||||
};
|
||||
|
||||
struct csr1212_leaf {
|
||||
int len;
|
||||
u32 *data;
|
||||
};
|
||||
|
||||
struct csr1212_dentry {
|
||||
struct csr1212_dentry *next, *prev;
|
||||
struct csr1212_keyval *kv;
|
||||
};
|
||||
|
||||
struct csr1212_directory {
|
||||
int len;
|
||||
struct csr1212_dentry *dentries_head, *dentries_tail;
|
||||
};
|
||||
|
||||
struct csr1212_keyval {
|
||||
struct {
|
||||
u8 type;
|
||||
u8 id;
|
||||
} key;
|
||||
union {
|
||||
u32 immediate;
|
||||
u32 csr_offset;
|
||||
struct csr1212_leaf leaf;
|
||||
struct csr1212_directory directory;
|
||||
} value;
|
||||
struct csr1212_keyval *associate;
|
||||
atomic_t refcnt;
|
||||
|
||||
/* used in generating and/or parsing CSR image */
|
||||
struct csr1212_keyval *next, *prev; /* flat list of CSR elements */
|
||||
u32 offset; /* position in CSR from 0xffff f000 0000 */
|
||||
u8 valid; /* flag indicating keyval has valid data*/
|
||||
};
|
||||
|
||||
|
||||
struct csr1212_cache_region {
|
||||
struct csr1212_cache_region *next, *prev;
|
||||
u32 offset_start; /* inclusive */
|
||||
u32 offset_end; /* exclusive */
|
||||
};
|
||||
|
||||
struct csr1212_csr_rom_cache {
|
||||
struct csr1212_csr_rom_cache *next, *prev;
|
||||
struct csr1212_cache_region *filled_head, *filled_tail;
|
||||
struct csr1212_keyval *layout_head, *layout_tail;
|
||||
size_t size;
|
||||
u32 offset;
|
||||
struct csr1212_keyval *ext_rom;
|
||||
size_t len;
|
||||
|
||||
/* Must be last */
|
||||
u32 data[0]; /* older gcc can't handle [] which is standard */
|
||||
};
|
||||
|
||||
struct csr1212_csr {
|
||||
size_t bus_info_len; /* bus info block length in bytes */
|
||||
size_t crc_len; /* crc length in bytes */
|
||||
__be32 *bus_info_data; /* bus info data incl bus name and EUI */
|
||||
|
||||
void *private; /* private, bus specific data */
|
||||
struct csr1212_bus_ops *ops;
|
||||
|
||||
struct csr1212_keyval *root_kv;
|
||||
|
||||
int max_rom; /* max bytes readable in Config ROM region */
|
||||
|
||||
/* Items below used for image parsing and generation */
|
||||
struct csr1212_csr_rom_cache *cache_head, *cache_tail;
|
||||
};
|
||||
|
||||
struct csr1212_bus_ops {
|
||||
/* This function is used by csr1212 to read additional information
|
||||
* from remote nodes when parsing a Config ROM (i.e., read Config ROM
|
||||
* entries located in the Units Space. Must return 0 on success
|
||||
* anything else indicates an error. */
|
||||
int (*bus_read) (struct csr1212_csr *csr, u64 addr,
|
||||
void *buffer, void *private);
|
||||
|
||||
/* This function is used by csr1212 to allocate a region in units space
|
||||
* in the event that Config ROM entries don't all fit in the predefined
|
||||
* 1K region. The void *private parameter is private member of struct
|
||||
* csr1212_csr. */
|
||||
u64 (*allocate_addr_range) (u64 size, u32 alignment, void *private);
|
||||
|
||||
/* This function is used by csr1212 to release a region in units space
|
||||
* that is no longer needed. */
|
||||
void (*release_addr) (u64 addr, void *private);
|
||||
};
|
||||
|
||||
|
||||
/* Descriptor Leaf manipulation macros */
|
||||
#define CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT 24
|
||||
#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK 0xffffff
|
||||
#define CSR1212_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
|
||||
|
||||
#define CSR1212_DESCRIPTOR_LEAF_TYPE(kv) \
|
||||
(be32_to_cpu((kv)->value.leaf.data[0]) >> \
|
||||
CSR1212_DESCRIPTOR_LEAF_TYPE_SHIFT)
|
||||
#define CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID(kv) \
|
||||
(be32_to_cpu((kv)->value.leaf.data[0]) & \
|
||||
CSR1212_DESCRIPTOR_LEAF_SPECIFIER_ID_MASK)
|
||||
|
||||
|
||||
/* Text Descriptor Leaf manipulation macros */
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT 28
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_MASK 0xf /* after shift */
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT 16
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK 0xfff /* after shift */
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK 0xffff
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_OVERHEAD (1 * sizeof(u32))
|
||||
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH(kv) \
|
||||
(be32_to_cpu((kv)->value.leaf.data[1]) >> \
|
||||
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_WIDTH_SHIFT)
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET(kv) \
|
||||
((be32_to_cpu((kv)->value.leaf.data[1]) >> \
|
||||
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_SHIFT) & \
|
||||
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_CHAR_SET_MASK)
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE(kv) \
|
||||
(be32_to_cpu((kv)->value.leaf.data[1]) & \
|
||||
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_LANGUAGE_MASK)
|
||||
#define CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(kv) \
|
||||
(&((kv)->value.leaf.data[2]))
|
||||
|
||||
|
||||
/* The following 2 function are for creating new Configuration ROM trees. The
|
||||
* first function is used for both creating local trees and parsing remote
|
||||
* trees. The second function adds pertinent information to local Configuration
|
||||
* ROM trees - namely data for the bus information block. */
|
||||
extern struct csr1212_csr *csr1212_create_csr(struct csr1212_bus_ops *ops,
|
||||
size_t bus_info_size,
|
||||
void *private);
|
||||
extern void csr1212_init_local_csr(struct csr1212_csr *csr,
|
||||
const u32 *bus_info_data, int max_rom);
|
||||
|
||||
|
||||
/* Destroy a Configuration ROM tree and release all memory taken by the tree. */
|
||||
extern void csr1212_destroy_csr(struct csr1212_csr *csr);
|
||||
|
||||
|
||||
/* The following set of functions are fore creating new keyvals for placement in
|
||||
* a Configuration ROM tree. Code that creates new keyvals with these functions
|
||||
* must release those keyvals with csr1212_release_keyval() when they are no
|
||||
* longer needed. */
|
||||
extern struct csr1212_keyval *csr1212_new_immediate(u8 key, u32 value);
|
||||
extern struct csr1212_keyval *csr1212_new_directory(u8 key);
|
||||
extern struct csr1212_keyval *csr1212_new_string_descriptor_leaf(const char *s);
|
||||
|
||||
|
||||
/* The following function manages association between keyvals. Typically,
|
||||
* Descriptor Leaves and Directories will be associated with another keyval and
|
||||
* it is desirable for the Descriptor keyval to be place immediately after the
|
||||
* keyval that it is associated with.
|
||||
* Take care with subsequent ROM modifications: There is no function to remove
|
||||
* previously specified associations.
|
||||
*/
|
||||
extern void csr1212_associate_keyval(struct csr1212_keyval *kv,
|
||||
struct csr1212_keyval *associate);
|
||||
|
||||
|
||||
/* The following functions manage the association of a keyval and directories.
|
||||
* A keyval may be attached to more than one directory. */
|
||||
extern int csr1212_attach_keyval_to_directory(struct csr1212_keyval *dir,
|
||||
struct csr1212_keyval *kv);
|
||||
extern void csr1212_detach_keyval_from_directory(struct csr1212_keyval *dir,
|
||||
struct csr1212_keyval *kv);
|
||||
|
||||
|
||||
/* Creates a complete Configuration ROM image in the list of caches available
|
||||
* via csr->cache_head. */
|
||||
extern int csr1212_generate_csr_image(struct csr1212_csr *csr);
|
||||
|
||||
|
||||
/* This is a convience function for reading a block of data out of one of the
|
||||
* caches in the csr->cache_head list. */
|
||||
extern int csr1212_read(struct csr1212_csr *csr, u32 offset, void *buffer,
|
||||
u32 len);
|
||||
|
||||
|
||||
/* The following functions are in place for parsing Configuration ROM images.
|
||||
* csr1212_parse_keyval() is used should there be a need to directly parse a
|
||||
* Configuration ROM directly. */
|
||||
extern int csr1212_parse_keyval(struct csr1212_keyval *kv,
|
||||
struct csr1212_csr_rom_cache *cache);
|
||||
extern int csr1212_parse_csr(struct csr1212_csr *csr);
|
||||
|
||||
|
||||
/* This function allocates a new cache which may be used for either parsing or
|
||||
* generating sub-sets of Configuration ROM images. */
|
||||
static inline struct csr1212_csr_rom_cache *
|
||||
csr1212_rom_cache_malloc(u32 offset, size_t size)
|
||||
{
|
||||
struct csr1212_csr_rom_cache *cache;
|
||||
|
||||
cache = CSR1212_MALLOC(sizeof(*cache) + size);
|
||||
if (!cache)
|
||||
return NULL;
|
||||
|
||||
cache->next = NULL;
|
||||
cache->prev = NULL;
|
||||
cache->filled_head = NULL;
|
||||
cache->filled_tail = NULL;
|
||||
cache->layout_head = NULL;
|
||||
cache->layout_tail = NULL;
|
||||
cache->offset = offset;
|
||||
cache->size = size;
|
||||
cache->ext_rom = NULL;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
/* This function ensures that a keyval contains data when referencing a keyval
|
||||
* created by parsing a Configuration ROM. */
|
||||
extern struct csr1212_keyval *
|
||||
csr1212_get_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv);
|
||||
|
||||
|
||||
/* This function increments the reference count for a keyval should there be a
|
||||
* need for code to retain a keyval that has been parsed. */
|
||||
static inline void csr1212_keep_keyval(struct csr1212_keyval *kv)
|
||||
{
|
||||
atomic_inc(&kv->refcnt);
|
||||
smp_mb__after_atomic_inc();
|
||||
}
|
||||
|
||||
|
||||
/* This function decrements a keyval's reference count and will destroy the
|
||||
* keyval when there are no more users of the keyval. This should be called by
|
||||
* any code that calls csr1212_keep_keyval() or any of the keyval creation
|
||||
* routines csr1212_new_*(). */
|
||||
extern void csr1212_release_keyval(struct csr1212_keyval *kv);
|
||||
|
||||
|
||||
/*
|
||||
* This macro allows for looping over the keyval entries in a directory and it
|
||||
* ensures that keyvals from remote ConfigROMs are parsed properly.
|
||||
*
|
||||
* struct csr1212_csr *_csr points to the CSR associated with dir.
|
||||
* struct csr1212_keyval *_kv points to the current keyval (loop index).
|
||||
* struct csr1212_keyval *_dir points to the directory to be looped.
|
||||
* struct csr1212_dentry *_pos is used internally for indexing.
|
||||
*
|
||||
* kv will be NULL upon exit of the loop.
|
||||
*/
|
||||
#define csr1212_for_each_dir_entry(_csr, _kv, _dir, _pos) \
|
||||
for (csr1212_get_keyval((_csr), (_dir)), \
|
||||
_pos = (_dir)->value.directory.dentries_head, \
|
||||
_kv = (_pos) ? csr1212_get_keyval((_csr), _pos->kv) : NULL;\
|
||||
(_kv) && (_pos); \
|
||||
(_kv->associate == NULL) ? \
|
||||
((_pos = _pos->next), (_kv = (_pos) ? \
|
||||
csr1212_get_keyval((_csr), _pos->kv) : \
|
||||
NULL)) : \
|
||||
(_kv = csr1212_get_keyval((_csr), _kv->associate)))
|
||||
|
||||
#endif /* __CSR1212_H__ */
|
|
@ -1,289 +0,0 @@
|
|||
/*
|
||||
* DMA region bookkeeping routines
|
||||
*
|
||||
* Copyright (C) 2002 Maas Digital LLC
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include "dma.h"
|
||||
|
||||
/* dma_prog_region */
|
||||
|
||||
void dma_prog_region_init(struct dma_prog_region *prog)
|
||||
{
|
||||
prog->kvirt = NULL;
|
||||
prog->dev = NULL;
|
||||
prog->n_pages = 0;
|
||||
prog->bus_addr = 0;
|
||||
}
|
||||
|
||||
int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
|
||||
struct pci_dev *dev)
|
||||
{
|
||||
/* round up to page size */
|
||||
n_bytes = PAGE_ALIGN(n_bytes);
|
||||
|
||||
prog->n_pages = n_bytes >> PAGE_SHIFT;
|
||||
|
||||
prog->kvirt = pci_alloc_consistent(dev, n_bytes, &prog->bus_addr);
|
||||
if (!prog->kvirt) {
|
||||
printk(KERN_ERR
|
||||
"dma_prog_region_alloc: pci_alloc_consistent() failed\n");
|
||||
dma_prog_region_free(prog);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
prog->dev = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dma_prog_region_free(struct dma_prog_region *prog)
|
||||
{
|
||||
if (prog->kvirt) {
|
||||
pci_free_consistent(prog->dev, prog->n_pages << PAGE_SHIFT,
|
||||
prog->kvirt, prog->bus_addr);
|
||||
}
|
||||
|
||||
prog->kvirt = NULL;
|
||||
prog->dev = NULL;
|
||||
prog->n_pages = 0;
|
||||
prog->bus_addr = 0;
|
||||
}
|
||||
|
||||
/* dma_region */
|
||||
|
||||
/**
|
||||
* dma_region_init - clear out all fields but do not allocate anything
|
||||
*/
|
||||
void dma_region_init(struct dma_region *dma)
|
||||
{
|
||||
dma->kvirt = NULL;
|
||||
dma->dev = NULL;
|
||||
dma->n_pages = 0;
|
||||
dma->n_dma_pages = 0;
|
||||
dma->sglist = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_region_alloc - allocate the buffer and map it to the IOMMU
|
||||
*/
|
||||
int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
|
||||
struct pci_dev *dev, int direction)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/* round up to page size */
|
||||
n_bytes = PAGE_ALIGN(n_bytes);
|
||||
|
||||
dma->n_pages = n_bytes >> PAGE_SHIFT;
|
||||
|
||||
dma->kvirt = vmalloc_32(n_bytes);
|
||||
if (!dma->kvirt) {
|
||||
printk(KERN_ERR "dma_region_alloc: vmalloc_32() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Clear the ram out, no junk to the user */
|
||||
memset(dma->kvirt, 0, n_bytes);
|
||||
|
||||
/* allocate scatter/gather list */
|
||||
dma->sglist = vmalloc(dma->n_pages * sizeof(*dma->sglist));
|
||||
if (!dma->sglist) {
|
||||
printk(KERN_ERR "dma_region_alloc: vmalloc(sglist) failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
sg_init_table(dma->sglist, dma->n_pages);
|
||||
|
||||
/* fill scatter/gather list with pages */
|
||||
for (i = 0; i < dma->n_pages; i++) {
|
||||
unsigned long va =
|
||||
(unsigned long)dma->kvirt + (i << PAGE_SHIFT);
|
||||
|
||||
sg_set_page(&dma->sglist[i], vmalloc_to_page((void *)va),
|
||||
PAGE_SIZE, 0);
|
||||
}
|
||||
|
||||
/* map sglist to the IOMMU */
|
||||
dma->n_dma_pages =
|
||||
pci_map_sg(dev, dma->sglist, dma->n_pages, direction);
|
||||
|
||||
if (dma->n_dma_pages == 0) {
|
||||
printk(KERN_ERR "dma_region_alloc: pci_map_sg() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
dma->dev = dev;
|
||||
dma->direction = direction;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dma_region_free(dma);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_region_free - unmap and free the buffer
|
||||
*/
|
||||
void dma_region_free(struct dma_region *dma)
|
||||
{
|
||||
if (dma->n_dma_pages) {
|
||||
pci_unmap_sg(dma->dev, dma->sglist, dma->n_pages,
|
||||
dma->direction);
|
||||
dma->n_dma_pages = 0;
|
||||
dma->dev = NULL;
|
||||
}
|
||||
|
||||
vfree(dma->sglist);
|
||||
dma->sglist = NULL;
|
||||
|
||||
vfree(dma->kvirt);
|
||||
dma->kvirt = NULL;
|
||||
dma->n_pages = 0;
|
||||
}
|
||||
|
||||
/* find the scatterlist index and remaining offset corresponding to a
|
||||
given offset from the beginning of the buffer */
|
||||
static inline int dma_region_find(struct dma_region *dma, unsigned long offset,
|
||||
unsigned int start, unsigned long *rem)
|
||||
{
|
||||
int i;
|
||||
unsigned long off = offset;
|
||||
|
||||
for (i = start; i < dma->n_dma_pages; i++) {
|
||||
if (off < sg_dma_len(&dma->sglist[i])) {
|
||||
*rem = off;
|
||||
break;
|
||||
}
|
||||
|
||||
off -= sg_dma_len(&dma->sglist[i]);
|
||||
}
|
||||
|
||||
BUG_ON(i >= dma->n_dma_pages);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_region_offset_to_bus - get bus address of an offset within a DMA region
|
||||
*
|
||||
* Returns the DMA bus address of the byte with the given @offset relative to
|
||||
* the beginning of the @dma.
|
||||
*/
|
||||
dma_addr_t dma_region_offset_to_bus(struct dma_region * dma,
|
||||
unsigned long offset)
|
||||
{
|
||||
unsigned long rem = 0;
|
||||
|
||||
struct scatterlist *sg =
|
||||
&dma->sglist[dma_region_find(dma, offset, 0, &rem)];
|
||||
return sg_dma_address(sg) + rem;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_region_sync_for_cpu - sync the CPU's view of the buffer
|
||||
*/
|
||||
void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
|
||||
unsigned long len)
|
||||
{
|
||||
int first, last;
|
||||
unsigned long rem = 0;
|
||||
|
||||
if (!len)
|
||||
len = 1;
|
||||
|
||||
first = dma_region_find(dma, offset, 0, &rem);
|
||||
last = dma_region_find(dma, rem + len - 1, first, &rem);
|
||||
|
||||
pci_dma_sync_sg_for_cpu(dma->dev, &dma->sglist[first], last - first + 1,
|
||||
dma->direction);
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_region_sync_for_device - sync the IO bus' view of the buffer
|
||||
*/
|
||||
void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
|
||||
unsigned long len)
|
||||
{
|
||||
int first, last;
|
||||
unsigned long rem = 0;
|
||||
|
||||
if (!len)
|
||||
len = 1;
|
||||
|
||||
first = dma_region_find(dma, offset, 0, &rem);
|
||||
last = dma_region_find(dma, rem + len - 1, first, &rem);
|
||||
|
||||
pci_dma_sync_sg_for_device(dma->dev, &dma->sglist[first],
|
||||
last - first + 1, dma->direction);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
|
||||
static int dma_region_pagefault(struct vm_area_struct *vma,
|
||||
struct vm_fault *vmf)
|
||||
{
|
||||
struct dma_region *dma = (struct dma_region *)vma->vm_private_data;
|
||||
|
||||
if (!dma->kvirt)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
if (vmf->pgoff >= dma->n_pages)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
vmf->page = vmalloc_to_page(dma->kvirt + (vmf->pgoff << PAGE_SHIFT));
|
||||
get_page(vmf->page);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct dma_region_vm_ops = {
|
||||
.fault = dma_region_pagefault,
|
||||
};
|
||||
|
||||
/**
|
||||
* dma_region_mmap - map the buffer into a user space process
|
||||
*/
|
||||
int dma_region_mmap(struct dma_region *dma, struct file *file,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
unsigned long size;
|
||||
|
||||
if (!dma->kvirt)
|
||||
return -EINVAL;
|
||||
|
||||
/* must be page-aligned (XXX: comment is wrong, we could allow pgoff) */
|
||||
if (vma->vm_pgoff != 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* check the length */
|
||||
size = vma->vm_end - vma->vm_start;
|
||||
if (size > (dma->n_pages << PAGE_SHIFT))
|
||||
return -EINVAL;
|
||||
|
||||
vma->vm_ops = &dma_region_vm_ops;
|
||||
vma->vm_private_data = dma;
|
||||
vma->vm_file = file;
|
||||
vma->vm_flags |= VM_RESERVED | VM_ALWAYSDUMP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* CONFIG_MMU */
|
||||
|
||||
int dma_region_mmap(struct dma_region *dma, struct file *file,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MMU */
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* DMA region bookkeeping routines
|
||||
*
|
||||
* Copyright (C) 2002 Maas Digital LLC
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#ifndef IEEE1394_DMA_H
|
||||
#define IEEE1394_DMA_H
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
struct file;
|
||||
struct pci_dev;
|
||||
struct scatterlist;
|
||||
struct vm_area_struct;
|
||||
|
||||
/**
|
||||
* struct dma_prog_region - small contiguous DMA buffer
|
||||
* @kvirt: kernel virtual address
|
||||
* @dev: PCI device
|
||||
* @n_pages: number of kernel pages
|
||||
* @bus_addr: base bus address
|
||||
*
|
||||
* a small, physically contiguous DMA buffer with random-access, synchronous
|
||||
* usage characteristics
|
||||
*/
|
||||
struct dma_prog_region {
|
||||
unsigned char *kvirt;
|
||||
struct pci_dev *dev;
|
||||
unsigned int n_pages;
|
||||
dma_addr_t bus_addr;
|
||||
};
|
||||
|
||||
/* clear out all fields but do not allocate any memory */
|
||||
void dma_prog_region_init(struct dma_prog_region *prog);
|
||||
int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
|
||||
struct pci_dev *dev);
|
||||
void dma_prog_region_free(struct dma_prog_region *prog);
|
||||
|
||||
static inline dma_addr_t dma_prog_region_offset_to_bus(
|
||||
struct dma_prog_region *prog, unsigned long offset)
|
||||
{
|
||||
return prog->bus_addr + offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct dma_region - large non-contiguous DMA buffer
|
||||
* @virt: kernel virtual address
|
||||
* @dev: PCI device
|
||||
* @n_pages: number of kernel pages
|
||||
* @n_dma_pages: number of IOMMU pages
|
||||
* @sglist: IOMMU mapping
|
||||
* @direction: PCI_DMA_TODEVICE, etc.
|
||||
*
|
||||
* a large, non-physically-contiguous DMA buffer with streaming, asynchronous
|
||||
* usage characteristics
|
||||
*/
|
||||
struct dma_region {
|
||||
unsigned char *kvirt;
|
||||
struct pci_dev *dev;
|
||||
unsigned int n_pages;
|
||||
unsigned int n_dma_pages;
|
||||
struct scatterlist *sglist;
|
||||
int direction;
|
||||
};
|
||||
|
||||
void dma_region_init(struct dma_region *dma);
|
||||
int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
|
||||
struct pci_dev *dev, int direction);
|
||||
void dma_region_free(struct dma_region *dma);
|
||||
void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
|
||||
unsigned long len);
|
||||
void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
|
||||
unsigned long len);
|
||||
int dma_region_mmap(struct dma_region *dma, struct file *file,
|
||||
struct vm_area_struct *vma);
|
||||
dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
|
||||
unsigned long offset);
|
||||
|
||||
/**
|
||||
* dma_region_i - macro to index into a DMA region (or dma_prog_region)
|
||||
*/
|
||||
#define dma_region_i(_dma, _type, _index) \
|
||||
( ((_type*) ((_dma)->kvirt)) + (_index) )
|
||||
|
||||
#endif /* IEEE1394_DMA_H */
|
|
@ -1,587 +0,0 @@
|
|||
/*
|
||||
* dv1394-private.h - DV input/output over IEEE 1394 on OHCI chips
|
||||
* Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
|
||||
* receive by Dan Dennedy <dan@dennedy.org>
|
||||
*
|
||||
* based on:
|
||||
* video1394.h - driver for OHCI 1394 boards
|
||||
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
|
||||
* Peter Schlaile <udbz@rz.uni-karlsruhe.de>
|
||||
*
|
||||
* 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 _DV_1394_PRIVATE_H
|
||||
#define _DV_1394_PRIVATE_H
|
||||
|
||||
#include "ieee1394.h"
|
||||
#include "ohci1394.h"
|
||||
#include "dma.h"
|
||||
|
||||
/* data structures private to the dv1394 driver */
|
||||
/* none of this is exposed to user-space */
|
||||
|
||||
|
||||
/*
|
||||
the 8-byte CIP (Common Isochronous Packet) header that precedes
|
||||
each packet of DV data.
|
||||
|
||||
See the IEC 61883 standard.
|
||||
*/
|
||||
|
||||
struct CIP_header { unsigned char b[8]; };
|
||||
|
||||
static inline void fill_cip_header(struct CIP_header *cip,
|
||||
unsigned char source_node_id,
|
||||
unsigned long counter,
|
||||
enum pal_or_ntsc format,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
cip->b[0] = source_node_id;
|
||||
cip->b[1] = 0x78; /* packet size in quadlets (480/4) - even for empty packets! */
|
||||
cip->b[2] = 0x00;
|
||||
cip->b[3] = counter;
|
||||
|
||||
cip->b[4] = 0x80; /* const */
|
||||
|
||||
switch(format) {
|
||||
case DV1394_PAL:
|
||||
cip->b[5] = 0x80;
|
||||
break;
|
||||
case DV1394_NTSC:
|
||||
cip->b[5] = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
cip->b[6] = timestamp >> 8;
|
||||
cip->b[7] = timestamp & 0xFF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
DMA commands used to program the OHCI's DMA engine
|
||||
|
||||
See the Texas Instruments OHCI 1394 chipset documentation.
|
||||
*/
|
||||
|
||||
struct output_more_immediate { __le32 q[8]; };
|
||||
struct output_more { __le32 q[4]; };
|
||||
struct output_last { __le32 q[4]; };
|
||||
struct input_more { __le32 q[4]; };
|
||||
struct input_last { __le32 q[4]; };
|
||||
|
||||
/* outputs */
|
||||
|
||||
static inline void fill_output_more_immediate(struct output_more_immediate *omi,
|
||||
unsigned char tag,
|
||||
unsigned char channel,
|
||||
unsigned char sync_tag,
|
||||
unsigned int payload_size)
|
||||
{
|
||||
omi->q[0] = cpu_to_le32(0x02000000 | 8); /* OUTPUT_MORE_IMMEDIATE; 8 is the size of the IT header */
|
||||
omi->q[1] = cpu_to_le32(0);
|
||||
omi->q[2] = cpu_to_le32(0);
|
||||
omi->q[3] = cpu_to_le32(0);
|
||||
|
||||
/* IT packet header */
|
||||
omi->q[4] = cpu_to_le32( (0x0 << 16) /* IEEE1394_SPEED_100 */
|
||||
| (tag << 14)
|
||||
| (channel << 8)
|
||||
| (TCODE_ISO_DATA << 4)
|
||||
| (sync_tag) );
|
||||
|
||||
/* reserved field; mimic behavior of my Sony DSR-40 */
|
||||
omi->q[5] = cpu_to_le32((payload_size << 16) | (0x7F << 8) | 0xA0);
|
||||
|
||||
omi->q[6] = cpu_to_le32(0);
|
||||
omi->q[7] = cpu_to_le32(0);
|
||||
}
|
||||
|
||||
static inline void fill_output_more(struct output_more *om,
|
||||
unsigned int data_size,
|
||||
unsigned long data_phys_addr)
|
||||
{
|
||||
om->q[0] = cpu_to_le32(data_size);
|
||||
om->q[1] = cpu_to_le32(data_phys_addr);
|
||||
om->q[2] = cpu_to_le32(0);
|
||||
om->q[3] = cpu_to_le32(0);
|
||||
}
|
||||
|
||||
static inline void fill_output_last(struct output_last *ol,
|
||||
int want_timestamp,
|
||||
int want_interrupt,
|
||||
unsigned int data_size,
|
||||
unsigned long data_phys_addr)
|
||||
{
|
||||
u32 temp = 0;
|
||||
temp |= 1 << 28; /* OUTPUT_LAST */
|
||||
|
||||
if (want_timestamp) /* controller will update timestamp at DMA time */
|
||||
temp |= 1 << 27;
|
||||
|
||||
if (want_interrupt)
|
||||
temp |= 3 << 20;
|
||||
|
||||
temp |= 3 << 18; /* must take branch */
|
||||
temp |= data_size;
|
||||
|
||||
ol->q[0] = cpu_to_le32(temp);
|
||||
ol->q[1] = cpu_to_le32(data_phys_addr);
|
||||
ol->q[2] = cpu_to_le32(0);
|
||||
ol->q[3] = cpu_to_le32(0);
|
||||
}
|
||||
|
||||
/* inputs */
|
||||
|
||||
static inline void fill_input_more(struct input_more *im,
|
||||
int want_interrupt,
|
||||
unsigned int data_size,
|
||||
unsigned long data_phys_addr)
|
||||
{
|
||||
u32 temp = 2 << 28; /* INPUT_MORE */
|
||||
temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
|
||||
if (want_interrupt)
|
||||
temp |= 0 << 20; /* interrupts, i=0 in packet-per-buffer mode */
|
||||
temp |= 0x0 << 16; /* disable branch to address for packet-per-buffer mode */
|
||||
/* disable wait on sync field, not used in DV :-( */
|
||||
temp |= data_size;
|
||||
|
||||
im->q[0] = cpu_to_le32(temp);
|
||||
im->q[1] = cpu_to_le32(data_phys_addr);
|
||||
im->q[2] = cpu_to_le32(0); /* branchAddress and Z not use in packet-per-buffer mode */
|
||||
im->q[3] = cpu_to_le32(0); /* xferStatus & resCount, resCount must be initialize to data_size */
|
||||
}
|
||||
|
||||
static inline void fill_input_last(struct input_last *il,
|
||||
int want_interrupt,
|
||||
unsigned int data_size,
|
||||
unsigned long data_phys_addr)
|
||||
{
|
||||
u32 temp = 3 << 28; /* INPUT_LAST */
|
||||
temp |= 8 << 24; /* s = 1, update xferStatus and resCount */
|
||||
if (want_interrupt)
|
||||
temp |= 3 << 20; /* enable interrupts */
|
||||
temp |= 0xC << 16; /* enable branch to address */
|
||||
/* disable wait on sync field, not used in DV :-( */
|
||||
temp |= data_size;
|
||||
|
||||
il->q[0] = cpu_to_le32(temp);
|
||||
il->q[1] = cpu_to_le32(data_phys_addr);
|
||||
il->q[2] = cpu_to_le32(1); /* branchAddress (filled in later) and Z = 1 descriptor in next block */
|
||||
il->q[3] = cpu_to_le32(data_size); /* xferStatus & resCount, resCount must be initialize to data_size */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
A "DMA descriptor block" consists of several contiguous DMA commands.
|
||||
struct DMA_descriptor_block encapsulates all of the commands necessary
|
||||
to send one packet of DV data.
|
||||
|
||||
There are three different types of these blocks:
|
||||
|
||||
1) command to send an empty packet (CIP header only, no DV data):
|
||||
|
||||
OUTPUT_MORE-Immediate <-- contains the iso header in-line
|
||||
OUTPUT_LAST <-- points to the CIP header
|
||||
|
||||
2) command to send a full packet when the DV data payload does NOT
|
||||
cross a page boundary:
|
||||
|
||||
OUTPUT_MORE-Immediate <-- contains the iso header in-line
|
||||
OUTPUT_MORE <-- points to the CIP header
|
||||
OUTPUT_LAST <-- points to entire DV data payload
|
||||
|
||||
3) command to send a full packet when the DV payload DOES cross
|
||||
a page boundary:
|
||||
|
||||
OUTPUT_MORE-Immediate <-- contains the iso header in-line
|
||||
OUTPUT_MORE <-- points to the CIP header
|
||||
OUTPUT_MORE <-- points to first part of DV data payload
|
||||
OUTPUT_LAST <-- points to second part of DV data payload
|
||||
|
||||
This struct describes all three block types using unions.
|
||||
|
||||
!!! It is vital that an even number of these descriptor blocks fit on one
|
||||
page of memory, since a block cannot cross a page boundary !!!
|
||||
|
||||
*/
|
||||
|
||||
struct DMA_descriptor_block {
|
||||
|
||||
union {
|
||||
struct {
|
||||
/* iso header, common to all output block types */
|
||||
struct output_more_immediate omi;
|
||||
|
||||
union {
|
||||
/* empty packet */
|
||||
struct {
|
||||
struct output_last ol; /* CIP header */
|
||||
} empty;
|
||||
|
||||
/* full packet */
|
||||
struct {
|
||||
struct output_more om; /* CIP header */
|
||||
|
||||
union {
|
||||
/* payload does not cross page boundary */
|
||||
struct {
|
||||
struct output_last ol; /* data payload */
|
||||
} nocross;
|
||||
|
||||
/* payload crosses page boundary */
|
||||
struct {
|
||||
struct output_more om; /* data payload */
|
||||
struct output_last ol; /* data payload */
|
||||
} cross;
|
||||
} u;
|
||||
|
||||
} full;
|
||||
} u;
|
||||
} out;
|
||||
|
||||
struct {
|
||||
struct input_last il;
|
||||
} in;
|
||||
|
||||
} u;
|
||||
|
||||
/* ensure that PAGE_SIZE % sizeof(struct DMA_descriptor_block) == 0
|
||||
by padding out to 128 bytes */
|
||||
u32 __pad__[12];
|
||||
};
|
||||
|
||||
|
||||
/* struct frame contains all data associated with one frame in the
|
||||
ringbuffer these are allocated when the DMA context is initialized
|
||||
do_dv1394_init(). They are re-used after the card finishes
|
||||
transmitting the frame. */
|
||||
|
||||
struct video_card; /* forward declaration */
|
||||
|
||||
struct frame {
|
||||
|
||||
/* points to the struct video_card that owns this frame */
|
||||
struct video_card *video;
|
||||
|
||||
/* index of this frame in video_card->frames[] */
|
||||
unsigned int frame_num;
|
||||
|
||||
/* FRAME_CLEAR - DMA program not set up, waiting for data
|
||||
FRAME_READY - DMA program written, ready to transmit
|
||||
|
||||
Changes to these should be locked against the interrupt
|
||||
*/
|
||||
enum {
|
||||
FRAME_CLEAR = 0,
|
||||
FRAME_READY
|
||||
} state;
|
||||
|
||||
/* whether this frame has been DMA'ed already; used only from
|
||||
the IRQ handler to determine whether the frame can be reset */
|
||||
int done;
|
||||
|
||||
|
||||
/* kernel virtual pointer to the start of this frame's data in
|
||||
the user ringbuffer. Use only for CPU access; to get the DMA
|
||||
bus address you must go through the video->user_dma mapping */
|
||||
unsigned long data;
|
||||
|
||||
/* Max # of packets per frame */
|
||||
#define MAX_PACKETS 500
|
||||
|
||||
|
||||
/* a PAGE_SIZE memory pool for allocating CIP headers
|
||||
!header_pool must be aligned to PAGE_SIZE! */
|
||||
struct CIP_header *header_pool;
|
||||
dma_addr_t header_pool_dma;
|
||||
|
||||
|
||||
/* a physically contiguous memory pool for allocating DMA
|
||||
descriptor blocks; usually around 64KB in size
|
||||
!descriptor_pool must be aligned to PAGE_SIZE! */
|
||||
struct DMA_descriptor_block *descriptor_pool;
|
||||
dma_addr_t descriptor_pool_dma;
|
||||
unsigned long descriptor_pool_size;
|
||||
|
||||
|
||||
/* # of packets allocated for this frame */
|
||||
unsigned int n_packets;
|
||||
|
||||
|
||||
/* below are several pointers (kernel virtual addresses, not
|
||||
DMA bus addresses) to parts of the DMA program. These are
|
||||
set each time the DMA program is written in
|
||||
frame_prepare(). They are used later on, e.g. from the
|
||||
interrupt handler, to check the status of the frame */
|
||||
|
||||
/* points to status/timestamp field of first DMA packet */
|
||||
/* (we'll check it later to monitor timestamp accuracy) */
|
||||
__le32 *frame_begin_timestamp;
|
||||
|
||||
/* the timestamp we assigned to the first packet in the frame */
|
||||
u32 assigned_timestamp;
|
||||
|
||||
/* pointer to the first packet's CIP header (where the timestamp goes) */
|
||||
struct CIP_header *cip_syt1;
|
||||
|
||||
/* pointer to the second packet's CIP header
|
||||
(only set if the first packet was empty) */
|
||||
struct CIP_header *cip_syt2;
|
||||
|
||||
/* in order to figure out what caused an interrupt,
|
||||
store pointers to the status fields of the two packets
|
||||
that can cause interrupts. We'll check these from the
|
||||
interrupt handler.
|
||||
*/
|
||||
__le32 *mid_frame_timestamp;
|
||||
__le32 *frame_end_timestamp;
|
||||
|
||||
/* branch address field of final packet. This is effectively
|
||||
the "tail" in the chain of DMA descriptor blocks.
|
||||
We will fill it with the address of the first DMA descriptor
|
||||
block in the subsequent frame, once it is ready.
|
||||
*/
|
||||
__le32 *frame_end_branch;
|
||||
|
||||
/* the number of descriptors in the first descriptor block
|
||||
of the frame. Needed to start DMA */
|
||||
int first_n_descriptors;
|
||||
};
|
||||
|
||||
|
||||
struct packet {
|
||||
__le16 timestamp;
|
||||
u16 invalid;
|
||||
u16 iso_header;
|
||||
__le16 data_length;
|
||||
u32 cip_h1;
|
||||
u32 cip_h2;
|
||||
unsigned char data[480];
|
||||
unsigned char padding[16]; /* force struct size =512 for page alignment */
|
||||
};
|
||||
|
||||
|
||||
/* allocate/free a frame */
|
||||
static struct frame* frame_new(unsigned int frame_num, struct video_card *video);
|
||||
static void frame_delete(struct frame *f);
|
||||
|
||||
/* reset f so that it can be used again */
|
||||
static void frame_reset(struct frame *f);
|
||||
|
||||
/* struct video_card contains all data associated with one instance
|
||||
of the dv1394 driver
|
||||
*/
|
||||
enum modes {
|
||||
MODE_RECEIVE,
|
||||
MODE_TRANSMIT
|
||||
};
|
||||
|
||||
struct video_card {
|
||||
|
||||
/* ohci card to which this instance corresponds */
|
||||
struct ti_ohci *ohci;
|
||||
|
||||
/* OHCI card id; the link between the VFS inode and a specific video_card
|
||||
(essentially the device minor number) */
|
||||
int id;
|
||||
|
||||
/* entry in dv1394_cards */
|
||||
struct list_head list;
|
||||
|
||||
/* OHCI card IT DMA context number, -1 if not in use */
|
||||
int ohci_it_ctx;
|
||||
struct ohci1394_iso_tasklet it_tasklet;
|
||||
|
||||
/* register offsets for current IT DMA context, 0 if not in use */
|
||||
u32 ohci_IsoXmitContextControlSet;
|
||||
u32 ohci_IsoXmitContextControlClear;
|
||||
u32 ohci_IsoXmitCommandPtr;
|
||||
|
||||
/* OHCI card IR DMA context number, -1 if not in use */
|
||||
struct ohci1394_iso_tasklet ir_tasklet;
|
||||
int ohci_ir_ctx;
|
||||
|
||||
/* register offsets for current IR DMA context, 0 if not in use */
|
||||
u32 ohci_IsoRcvContextControlSet;
|
||||
u32 ohci_IsoRcvContextControlClear;
|
||||
u32 ohci_IsoRcvCommandPtr;
|
||||
u32 ohci_IsoRcvContextMatch;
|
||||
|
||||
|
||||
/* CONCURRENCY CONTROL */
|
||||
|
||||
/* there are THREE levels of locking associated with video_card. */
|
||||
|
||||
/*
|
||||
1) the 'open' flag - this prevents more than one process from
|
||||
opening the device. (the driver currently assumes only one opener).
|
||||
This is a regular int, but use test_and_set_bit() (on bit zero)
|
||||
for atomicity.
|
||||
*/
|
||||
unsigned long open;
|
||||
|
||||
/*
|
||||
2) the spinlock - this provides mutual exclusion between the interrupt
|
||||
handler and process-context operations. Generally you must take the
|
||||
spinlock under the following conditions:
|
||||
1) DMA (and hence the interrupt handler) may be running
|
||||
AND
|
||||
2) you need to operate on the video_card, especially active_frame
|
||||
|
||||
It is OK to play with video_card without taking the spinlock if
|
||||
you are certain that DMA is not running. Even if DMA is running,
|
||||
it is OK to *read* active_frame with the lock, then drop it
|
||||
immediately. This is safe because the interrupt handler will never
|
||||
advance active_frame onto a frame that is not READY (and the spinlock
|
||||
must be held while marking a frame READY).
|
||||
|
||||
spinlock is also used to protect ohci_it_ctx and ohci_ir_ctx,
|
||||
which can be accessed from both process and interrupt context
|
||||
*/
|
||||
spinlock_t spinlock;
|
||||
|
||||
/* flag to prevent spurious interrupts (which OHCI seems to
|
||||
generate a lot :) from accessing the struct */
|
||||
int dma_running;
|
||||
|
||||
/*
|
||||
3) the sleeping mutex 'mtx' - this is used from process context only,
|
||||
to serialize various operations on the video_card. Even though only one
|
||||
open() is allowed, we still need to prevent multiple threads of execution
|
||||
from entering calls like read, write, ioctl, etc.
|
||||
|
||||
I honestly can't think of a good reason to use dv1394 from several threads
|
||||
at once, but we need to serialize anyway to prevent oopses =).
|
||||
|
||||
NOTE: if you need both spinlock and mtx, take mtx first to avoid deadlock!
|
||||
*/
|
||||
struct mutex mtx;
|
||||
|
||||
/* people waiting for buffer space, please form a line here... */
|
||||
wait_queue_head_t waitq;
|
||||
|
||||
/* support asynchronous I/O signals (SIGIO) */
|
||||
struct fasync_struct *fasync;
|
||||
|
||||
/* the large, non-contiguous (rvmalloc()) ringbuffer for DV
|
||||
data, exposed to user-space via mmap() */
|
||||
unsigned long dv_buf_size;
|
||||
struct dma_region dv_buf;
|
||||
|
||||
/* next byte in the ringbuffer that a write() call will fill */
|
||||
size_t write_off;
|
||||
|
||||
struct frame *frames[DV1394_MAX_FRAMES];
|
||||
|
||||
/* n_frames also serves as an indicator that this struct video_card is
|
||||
initialized and ready to run DMA buffers */
|
||||
|
||||
int n_frames;
|
||||
|
||||
/* this is the frame that is currently "owned" by the OHCI DMA controller
|
||||
(set to -1 iff DMA is not running)
|
||||
|
||||
! must lock against the interrupt handler when accessing it !
|
||||
|
||||
RULES:
|
||||
|
||||
Only the interrupt handler may change active_frame if DMA
|
||||
is running; if not, process may change it
|
||||
|
||||
If the next frame is READY, the interrupt handler will advance
|
||||
active_frame when the current frame is finished.
|
||||
|
||||
If the next frame is CLEAR, the interrupt handler will re-transmit
|
||||
the current frame, and the dropped_frames counter will be incremented.
|
||||
|
||||
The interrupt handler will NEVER advance active_frame to a
|
||||
frame that is not READY.
|
||||
*/
|
||||
int active_frame;
|
||||
int first_run;
|
||||
|
||||
/* the same locking rules apply to these three fields also: */
|
||||
|
||||
/* altered ONLY from process context. Must check first_clear_frame->state;
|
||||
if it's READY, that means the ringbuffer is full with READY frames;
|
||||
if it's CLEAR, that means one or more ringbuffer frames are CLEAR */
|
||||
unsigned int first_clear_frame;
|
||||
|
||||
/* altered both by process and interrupt */
|
||||
unsigned int n_clear_frames;
|
||||
|
||||
/* only altered by the interrupt */
|
||||
unsigned int dropped_frames;
|
||||
|
||||
|
||||
|
||||
/* the CIP accumulator and continuity counter are properties
|
||||
of the DMA stream as a whole (not a single frame), so they
|
||||
are stored here in the video_card */
|
||||
|
||||
unsigned long cip_accum;
|
||||
unsigned long cip_n, cip_d;
|
||||
unsigned int syt_offset;
|
||||
unsigned int continuity_counter;
|
||||
|
||||
enum pal_or_ntsc pal_or_ntsc;
|
||||
|
||||
/* redundant, but simplifies the code somewhat */
|
||||
unsigned int frame_size; /* in bytes */
|
||||
|
||||
/* the isochronous channel to use, -1 if video card is inactive */
|
||||
int channel;
|
||||
|
||||
|
||||
/* physically contiguous packet ringbuffer for receive */
|
||||
struct dma_region packet_buf;
|
||||
unsigned long packet_buf_size;
|
||||
|
||||
unsigned int current_packet;
|
||||
int first_frame; /* received first start frame marker? */
|
||||
enum modes mode;
|
||||
};
|
||||
|
||||
/*
|
||||
if the video_card is not initialized, then the ONLY fields that are valid are:
|
||||
ohci
|
||||
open
|
||||
n_frames
|
||||
*/
|
||||
|
||||
static inline int video_card_initialized(struct video_card *v)
|
||||
{
|
||||
return v->n_frames > 0;
|
||||
}
|
||||
|
||||
static int do_dv1394_init(struct video_card *video, struct dv1394_init *init);
|
||||
static int do_dv1394_init_default(struct video_card *video);
|
||||
static void do_dv1394_shutdown(struct video_card *video, int free_user_buf);
|
||||
|
||||
|
||||
/* NTSC empty packet rate accurate to within 0.01%,
|
||||
calibrated against a Sony DSR-40 DVCAM deck */
|
||||
|
||||
#define CIP_N_NTSC 68000000
|
||||
#define CIP_D_NTSC 1068000000
|
||||
|
||||
#define CIP_N_PAL 1
|
||||
#define CIP_D_PAL 16
|
||||
|
||||
#endif /* _DV_1394_PRIVATE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -1,305 +0,0 @@
|
|||
/*
|
||||
* dv1394.h - DV input/output over IEEE 1394 on OHCI chips
|
||||
* Copyright (C)2001 Daniel Maas <dmaas@dcine.com>
|
||||
* receive by Dan Dennedy <dan@dennedy.org>
|
||||
*
|
||||
* based on:
|
||||
* video1394.h - driver for OHCI 1394 boards
|
||||
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
|
||||
* Peter Schlaile <udbz@rz.uni-karlsruhe.de>
|
||||
*
|
||||
* 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 _DV_1394_H
|
||||
#define _DV_1394_H
|
||||
|
||||
/* This is the public user-space interface. Try not to break it. */
|
||||
|
||||
#define DV1394_API_VERSION 0x20011127
|
||||
|
||||
/* ********************
|
||||
** **
|
||||
** DV1394 API **
|
||||
** **
|
||||
********************
|
||||
|
||||
There are two methods of operating the DV1394 DV output device.
|
||||
|
||||
1)
|
||||
|
||||
The simplest is an interface based on write(): simply write
|
||||
full DV frames of data to the device, and they will be transmitted
|
||||
as quickly as possible. The FD may be set for non-blocking I/O,
|
||||
in which case you can use select() or poll() to wait for output
|
||||
buffer space.
|
||||
|
||||
To set the DV output parameters (e.g. whether you want NTSC or PAL
|
||||
video), use the DV1394_INIT ioctl, passing in the parameters you
|
||||
want in a struct dv1394_init.
|
||||
|
||||
Example 1:
|
||||
To play a raw .DV file: cat foo.DV > /dev/dv1394
|
||||
(cat will use write() internally)
|
||||
|
||||
Example 2:
|
||||
static struct dv1394_init init = {
|
||||
0x63, (broadcast channel)
|
||||
4, (four-frame ringbuffer)
|
||||
DV1394_NTSC, (send NTSC video)
|
||||
0, 0 (default empty packet rate)
|
||||
}
|
||||
|
||||
ioctl(fd, DV1394_INIT, &init);
|
||||
|
||||
while (1) {
|
||||
read( <a raw DV file>, buf, DV1394_NTSC_FRAME_SIZE );
|
||||
write( <the dv1394 FD>, buf, DV1394_NTSC_FRAME_SIZE );
|
||||
}
|
||||
|
||||
2)
|
||||
|
||||
For more control over buffering, and to avoid unnecessary copies
|
||||
of the DV data, you can use the more sophisticated the mmap() interface.
|
||||
First, call the DV1394_INIT ioctl to specify your parameters,
|
||||
including the number of frames in the ringbuffer. Then, calling mmap()
|
||||
on the dv1394 device will give you direct access to the ringbuffer
|
||||
from which the DV card reads your frame data.
|
||||
|
||||
The ringbuffer is simply one large, contiguous region of memory
|
||||
containing two or more frames of packed DV data. Each frame of DV data
|
||||
is 120000 bytes (NTSC) or 144000 bytes (PAL).
|
||||
|
||||
Fill one or more frames in the ringbuffer, then use the DV1394_SUBMIT_FRAMES
|
||||
ioctl to begin I/O. You can use either the DV1394_WAIT_FRAMES ioctl
|
||||
or select()/poll() to wait until the frames are transmitted. Next, you'll
|
||||
need to call the DV1394_GET_STATUS ioctl to determine which ringbuffer
|
||||
frames are clear (ready to be filled with new DV data). Finally, use
|
||||
DV1394_SUBMIT_FRAMES again to send the new data to the DV output.
|
||||
|
||||
|
||||
Example: here is what a four-frame ringbuffer might look like
|
||||
during DV transmission:
|
||||
|
||||
|
||||
frame 0 frame 1 frame 2 frame 3
|
||||
|
||||
*--------------------------------------*
|
||||
| CLEAR | DV data | DV data | CLEAR |
|
||||
*--------------------------------------*
|
||||
<ACTIVE>
|
||||
|
||||
transmission goes in this direction --->>>
|
||||
|
||||
|
||||
The DV hardware is currently transmitting the data in frame 1.
|
||||
Once frame 1 is finished, it will automatically transmit frame 2.
|
||||
(if frame 2 finishes before frame 3 is submitted, the device
|
||||
will continue to transmit frame 2, and will increase the dropped_frames
|
||||
counter each time it repeats the transmission).
|
||||
|
||||
|
||||
If you called DV1394_GET_STATUS at this instant, you would
|
||||
receive the following values:
|
||||
|
||||
n_frames = 4
|
||||
active_frame = 1
|
||||
first_clear_frame = 3
|
||||
n_clear_frames = 2
|
||||
|
||||
At this point, you should write new DV data into frame 3 and optionally
|
||||
frame 0. Then call DV1394_SUBMIT_FRAMES to inform the device that
|
||||
it may transmit the new frames.
|
||||
|
||||
ERROR HANDLING
|
||||
|
||||
An error (buffer underflow/overflow or a break in the DV stream due
|
||||
to a 1394 bus reset) can be detected by checking the dropped_frames
|
||||
field of struct dv1394_status (obtained through the
|
||||
DV1394_GET_STATUS ioctl).
|
||||
|
||||
The best way to recover from such an error is to re-initialize
|
||||
dv1394, either by using the DV1394_INIT ioctl call, or closing the
|
||||
file descriptor and opening it again. (note that you must unmap all
|
||||
ringbuffer mappings when closing the file descriptor, or else
|
||||
dv1394 will still be considered 'in use').
|
||||
|
||||
MAIN LOOP
|
||||
|
||||
For maximum efficiency and robustness against bus errors, you are
|
||||
advised to model the main loop of your application after the
|
||||
following pseudo-code example:
|
||||
|
||||
(checks of system call return values omitted for brevity; always
|
||||
check return values in your code!)
|
||||
|
||||
while ( frames left ) {
|
||||
|
||||
struct pollfd *pfd = ...;
|
||||
|
||||
pfd->fd = dv1394_fd;
|
||||
pfd->revents = 0;
|
||||
pfd->events = POLLOUT | POLLIN; (OUT for transmit, IN for receive)
|
||||
|
||||
(add other sources of I/O here)
|
||||
|
||||
poll(pfd, 1, -1); (or select(); add a timeout if you want)
|
||||
|
||||
if (pfd->revents) {
|
||||
struct dv1394_status status;
|
||||
|
||||
ioctl(dv1394_fd, DV1394_GET_STATUS, &status);
|
||||
|
||||
if (status.dropped_frames > 0) {
|
||||
reset_dv1394();
|
||||
} else {
|
||||
for (int i = 0; i < status.n_clear_frames; i++) {
|
||||
copy_DV_frame();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
where copy_DV_frame() reads or writes on the dv1394 file descriptor
|
||||
(read/write mode) or copies data to/from the mmap ringbuffer and
|
||||
then calls ioctl(DV1394_SUBMIT_FRAMES) to notify dv1394 that new
|
||||
frames are availble (mmap mode).
|
||||
|
||||
reset_dv1394() is called in the event of a buffer
|
||||
underflow/overflow or a halt in the DV stream (e.g. due to a 1394
|
||||
bus reset). To guarantee recovery from the error, this function
|
||||
should close the dv1394 file descriptor (and munmap() all
|
||||
ringbuffer mappings, if you are using them), then re-open the
|
||||
dv1394 device (and re-map the ringbuffer).
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* maximum number of frames in the ringbuffer */
|
||||
#define DV1394_MAX_FRAMES 32
|
||||
|
||||
/* number of *full* isochronous packets per DV frame */
|
||||
#define DV1394_NTSC_PACKETS_PER_FRAME 250
|
||||
#define DV1394_PAL_PACKETS_PER_FRAME 300
|
||||
|
||||
/* size of one frame's worth of DV data, in bytes */
|
||||
#define DV1394_NTSC_FRAME_SIZE (480 * DV1394_NTSC_PACKETS_PER_FRAME)
|
||||
#define DV1394_PAL_FRAME_SIZE (480 * DV1394_PAL_PACKETS_PER_FRAME)
|
||||
|
||||
|
||||
/* ioctl() commands */
|
||||
#include "ieee1394-ioctl.h"
|
||||
|
||||
|
||||
enum pal_or_ntsc {
|
||||
DV1394_NTSC = 0,
|
||||
DV1394_PAL
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* this is the argument to DV1394_INIT */
|
||||
struct dv1394_init {
|
||||
/* DV1394_API_VERSION */
|
||||
unsigned int api_version;
|
||||
|
||||
/* isochronous transmission channel to use */
|
||||
unsigned int channel;
|
||||
|
||||
/* number of frames in the ringbuffer. Must be at least 2
|
||||
and at most DV1394_MAX_FRAMES. */
|
||||
unsigned int n_frames;
|
||||
|
||||
/* send/receive PAL or NTSC video format */
|
||||
enum pal_or_ntsc format;
|
||||
|
||||
/* the following are used only for transmission */
|
||||
|
||||
/* set these to zero unless you want a
|
||||
non-default empty packet rate (see below) */
|
||||
unsigned long cip_n;
|
||||
unsigned long cip_d;
|
||||
|
||||
/* set this to zero unless you want a
|
||||
non-default SYT cycle offset (default = 3 cycles) */
|
||||
unsigned int syt_offset;
|
||||
};
|
||||
|
||||
/* NOTE: you may only allocate the DV frame ringbuffer once each time
|
||||
you open the dv1394 device. DV1394_INIT will fail if you call it a
|
||||
second time with different 'n_frames' or 'format' arguments (which
|
||||
would imply a different size for the ringbuffer). If you need a
|
||||
different buffer size, simply close and re-open the device, then
|
||||
initialize it with your new settings. */
|
||||
|
||||
/* Q: What are cip_n and cip_d? */
|
||||
|
||||
/*
|
||||
A: DV video streams do not utilize 100% of the potential bandwidth offered
|
||||
by IEEE 1394 (FireWire). To achieve the correct rate of data transmission,
|
||||
DV devices must periodically insert empty packets into the 1394 data stream.
|
||||
Typically there is one empty packet per 14-16 data-carrying packets.
|
||||
|
||||
Some DV devices will accept a wide range of empty packet rates, while others
|
||||
require a precise rate. If the dv1394 driver produces empty packets at
|
||||
a rate that your device does not accept, you may see ugly patterns on the
|
||||
DV output, or even no output at all.
|
||||
|
||||
The default empty packet insertion rate seems to work for many people; if
|
||||
your DV output is stable, you can simply ignore this discussion. However,
|
||||
we have exposed the empty packet rate as a parameter to support devices that
|
||||
do not work with the default rate.
|
||||
|
||||
The decision to insert an empty packet is made with a numerator/denominator
|
||||
algorithm. Empty packets are produced at an average rate of CIP_N / CIP_D.
|
||||
You can alter the empty packet rate by passing non-zero values for cip_n
|
||||
and cip_d to the INIT ioctl.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
struct dv1394_status {
|
||||
/* this embedded init struct returns the current dv1394
|
||||
parameters in use */
|
||||
struct dv1394_init init;
|
||||
|
||||
/* the ringbuffer frame that is currently being
|
||||
displayed. (-1 if the device is not transmitting anything) */
|
||||
int active_frame;
|
||||
|
||||
/* index of the first buffer (ahead of active_frame) that
|
||||
is ready to be filled with data */
|
||||
unsigned int first_clear_frame;
|
||||
|
||||
/* how many buffers, including first_clear_buffer, are
|
||||
ready to be filled with data */
|
||||
unsigned int n_clear_frames;
|
||||
|
||||
/* how many times the DV stream has underflowed, overflowed,
|
||||
or otherwise encountered an error, since the previous call
|
||||
to DV1394_GET_STATUS */
|
||||
unsigned int dropped_frames;
|
||||
|
||||
/* N.B. The dropped_frames counter is only a lower bound on the actual
|
||||
number of dropped frames, with the special case that if dropped_frames
|
||||
is zero, then it is guaranteed that NO frames have been dropped
|
||||
since the last call to DV1394_GET_STATUS.
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
#endif /* _DV_1394_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,234 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
/* Register for incoming packets. This is 4096 bytes, which supports up to
|
||||
* S3200 (per Table 16-3 of IEEE 1394b-2002). */
|
||||
#define ETHER1394_REGION_ADDR_LEN 4096
|
||||
|
||||
/* GASP identifier numbers for IPv4 over IEEE 1394 */
|
||||
#define ETHER1394_GASP_SPECIFIER_ID 0x00005E
|
||||
#define ETHER1394_GASP_SPECIFIER_ID_HI ((0x00005E >> 8) & 0xffff)
|
||||
#define ETHER1394_GASP_SPECIFIER_ID_LO (0x00005E & 0xff)
|
||||
#define ETHER1394_GASP_VERSION 1
|
||||
|
||||
#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* for GASP header */
|
||||
|
||||
#define ETHER1394_GASP_BUFFERS 16
|
||||
|
||||
#define NODE_SET (ALL_NODES + 1) /* Node set == 64 */
|
||||
|
||||
enum eth1394_bc_states { ETHER1394_BC_ERROR,
|
||||
ETHER1394_BC_RUNNING,
|
||||
ETHER1394_BC_STOPPED };
|
||||
|
||||
|
||||
/* Private structure for our ethernet driver */
|
||||
struct eth1394_priv {
|
||||
struct hpsb_host *host; /* The card for this dev */
|
||||
u16 bc_maxpayload; /* Max broadcast payload */
|
||||
u8 bc_sspd; /* Max broadcast speed */
|
||||
u64 local_fifo; /* Local FIFO Address */
|
||||
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 */
|
||||
int bc_dgl; /* Outgoing broadcast datagram label */
|
||||
struct list_head ip_node_list; /* List of IP capable nodes */
|
||||
struct unit_directory *ud_list[ALL_NODES]; /* Cached unit dir list */
|
||||
|
||||
struct work_struct wake; /* Wake up after xmit failure */
|
||||
struct net_device *wake_dev; /* Stupid backlink for .wake */
|
||||
nodeid_t wake_node; /* Destination of failed xmit */
|
||||
};
|
||||
|
||||
|
||||
/* Define a fake hardware header format for the networking core. Note that
|
||||
* header size cannot exceed 16 bytes as that is the size of the header cache.
|
||||
* Also, we do not need the source address in the header so we omit it and
|
||||
* keep the header to under 16 bytes */
|
||||
#define ETH1394_ALEN (8)
|
||||
#define ETH1394_HLEN (10)
|
||||
|
||||
struct eth1394hdr {
|
||||
unsigned char h_dest[ETH1394_ALEN]; /* destination eth1394 addr */
|
||||
__be16 h_proto; /* packet type ID field */
|
||||
} __attribute__((packed));
|
||||
|
||||
static inline struct eth1394hdr *eth1394_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (struct eth1394hdr *)skb_mac_header(skb);
|
||||
}
|
||||
|
||||
typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type;
|
||||
|
||||
/* IP1394 headers */
|
||||
|
||||
/* Unfragmented */
|
||||
#if defined __BIG_ENDIAN_BITFIELD
|
||||
struct eth1394_uf_hdr {
|
||||
u16 lf:2;
|
||||
u16 res:14;
|
||||
__be16 ether_type; /* Ethernet packet type */
|
||||
} __attribute__((packed));
|
||||
#elif defined __LITTLE_ENDIAN_BITFIELD
|
||||
struct eth1394_uf_hdr {
|
||||
u16 res:14;
|
||||
u16 lf:2;
|
||||
__be16 ether_type;
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
#error Unknown bit field type
|
||||
#endif
|
||||
|
||||
/* First fragment */
|
||||
#if defined __BIG_ENDIAN_BITFIELD
|
||||
struct eth1394_ff_hdr {
|
||||
u16 lf:2;
|
||||
u16 res1:2;
|
||||
u16 dg_size:12; /* Datagram size */
|
||||
__be16 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;
|
||||
u16 res1:2;
|
||||
u16 lf:2;
|
||||
__be16 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 {
|
||||
u16 lf:2;
|
||||
u16 res1:2;
|
||||
u16 dg_size:12; /* Datagram size */
|
||||
u16 res2:4;
|
||||
u16 fg_off:12; /* Fragment offset */
|
||||
u16 dgl; /* Datagram label */
|
||||
u16 res3;
|
||||
} __attribute__((packed));
|
||||
#elif defined __LITTLE_ENDIAN_BITFIELD
|
||||
struct eth1394_sf_hdr {
|
||||
u16 dg_size:12;
|
||||
u16 res1:2;
|
||||
u16 lf:2;
|
||||
u16 fg_off:12;
|
||||
u16 res2:4;
|
||||
u16 dgl;
|
||||
u16 res3;
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
#error Unknown bit field type
|
||||
#endif
|
||||
|
||||
#if defined __BIG_ENDIAN_BITFIELD
|
||||
struct eth1394_common_hdr {
|
||||
u16 lf:2;
|
||||
u16 pad1:14;
|
||||
} __attribute__((packed));
|
||||
#elif defined __LITTLE_ENDIAN_BITFIELD
|
||||
struct eth1394_common_hdr {
|
||||
u16 pad1:14;
|
||||
u16 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 */
|
||||
|
||||
__be64 s_uniq_id; /* Sender's 64bit EUI */
|
||||
u8 max_rec; /* Sender's max packet size */
|
||||
u8 sspd; /* Sender's max speed */
|
||||
__be16 fifo_hi; /* hi 16bits of sender's FIFO addr */
|
||||
__be32 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
|
||||
|
||||
/* This is our task struct. It's used for the packet complete callback. */
|
||||
struct packet_task {
|
||||
struct sk_buff *skb;
|
||||
int outstanding_pkts;
|
||||
eth1394_tx_type tx_type;
|
||||
int max_payload;
|
||||
struct hpsb_packet *packet;
|
||||
struct eth1394_priv *priv;
|
||||
union eth1394_hdr hdr;
|
||||
u64 addr;
|
||||
u16 dest_node;
|
||||
};
|
||||
|
||||
#endif /* __ETH1394_H */
|
|
@ -1,691 +0,0 @@
|
|||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* Copyright (C) 1999 Andreas E. Bombe
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*
|
||||
*
|
||||
* Contributions:
|
||||
*
|
||||
* Christian Toegel <christian.toegel@gmx.at>
|
||||
* unregister address space
|
||||
*
|
||||
* Manfred Weihs <weihs@ict.tuwien.ac.at>
|
||||
* unregister address space
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_types.h"
|
||||
#include "hosts.h"
|
||||
#include "ieee1394_core.h"
|
||||
#include "highlevel.h"
|
||||
#include "nodemgr.h"
|
||||
|
||||
|
||||
struct hl_host_info {
|
||||
struct list_head list;
|
||||
struct hpsb_host *host;
|
||||
size_t size;
|
||||
unsigned long key;
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
||||
static LIST_HEAD(hl_drivers);
|
||||
static DECLARE_RWSEM(hl_drivers_sem);
|
||||
|
||||
static LIST_HEAD(hl_irqs);
|
||||
static DEFINE_RWLOCK(hl_irqs_lock);
|
||||
|
||||
static DEFINE_RWLOCK(addr_space_lock);
|
||||
|
||||
|
||||
static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
|
||||
struct hpsb_host *host)
|
||||
{
|
||||
struct hl_host_info *hi = NULL;
|
||||
|
||||
if (!hl || !host)
|
||||
return NULL;
|
||||
|
||||
read_lock(&hl->host_info_lock);
|
||||
list_for_each_entry(hi, &hl->host_info_list, list) {
|
||||
if (hi->host == host) {
|
||||
read_unlock(&hl->host_info_lock);
|
||||
return hi;
|
||||
}
|
||||
}
|
||||
read_unlock(&hl->host_info_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_get_hostinfo - retrieve a hostinfo pointer bound to this driver/host
|
||||
*
|
||||
* Returns a per @host and @hl driver data structure that was previously stored
|
||||
* by hpsb_create_hostinfo.
|
||||
*/
|
||||
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
|
||||
{
|
||||
struct hl_host_info *hi = hl_get_hostinfo(hl, host);
|
||||
|
||||
return hi ? hi->data : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_create_hostinfo - allocate a hostinfo pointer bound to this driver/host
|
||||
*
|
||||
* Allocate a hostinfo pointer backed by memory with @data_size and bind it to
|
||||
* to this @hl driver and @host. If @data_size is zero, then the return here is
|
||||
* only valid for error checking.
|
||||
*/
|
||||
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
size_t data_size)
|
||||
{
|
||||
struct hl_host_info *hi;
|
||||
void *data;
|
||||
unsigned long flags;
|
||||
|
||||
hi = hl_get_hostinfo(hl, host);
|
||||
if (hi) {
|
||||
HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already"
|
||||
" exists", hl->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hi = kzalloc(sizeof(*hi) + data_size, GFP_ATOMIC);
|
||||
if (!hi)
|
||||
return NULL;
|
||||
|
||||
if (data_size) {
|
||||
data = hi->data = hi + 1;
|
||||
hi->size = data_size;
|
||||
} else
|
||||
data = hi;
|
||||
|
||||
hi->host = host;
|
||||
|
||||
write_lock_irqsave(&hl->host_info_lock, flags);
|
||||
list_add_tail(&hi->list, &hl->host_info_list);
|
||||
write_unlock_irqrestore(&hl->host_info_lock, flags);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_set_hostinfo - set the hostinfo pointer to something useful
|
||||
*
|
||||
* Usually follows a call to hpsb_create_hostinfo, where the size is 0.
|
||||
*/
|
||||
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
void *data)
|
||||
{
|
||||
struct hl_host_info *hi;
|
||||
|
||||
hi = hl_get_hostinfo(hl, host);
|
||||
if (hi) {
|
||||
if (!hi->size && !hi->data) {
|
||||
hi->data = data;
|
||||
return 0;
|
||||
} else
|
||||
HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo "
|
||||
"already has data", hl->name);
|
||||
} else
|
||||
HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
|
||||
hl->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_destroy_hostinfo - free and remove a hostinfo pointer
|
||||
*
|
||||
* Free and remove the hostinfo pointer bound to this @hl driver and @host.
|
||||
*/
|
||||
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
|
||||
{
|
||||
struct hl_host_info *hi;
|
||||
|
||||
hi = hl_get_hostinfo(hl, host);
|
||||
if (hi) {
|
||||
unsigned long flags;
|
||||
write_lock_irqsave(&hl->host_info_lock, flags);
|
||||
list_del(&hi->list);
|
||||
write_unlock_irqrestore(&hl->host_info_lock, flags);
|
||||
kfree(hi);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_set_hostinfo_key - set an alternate lookup key for an hostinfo
|
||||
*
|
||||
* Sets an alternate lookup key for the hostinfo bound to this @hl driver and
|
||||
* @host.
|
||||
*/
|
||||
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
unsigned long key)
|
||||
{
|
||||
struct hl_host_info *hi;
|
||||
|
||||
hi = hl_get_hostinfo(hl, host);
|
||||
if (hi)
|
||||
hi->key = key;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_get_hostinfo_bykey - retrieve a hostinfo pointer by its alternate key
|
||||
*/
|
||||
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key)
|
||||
{
|
||||
struct hl_host_info *hi;
|
||||
void *data = NULL;
|
||||
|
||||
if (!hl)
|
||||
return NULL;
|
||||
|
||||
read_lock(&hl->host_info_lock);
|
||||
list_for_each_entry(hi, &hl->host_info_list, list) {
|
||||
if (hi->key == key) {
|
||||
data = hi->data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&hl->host_info_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
static int highlevel_for_each_host_reg(struct hpsb_host *host, void *__data)
|
||||
{
|
||||
struct hpsb_highlevel *hl = __data;
|
||||
|
||||
hl->add_host(host);
|
||||
|
||||
if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
|
||||
HPSB_ERR("Failed to generate Configuration ROM image for host "
|
||||
"%s-%d", hl->name, host->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_register_highlevel - register highlevel driver
|
||||
*
|
||||
* The name pointer in @hl has to stay valid at all times because the string is
|
||||
* not copied.
|
||||
*/
|
||||
void hpsb_register_highlevel(struct hpsb_highlevel *hl)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
hpsb_init_highlevel(hl);
|
||||
INIT_LIST_HEAD(&hl->addr_list);
|
||||
|
||||
down_write(&hl_drivers_sem);
|
||||
list_add_tail(&hl->hl_list, &hl_drivers);
|
||||
up_write(&hl_drivers_sem);
|
||||
|
||||
write_lock_irqsave(&hl_irqs_lock, flags);
|
||||
list_add_tail(&hl->irq_list, &hl_irqs);
|
||||
write_unlock_irqrestore(&hl_irqs_lock, flags);
|
||||
|
||||
if (hl->add_host)
|
||||
nodemgr_for_each_host(hl, highlevel_for_each_host_reg);
|
||||
return;
|
||||
}
|
||||
|
||||
static void __delete_addr(struct hpsb_address_serve *as)
|
||||
{
|
||||
list_del(&as->host_list);
|
||||
list_del(&as->hl_list);
|
||||
kfree(as);
|
||||
}
|
||||
|
||||
static void __unregister_host(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
int update_cr)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct list_head *lh, *next;
|
||||
struct hpsb_address_serve *as;
|
||||
|
||||
/* First, let the highlevel driver unreg */
|
||||
if (hl->remove_host)
|
||||
hl->remove_host(host);
|
||||
|
||||
/* Remove any addresses that are matched for this highlevel driver
|
||||
* and this particular host. */
|
||||
write_lock_irqsave(&addr_space_lock, flags);
|
||||
list_for_each_safe (lh, next, &hl->addr_list) {
|
||||
as = list_entry(lh, struct hpsb_address_serve, hl_list);
|
||||
if (as->host == host)
|
||||
__delete_addr(as);
|
||||
}
|
||||
write_unlock_irqrestore(&addr_space_lock, flags);
|
||||
|
||||
/* Now update the config-rom to reflect anything removed by the
|
||||
* highlevel driver. */
|
||||
if (update_cr && host->update_config_rom &&
|
||||
hpsb_update_config_rom_image(host) < 0)
|
||||
HPSB_ERR("Failed to generate Configuration ROM image for host "
|
||||
"%s-%d", hl->name, host->id);
|
||||
|
||||
/* Finally remove all the host info associated between these two. */
|
||||
hpsb_destroy_hostinfo(hl, host);
|
||||
}
|
||||
|
||||
static int highlevel_for_each_host_unreg(struct hpsb_host *host, void *__data)
|
||||
{
|
||||
struct hpsb_highlevel *hl = __data;
|
||||
|
||||
__unregister_host(hl, host, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_unregister_highlevel - unregister highlevel driver
|
||||
*/
|
||||
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&hl_irqs_lock, flags);
|
||||
list_del(&hl->irq_list);
|
||||
write_unlock_irqrestore(&hl_irqs_lock, flags);
|
||||
|
||||
down_write(&hl_drivers_sem);
|
||||
list_del(&hl->hl_list);
|
||||
up_write(&hl_drivers_sem);
|
||||
|
||||
nodemgr_for_each_host(hl, highlevel_for_each_host_unreg);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_allocate_and_register_addrspace - alloc' and reg' a host address space
|
||||
*
|
||||
* @start and @end are 48 bit pointers and have to be quadlet aligned.
|
||||
* @end points to the first address behind the handled addresses. This
|
||||
* function can be called multiple times for a single hpsb_highlevel @hl to
|
||||
* implement sparse register sets. The requested region must not overlap any
|
||||
* previously allocated region, otherwise registering will fail.
|
||||
*
|
||||
* It returns true for successful allocation. Address spaces can be
|
||||
* unregistered with hpsb_unregister_addrspace. All remaining address spaces
|
||||
* are automatically deallocated together with the hpsb_highlevel @hl.
|
||||
*/
|
||||
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
|
||||
struct hpsb_host *host,
|
||||
const struct hpsb_address_ops *ops,
|
||||
u64 size, u64 alignment,
|
||||
u64 start, u64 end)
|
||||
{
|
||||
struct hpsb_address_serve *as, *a1, *a2;
|
||||
struct list_head *entry;
|
||||
u64 retval = CSR1212_INVALID_ADDR_SPACE;
|
||||
unsigned long flags;
|
||||
u64 align_mask = ~(alignment - 1);
|
||||
|
||||
if ((alignment & 3) || (alignment > 0x800000000000ULL) ||
|
||||
(hweight64(alignment) != 1)) {
|
||||
HPSB_ERR("%s called with invalid alignment: 0x%048llx",
|
||||
__func__, (unsigned long long)alignment);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* default range,
|
||||
* avoids controller's posted write area (see OHCI 1.1 clause 1.5) */
|
||||
if (start == CSR1212_INVALID_ADDR_SPACE &&
|
||||
end == CSR1212_INVALID_ADDR_SPACE) {
|
||||
start = host->middle_addr_space;
|
||||
end = CSR1212_ALL_SPACE_END;
|
||||
}
|
||||
|
||||
if (((start|end) & ~align_mask) || (start >= end) ||
|
||||
(end > CSR1212_ALL_SPACE_END)) {
|
||||
HPSB_ERR("%s called with invalid addresses "
|
||||
"(start = %012Lx end = %012Lx)", __func__,
|
||||
(unsigned long long)start,(unsigned long long)end);
|
||||
return retval;
|
||||
}
|
||||
|
||||
as = kmalloc(sizeof(*as), GFP_KERNEL);
|
||||
if (!as)
|
||||
return retval;
|
||||
|
||||
INIT_LIST_HEAD(&as->host_list);
|
||||
INIT_LIST_HEAD(&as->hl_list);
|
||||
as->op = ops;
|
||||
as->host = host;
|
||||
|
||||
write_lock_irqsave(&addr_space_lock, flags);
|
||||
list_for_each(entry, &host->addr_space) {
|
||||
u64 a1sa, a1ea;
|
||||
u64 a2sa, a2ea;
|
||||
|
||||
a1 = list_entry(entry, struct hpsb_address_serve, host_list);
|
||||
a2 = list_entry(entry->next, struct hpsb_address_serve,
|
||||
host_list);
|
||||
|
||||
a1sa = a1->start & align_mask;
|
||||
a1ea = (a1->end + alignment -1) & align_mask;
|
||||
a2sa = a2->start & align_mask;
|
||||
a2ea = (a2->end + alignment -1) & align_mask;
|
||||
|
||||
if ((a2sa - a1ea >= size) && (a2sa - start >= size) &&
|
||||
(a2sa > start)) {
|
||||
as->start = max(start, a1ea);
|
||||
as->end = as->start + size;
|
||||
list_add(&as->host_list, entry);
|
||||
list_add_tail(&as->hl_list, &hl->addr_list);
|
||||
retval = as->start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_unlock_irqrestore(&addr_space_lock, flags);
|
||||
|
||||
if (retval == CSR1212_INVALID_ADDR_SPACE)
|
||||
kfree(as);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_register_addrspace - register a host address space
|
||||
*
|
||||
* @start and @end are 48 bit pointers and have to be quadlet aligned.
|
||||
* @end points to the first address behind the handled addresses. This
|
||||
* function can be called multiple times for a single hpsb_highlevel @hl to
|
||||
* implement sparse register sets. The requested region must not overlap any
|
||||
* previously allocated region, otherwise registering will fail.
|
||||
*
|
||||
* It returns true for successful allocation. Address spaces can be
|
||||
* unregistered with hpsb_unregister_addrspace. All remaining address spaces
|
||||
* are automatically deallocated together with the hpsb_highlevel @hl.
|
||||
*/
|
||||
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
const struct hpsb_address_ops *ops,
|
||||
u64 start, u64 end)
|
||||
{
|
||||
struct hpsb_address_serve *as;
|
||||
struct list_head *lh;
|
||||
int retval = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (((start|end) & 3) || (start >= end) ||
|
||||
(end > CSR1212_ALL_SPACE_END)) {
|
||||
HPSB_ERR("%s called with invalid addresses", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
as = kmalloc(sizeof(*as), GFP_KERNEL);
|
||||
if (!as)
|
||||
return 0;
|
||||
|
||||
INIT_LIST_HEAD(&as->host_list);
|
||||
INIT_LIST_HEAD(&as->hl_list);
|
||||
as->op = ops;
|
||||
as->start = start;
|
||||
as->end = end;
|
||||
as->host = host;
|
||||
|
||||
write_lock_irqsave(&addr_space_lock, flags);
|
||||
list_for_each(lh, &host->addr_space) {
|
||||
struct hpsb_address_serve *as_this =
|
||||
list_entry(lh, struct hpsb_address_serve, host_list);
|
||||
struct hpsb_address_serve *as_next =
|
||||
list_entry(lh->next, struct hpsb_address_serve,
|
||||
host_list);
|
||||
|
||||
if (as_this->end > as->start)
|
||||
break;
|
||||
|
||||
if (as_next->start >= as->end) {
|
||||
list_add(&as->host_list, lh);
|
||||
list_add_tail(&as->hl_list, &hl->addr_list);
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_unlock_irqrestore(&addr_space_lock, flags);
|
||||
|
||||
if (retval == 0)
|
||||
kfree(as);
|
||||
return retval;
|
||||
}
|
||||
|
||||
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
u64 start)
|
||||
{
|
||||
int retval = 0;
|
||||
struct hpsb_address_serve *as;
|
||||
struct list_head *lh, *next;
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&addr_space_lock, flags);
|
||||
list_for_each_safe (lh, next, &hl->addr_list) {
|
||||
as = list_entry(lh, struct hpsb_address_serve, hl_list);
|
||||
if (as->start == start && as->host == host) {
|
||||
__delete_addr(as);
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
write_unlock_irqrestore(&addr_space_lock, flags);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct hpsb_address_ops dummy_ops;
|
||||
|
||||
/* dummy address spaces as lower and upper bounds of the host's a.s. list */
|
||||
static void init_hpsb_highlevel(struct hpsb_host *host)
|
||||
{
|
||||
INIT_LIST_HEAD(&host->dummy_zero_addr.host_list);
|
||||
INIT_LIST_HEAD(&host->dummy_zero_addr.hl_list);
|
||||
INIT_LIST_HEAD(&host->dummy_max_addr.host_list);
|
||||
INIT_LIST_HEAD(&host->dummy_max_addr.hl_list);
|
||||
|
||||
host->dummy_zero_addr.op = host->dummy_max_addr.op = &dummy_ops;
|
||||
|
||||
host->dummy_zero_addr.start = host->dummy_zero_addr.end = 0;
|
||||
host->dummy_max_addr.start = host->dummy_max_addr.end = ((u64) 1) << 48;
|
||||
|
||||
list_add_tail(&host->dummy_zero_addr.host_list, &host->addr_space);
|
||||
list_add_tail(&host->dummy_max_addr.host_list, &host->addr_space);
|
||||
}
|
||||
|
||||
void highlevel_add_host(struct hpsb_host *host)
|
||||
{
|
||||
struct hpsb_highlevel *hl;
|
||||
|
||||
init_hpsb_highlevel(host);
|
||||
|
||||
down_read(&hl_drivers_sem);
|
||||
list_for_each_entry(hl, &hl_drivers, hl_list) {
|
||||
if (hl->add_host)
|
||||
hl->add_host(host);
|
||||
}
|
||||
up_read(&hl_drivers_sem);
|
||||
if (host->update_config_rom && hpsb_update_config_rom_image(host) < 0)
|
||||
HPSB_ERR("Failed to generate Configuration ROM image for host "
|
||||
"%s-%d", hl->name, host->id);
|
||||
}
|
||||
|
||||
void highlevel_remove_host(struct hpsb_host *host)
|
||||
{
|
||||
struct hpsb_highlevel *hl;
|
||||
|
||||
down_read(&hl_drivers_sem);
|
||||
list_for_each_entry(hl, &hl_drivers, hl_list)
|
||||
__unregister_host(hl, host, 0);
|
||||
up_read(&hl_drivers_sem);
|
||||
}
|
||||
|
||||
void highlevel_host_reset(struct hpsb_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct hpsb_highlevel *hl;
|
||||
|
||||
read_lock_irqsave(&hl_irqs_lock, flags);
|
||||
list_for_each_entry(hl, &hl_irqs, irq_list) {
|
||||
if (hl->host_reset)
|
||||
hl->host_reset(host);
|
||||
}
|
||||
read_unlock_irqrestore(&hl_irqs_lock, flags);
|
||||
}
|
||||
|
||||
void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
|
||||
void *data, size_t length)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct hpsb_highlevel *hl;
|
||||
int cts = ((quadlet_t *)data)[0] >> 4;
|
||||
|
||||
read_lock_irqsave(&hl_irqs_lock, flags);
|
||||
list_for_each_entry(hl, &hl_irqs, irq_list) {
|
||||
if (hl->fcp_request)
|
||||
hl->fcp_request(host, nodeid, direction, cts, data,
|
||||
length);
|
||||
}
|
||||
read_unlock_irqrestore(&hl_irqs_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* highlevel_read, highlevel_write, highlevel_lock, highlevel_lock64:
|
||||
*
|
||||
* These functions are called to handle transactions. They are called when a
|
||||
* packet arrives. The flags argument contains the second word of the first
|
||||
* header quadlet of the incoming packet (containing transaction label, retry
|
||||
* code, transaction code and priority). These functions either return a
|
||||
* response code or a negative number. In the first case a response will be
|
||||
* generated. In the latter case, no response will be sent and the driver which
|
||||
* handled the request will send the response itself.
|
||||
*/
|
||||
int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
|
||||
unsigned int length, u16 flags)
|
||||
{
|
||||
struct hpsb_address_serve *as;
|
||||
unsigned int partlength;
|
||||
int rcode = RCODE_ADDRESS_ERROR;
|
||||
|
||||
read_lock(&addr_space_lock);
|
||||
list_for_each_entry(as, &host->addr_space, host_list) {
|
||||
if (as->start > addr)
|
||||
break;
|
||||
|
||||
if (as->end > addr) {
|
||||
partlength = min(as->end - addr, (u64) length);
|
||||
|
||||
if (as->op->read)
|
||||
rcode = as->op->read(host, nodeid, data,
|
||||
addr, partlength, flags);
|
||||
else
|
||||
rcode = RCODE_TYPE_ERROR;
|
||||
|
||||
data += partlength;
|
||||
length -= partlength;
|
||||
addr += partlength;
|
||||
|
||||
if ((rcode != RCODE_COMPLETE) || !length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&addr_space_lock);
|
||||
|
||||
if (length && (rcode == RCODE_COMPLETE))
|
||||
rcode = RCODE_ADDRESS_ERROR;
|
||||
return rcode;
|
||||
}
|
||||
|
||||
int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
|
||||
u64 addr, unsigned int length, u16 flags)
|
||||
{
|
||||
struct hpsb_address_serve *as;
|
||||
unsigned int partlength;
|
||||
int rcode = RCODE_ADDRESS_ERROR;
|
||||
|
||||
read_lock(&addr_space_lock);
|
||||
list_for_each_entry(as, &host->addr_space, host_list) {
|
||||
if (as->start > addr)
|
||||
break;
|
||||
|
||||
if (as->end > addr) {
|
||||
partlength = min(as->end - addr, (u64) length);
|
||||
|
||||
if (as->op->write)
|
||||
rcode = as->op->write(host, nodeid, destid,
|
||||
data, addr, partlength,
|
||||
flags);
|
||||
else
|
||||
rcode = RCODE_TYPE_ERROR;
|
||||
|
||||
data += partlength;
|
||||
length -= partlength;
|
||||
addr += partlength;
|
||||
|
||||
if ((rcode != RCODE_COMPLETE) || !length)
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&addr_space_lock);
|
||||
|
||||
if (length && (rcode == RCODE_COMPLETE))
|
||||
rcode = RCODE_ADDRESS_ERROR;
|
||||
return rcode;
|
||||
}
|
||||
|
||||
int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
|
||||
u16 flags)
|
||||
{
|
||||
struct hpsb_address_serve *as;
|
||||
int rcode = RCODE_ADDRESS_ERROR;
|
||||
|
||||
read_lock(&addr_space_lock);
|
||||
list_for_each_entry(as, &host->addr_space, host_list) {
|
||||
if (as->start > addr)
|
||||
break;
|
||||
|
||||
if (as->end > addr) {
|
||||
if (as->op->lock)
|
||||
rcode = as->op->lock(host, nodeid, store, addr,
|
||||
data, arg, ext_tcode,
|
||||
flags);
|
||||
else
|
||||
rcode = RCODE_TYPE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&addr_space_lock);
|
||||
return rcode;
|
||||
}
|
||||
|
||||
int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
|
||||
u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
|
||||
u16 flags)
|
||||
{
|
||||
struct hpsb_address_serve *as;
|
||||
int rcode = RCODE_ADDRESS_ERROR;
|
||||
|
||||
read_lock(&addr_space_lock);
|
||||
|
||||
list_for_each_entry(as, &host->addr_space, host_list) {
|
||||
if (as->start > addr)
|
||||
break;
|
||||
|
||||
if (as->end > addr) {
|
||||
if (as->op->lock64)
|
||||
rcode = as->op->lock64(host, nodeid, store,
|
||||
addr, data, arg,
|
||||
ext_tcode, flags);
|
||||
else
|
||||
rcode = RCODE_TYPE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
read_unlock(&addr_space_lock);
|
||||
return rcode;
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
#ifndef IEEE1394_HIGHLEVEL_H
|
||||
#define IEEE1394_HIGHLEVEL_H
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct module;
|
||||
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
struct hpsb_host;
|
||||
|
||||
/* internal to ieee1394 core */
|
||||
struct hpsb_address_serve {
|
||||
struct list_head host_list; /* per host list */
|
||||
struct list_head hl_list; /* hpsb_highlevel list */
|
||||
const struct hpsb_address_ops *op;
|
||||
struct hpsb_host *host;
|
||||
u64 start; /* first address handled, quadlet aligned */
|
||||
u64 end; /* first address behind, quadlet aligned */
|
||||
};
|
||||
|
||||
/* Only the following structures are of interest to actual highlevel drivers. */
|
||||
|
||||
struct hpsb_highlevel {
|
||||
const char *name;
|
||||
|
||||
/* Any of the following pointers can legally be NULL. */
|
||||
|
||||
/* New host initialized. Will also be called during
|
||||
* hpsb_register_highlevel for all hosts already installed. */
|
||||
void (*add_host)(struct hpsb_host *host);
|
||||
|
||||
/* Host about to be removed. Will also be called during
|
||||
* hpsb_unregister_highlevel once for each host. */
|
||||
void (*remove_host)(struct hpsb_host *host);
|
||||
|
||||
/* Host experienced bus reset with possible configuration changes.
|
||||
* Note that this one may occur during interrupt/bottom half handling.
|
||||
* You can not expect to be able to do stock hpsb_reads. */
|
||||
void (*host_reset)(struct hpsb_host *host);
|
||||
|
||||
/* A write request was received on either the FCP_COMMAND (direction =
|
||||
* 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
|
||||
* contains the cts field (first byte of data). */
|
||||
void (*fcp_request)(struct hpsb_host *host, int nodeid, int direction,
|
||||
int cts, u8 *data, size_t length);
|
||||
|
||||
/* These are initialized by the subsystem when the
|
||||
* hpsb_higlevel is registered. */
|
||||
struct list_head hl_list;
|
||||
struct list_head irq_list;
|
||||
struct list_head addr_list;
|
||||
|
||||
struct list_head host_info_list;
|
||||
rwlock_t host_info_lock;
|
||||
};
|
||||
|
||||
struct hpsb_address_ops {
|
||||
/*
|
||||
* Null function pointers will make the respective operation complete
|
||||
* with RCODE_TYPE_ERROR. Makes for easy to implement read-only
|
||||
* registers (just leave everything but read NULL).
|
||||
*
|
||||
* All functions shall return appropriate IEEE 1394 rcodes.
|
||||
*/
|
||||
|
||||
/* These functions have to implement block reads for themselves.
|
||||
*
|
||||
* These functions either return a response code or a negative number.
|
||||
* In the first case a response will be generated. In the latter case,
|
||||
* no response will be sent and the driver which handled the request
|
||||
* will send the response itself. */
|
||||
int (*read)(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
|
||||
u64 addr, size_t length, u16 flags);
|
||||
int (*write)(struct hpsb_host *host, int nodeid, int destid,
|
||||
quadlet_t *data, u64 addr, size_t length, u16 flags);
|
||||
|
||||
/* Lock transactions: write results of ext_tcode operation into
|
||||
* *store. */
|
||||
int (*lock)(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
|
||||
u16 flags);
|
||||
int (*lock64)(struct hpsb_host *host, int nodeid, octlet_t *store,
|
||||
u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
|
||||
u16 flags);
|
||||
};
|
||||
|
||||
void highlevel_add_host(struct hpsb_host *host);
|
||||
void highlevel_remove_host(struct hpsb_host *host);
|
||||
void highlevel_host_reset(struct hpsb_host *host);
|
||||
int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
|
||||
unsigned int length, u16 flags);
|
||||
int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
|
||||
u64 addr, unsigned int length, u16 flags);
|
||||
int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
|
||||
u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
|
||||
u16 flags);
|
||||
int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
|
||||
u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
|
||||
u16 flags);
|
||||
void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
|
||||
void *data, size_t length);
|
||||
|
||||
/**
|
||||
* hpsb_init_highlevel - initialize a struct hpsb_highlevel
|
||||
*
|
||||
* This is only necessary if hpsb_get_hostinfo_bykey can be called
|
||||
* before hpsb_register_highlevel.
|
||||
*/
|
||||
static inline void hpsb_init_highlevel(struct hpsb_highlevel *hl)
|
||||
{
|
||||
rwlock_init(&hl->host_info_lock);
|
||||
INIT_LIST_HEAD(&hl->host_info_list);
|
||||
}
|
||||
void hpsb_register_highlevel(struct hpsb_highlevel *hl);
|
||||
void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
|
||||
|
||||
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
|
||||
struct hpsb_host *host,
|
||||
const struct hpsb_address_ops *ops,
|
||||
u64 size, u64 alignment,
|
||||
u64 start, u64 end);
|
||||
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
const struct hpsb_address_ops *ops,
|
||||
u64 start, u64 end);
|
||||
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
u64 start);
|
||||
|
||||
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
|
||||
void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
size_t data_size);
|
||||
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
|
||||
void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
unsigned long key);
|
||||
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
|
||||
int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
|
||||
void *data);
|
||||
|
||||
#endif /* IEEE1394_HIGHLEVEL_H */
|
|
@ -1,249 +0,0 @@
|
|||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* Low level (host adapter) management.
|
||||
*
|
||||
* Copyright (C) 1999 Andreas E. Bombe
|
||||
* Copyright (C) 1999 Emanuel Pirker
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "csr1212.h"
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_types.h"
|
||||
#include "hosts.h"
|
||||
#include "ieee1394_core.h"
|
||||
#include "highlevel.h"
|
||||
#include "nodemgr.h"
|
||||
#include "csr.h"
|
||||
#include "config_roms.h"
|
||||
|
||||
|
||||
static void delayed_reset_bus(struct work_struct *work)
|
||||
{
|
||||
struct hpsb_host *host =
|
||||
container_of(work, struct hpsb_host, delayed_reset.work);
|
||||
u8 generation = host->csr.generation + 1;
|
||||
|
||||
/* The generation field rolls over to 2 rather than 0 per IEEE
|
||||
* 1394a-2000. */
|
||||
if (generation > 0xf || generation < 2)
|
||||
generation = 2;
|
||||
|
||||
csr_set_bus_info_generation(host->csr.rom, generation);
|
||||
if (csr1212_generate_csr_image(host->csr.rom) != CSR1212_SUCCESS) {
|
||||
/* CSR image creation failed.
|
||||
* Reset generation field and do not issue a bus reset. */
|
||||
csr_set_bus_info_generation(host->csr.rom,
|
||||
host->csr.generation);
|
||||
return;
|
||||
}
|
||||
|
||||
host->csr.generation = generation;
|
||||
|
||||
host->update_config_rom = 0;
|
||||
if (host->driver->set_hw_config_rom)
|
||||
host->driver->set_hw_config_rom(host,
|
||||
host->csr.rom->bus_info_data);
|
||||
|
||||
host->csr.gen_timestamp[host->csr.generation] = jiffies;
|
||||
hpsb_reset_bus(host, SHORT_RESET);
|
||||
}
|
||||
|
||||
static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dummy_isoctl(struct hpsb_iso *iso, enum isoctl_cmd command,
|
||||
unsigned long arg)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct hpsb_host_driver dummy_driver = {
|
||||
.transmit_packet = dummy_transmit_packet,
|
||||
.devctl = dummy_devctl,
|
||||
.isoctl = dummy_isoctl
|
||||
};
|
||||
|
||||
static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
|
||||
{
|
||||
int *hostnum = __data;
|
||||
|
||||
if (host->id == *hostnum)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(host_num_alloc);
|
||||
|
||||
/**
|
||||
* 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().
|
||||
*
|
||||
* Return Value: a pointer to the &hpsb_host if successful, %NULL if
|
||||
* no memory was available.
|
||||
*/
|
||||
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
|
||||
struct device *dev)
|
||||
{
|
||||
struct hpsb_host *h;
|
||||
int i;
|
||||
int hostnum = 0;
|
||||
|
||||
h = kzalloc(sizeof(*h) + extra, GFP_KERNEL);
|
||||
if (!h)
|
||||
return NULL;
|
||||
|
||||
h->csr.rom = csr1212_create_csr(&csr_bus_ops, CSR_BUS_INFO_SIZE, h);
|
||||
if (!h->csr.rom)
|
||||
goto fail;
|
||||
|
||||
h->hostdata = h + 1;
|
||||
h->driver = drv;
|
||||
|
||||
INIT_LIST_HEAD(&h->pending_packets);
|
||||
INIT_LIST_HEAD(&h->addr_space);
|
||||
|
||||
for (i = 2; i < 16; i++)
|
||||
h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
|
||||
|
||||
atomic_set(&h->generation, 0);
|
||||
|
||||
INIT_DELAYED_WORK(&h->delayed_reset, delayed_reset_bus);
|
||||
|
||||
init_timer(&h->timeout);
|
||||
h->timeout.data = (unsigned long) h;
|
||||
h->timeout.function = abort_timedouts;
|
||||
h->timeout_interval = HZ / 20; /* 50ms, half of minimum SPLIT_TIMEOUT */
|
||||
|
||||
h->topology_map = h->csr.topology_map + 3;
|
||||
h->speed_map = (u8 *)(h->csr.speed_map + 2);
|
||||
|
||||
mutex_lock(&host_num_alloc);
|
||||
while (nodemgr_for_each_host(&hostnum, alloc_hostnum_cb))
|
||||
hostnum++;
|
||||
mutex_unlock(&host_num_alloc);
|
||||
h->id = hostnum;
|
||||
|
||||
memcpy(&h->device, &nodemgr_dev_template_host, sizeof(h->device));
|
||||
h->device.parent = dev;
|
||||
set_dev_node(&h->device, dev_to_node(dev));
|
||||
dev_set_name(&h->device, "fw-host%d", h->id);
|
||||
|
||||
h->host_dev.parent = &h->device;
|
||||
h->host_dev.class = &hpsb_host_class;
|
||||
dev_set_name(&h->host_dev, "fw-host%d", h->id);
|
||||
|
||||
if (device_register(&h->device))
|
||||
goto fail;
|
||||
if (device_register(&h->host_dev)) {
|
||||
device_unregister(&h->device);
|
||||
goto fail;
|
||||
}
|
||||
get_device(&h->device);
|
||||
|
||||
return h;
|
||||
|
||||
fail:
|
||||
kfree(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hpsb_add_host(struct hpsb_host *host)
|
||||
{
|
||||
if (hpsb_default_host_entry(host))
|
||||
return -ENOMEM;
|
||||
|
||||
highlevel_add_host(host);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hpsb_resume_host(struct hpsb_host *host)
|
||||
{
|
||||
if (host->driver->set_hw_config_rom)
|
||||
host->driver->set_hw_config_rom(host,
|
||||
host->csr.rom->bus_info_data);
|
||||
host->driver->devctl(host, RESET_BUS, SHORT_RESET);
|
||||
}
|
||||
|
||||
void hpsb_remove_host(struct hpsb_host *host)
|
||||
{
|
||||
host->is_shutdown = 1;
|
||||
|
||||
cancel_delayed_work(&host->delayed_reset);
|
||||
flush_scheduled_work();
|
||||
|
||||
host->driver = &dummy_driver;
|
||||
highlevel_remove_host(host);
|
||||
|
||||
device_unregister(&host->host_dev);
|
||||
device_unregister(&host->device);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_update_config_rom_image - updates configuration ROM image of a host
|
||||
*
|
||||
* Updates the configuration ROM image of a host. rom_version must be the
|
||||
* current version, otherwise it will fail with return value -1. If this
|
||||
* host does not support config-rom-update, it will return -%EINVAL.
|
||||
* Return value 0 indicates success.
|
||||
*/
|
||||
int hpsb_update_config_rom_image(struct hpsb_host *host)
|
||||
{
|
||||
unsigned long reset_delay;
|
||||
int next_gen = host->csr.generation + 1;
|
||||
|
||||
if (!host->update_config_rom)
|
||||
return -EINVAL;
|
||||
|
||||
if (next_gen > 0xf)
|
||||
next_gen = 2;
|
||||
|
||||
/* Stop the delayed interrupt, we're about to change the config rom and
|
||||
* it would be a waste to do a bus reset twice. */
|
||||
cancel_delayed_work(&host->delayed_reset);
|
||||
|
||||
/* IEEE 1394a-2000 prohibits using the same generation number
|
||||
* twice in a 60 second period. */
|
||||
if (time_before(jiffies, host->csr.gen_timestamp[next_gen] + 60 * HZ))
|
||||
/* Wait 60 seconds from the last time this generation number was
|
||||
* used. */
|
||||
reset_delay =
|
||||
(60 * HZ) + host->csr.gen_timestamp[next_gen] - jiffies;
|
||||
else
|
||||
/* Wait 1 second in case some other code wants to change the
|
||||
* Config ROM in the near future. */
|
||||
reset_delay = HZ;
|
||||
|
||||
PREPARE_DELAYED_WORK(&host->delayed_reset, delayed_reset_bus);
|
||||
schedule_delayed_work(&host->delayed_reset, reset_delay);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,201 +0,0 @@
|
|||
#ifndef _IEEE1394_HOSTS_H
|
||||
#define _IEEE1394_HOSTS_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
struct pci_dev;
|
||||
struct module;
|
||||
|
||||
#include "ieee1394_types.h"
|
||||
#include "csr.h"
|
||||
#include "highlevel.h"
|
||||
|
||||
struct hpsb_packet;
|
||||
struct hpsb_iso;
|
||||
|
||||
struct hpsb_host {
|
||||
struct list_head host_list;
|
||||
|
||||
void *hostdata;
|
||||
|
||||
atomic_t generation;
|
||||
|
||||
struct list_head pending_packets;
|
||||
struct timer_list timeout;
|
||||
unsigned long timeout_interval;
|
||||
|
||||
int node_count; /* number of identified nodes on this bus */
|
||||
int selfid_count; /* total number of SelfIDs received */
|
||||
int nodes_active; /* number of nodes with active link layer */
|
||||
|
||||
nodeid_t node_id; /* node ID of this host */
|
||||
nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
|
||||
nodeid_t busmgr_id; /* ID of this bus' bus manager */
|
||||
|
||||
/* this nodes state */
|
||||
unsigned in_bus_reset:1;
|
||||
unsigned is_shutdown:1;
|
||||
unsigned resume_packet_sent:1;
|
||||
|
||||
/* this nodes' duties on the bus */
|
||||
unsigned is_root:1;
|
||||
unsigned is_cycmst:1;
|
||||
unsigned is_irm:1;
|
||||
unsigned is_busmgr:1;
|
||||
|
||||
int reset_retries;
|
||||
quadlet_t *topology_map;
|
||||
u8 *speed_map;
|
||||
|
||||
int id;
|
||||
struct hpsb_host_driver *driver;
|
||||
struct pci_dev *pdev;
|
||||
struct device device;
|
||||
struct device host_dev;
|
||||
|
||||
struct delayed_work delayed_reset;
|
||||
unsigned config_roms:31;
|
||||
unsigned update_config_rom:1;
|
||||
|
||||
struct list_head addr_space;
|
||||
u64 low_addr_space; /* upper bound of physical DMA area */
|
||||
u64 middle_addr_space; /* upper bound of posted write area */
|
||||
|
||||
u8 speed[ALL_NODES]; /* speed between each node and local node */
|
||||
|
||||
/* per node tlabel allocation */
|
||||
u8 next_tl[ALL_NODES];
|
||||
struct { DECLARE_BITMAP(map, 64); } tl_pool[ALL_NODES];
|
||||
|
||||
struct csr_control csr;
|
||||
|
||||
struct hpsb_address_serve dummy_zero_addr;
|
||||
struct hpsb_address_serve dummy_max_addr;
|
||||
};
|
||||
|
||||
enum devctl_cmd {
|
||||
/* Host is requested to reset its bus and cancel all outstanding async
|
||||
* requests. If arg == 1, it shall also attempt to become root on the
|
||||
* bus. Return void. */
|
||||
RESET_BUS,
|
||||
|
||||
/* Arg is void, return value is the hardware cycle counter value. */
|
||||
GET_CYCLE_COUNTER,
|
||||
|
||||
/* Set the hardware cycle counter to the value in arg, return void.
|
||||
* FIXME - setting is probably not required. */
|
||||
SET_CYCLE_COUNTER,
|
||||
|
||||
/* Configure hardware for new bus ID in arg, return void. */
|
||||
SET_BUS_ID,
|
||||
|
||||
/* If arg true, start sending cycle start packets, stop if arg == 0.
|
||||
* Return void. */
|
||||
ACT_CYCLE_MASTER,
|
||||
|
||||
/* Cancel all outstanding async requests without resetting the bus.
|
||||
* Return void. */
|
||||
CANCEL_REQUESTS,
|
||||
};
|
||||
|
||||
enum isoctl_cmd {
|
||||
/* rawiso API - see iso.h for the meanings of these commands
|
||||
* (they correspond exactly to the hpsb_iso_* API functions)
|
||||
* INIT = allocate resources
|
||||
* START = begin transmission/reception
|
||||
* STOP = halt transmission/reception
|
||||
* QUEUE/RELEASE = produce/consume packets
|
||||
* SHUTDOWN = deallocate resources
|
||||
*/
|
||||
|
||||
XMIT_INIT,
|
||||
XMIT_START,
|
||||
XMIT_STOP,
|
||||
XMIT_QUEUE,
|
||||
XMIT_SHUTDOWN,
|
||||
|
||||
RECV_INIT,
|
||||
RECV_LISTEN_CHANNEL, /* multi-channel only */
|
||||
RECV_UNLISTEN_CHANNEL, /* multi-channel only */
|
||||
RECV_SET_CHANNEL_MASK, /* multi-channel only; arg is a *u64 */
|
||||
RECV_START,
|
||||
RECV_STOP,
|
||||
RECV_RELEASE,
|
||||
RECV_SHUTDOWN,
|
||||
RECV_FLUSH
|
||||
};
|
||||
|
||||
enum reset_types {
|
||||
/* 166 microsecond reset -- only type of reset available on
|
||||
non-1394a capable controllers */
|
||||
LONG_RESET,
|
||||
|
||||
/* Short (arbitrated) reset -- only available on 1394a capable
|
||||
controllers */
|
||||
SHORT_RESET,
|
||||
|
||||
/* Variants that set force_root before issueing the bus reset */
|
||||
LONG_RESET_FORCE_ROOT, SHORT_RESET_FORCE_ROOT,
|
||||
|
||||
/* Variants that clear force_root before issueing the bus reset */
|
||||
LONG_RESET_NO_FORCE_ROOT, SHORT_RESET_NO_FORCE_ROOT
|
||||
};
|
||||
|
||||
struct hpsb_host_driver {
|
||||
struct module *owner;
|
||||
const char *name;
|
||||
|
||||
/* The hardware driver may optionally support a function that is used
|
||||
* to set the hardware ConfigROM if the hardware supports handling
|
||||
* reads to the ConfigROM on its own. */
|
||||
void (*set_hw_config_rom)(struct hpsb_host *host,
|
||||
__be32 *config_rom);
|
||||
|
||||
/* This function shall implement packet transmission based on
|
||||
* packet->type. It shall CRC both parts of the packet (unless
|
||||
* packet->type == raw) and do byte-swapping as necessary or instruct
|
||||
* the hardware to do so. It can return immediately after the packet
|
||||
* was queued for sending. After sending, hpsb_sent_packet() has to be
|
||||
* called. Return 0 on success, negative errno on failure.
|
||||
* NOTE: The function must be callable in interrupt context.
|
||||
*/
|
||||
int (*transmit_packet)(struct hpsb_host *host,
|
||||
struct hpsb_packet *packet);
|
||||
|
||||
/* This function requests miscellanous services from the driver, see
|
||||
* above for command codes and expected actions. Return -1 for unknown
|
||||
* command, though that should never happen.
|
||||
*/
|
||||
int (*devctl)(struct hpsb_host *host, enum devctl_cmd command, int arg);
|
||||
|
||||
/* ISO transmission/reception functions. Return 0 on success, -1
|
||||
* (or -EXXX errno code) on failure. If the low-level driver does not
|
||||
* support the new ISO API, set isoctl to NULL.
|
||||
*/
|
||||
int (*isoctl)(struct hpsb_iso *iso, enum isoctl_cmd command,
|
||||
unsigned long arg);
|
||||
|
||||
/* This function is mainly to redirect local CSR reads/locks to the iso
|
||||
* management registers (bus manager id, bandwidth available, channels
|
||||
* available) to the hardware registers in OHCI. reg is 0,1,2,3 for bus
|
||||
* mgr, bwdth avail, ch avail hi, ch avail lo respectively (the same ids
|
||||
* as OHCI uses). data and compare are the new data and expected data
|
||||
* respectively, return value is the old value.
|
||||
*/
|
||||
quadlet_t (*hw_csr_reg) (struct hpsb_host *host, int reg,
|
||||
quadlet_t data, quadlet_t compare);
|
||||
};
|
||||
|
||||
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
|
||||
struct device *dev);
|
||||
int hpsb_add_host(struct hpsb_host *host);
|
||||
void hpsb_resume_host(struct hpsb_host *host);
|
||||
void hpsb_remove_host(struct hpsb_host *host);
|
||||
int hpsb_update_config_rom_image(struct hpsb_host *host);
|
||||
|
||||
#endif /* _IEEE1394_HOSTS_H */
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* Base file for all ieee1394 ioctl's.
|
||||
* Linux-1394 has allocated base '#' with a range of 0x00-0x3f.
|
||||
*/
|
||||
|
||||
#ifndef __IEEE1394_IOCTL_H
|
||||
#define __IEEE1394_IOCTL_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* DV1394 Gets 10 */
|
||||
|
||||
/* Get the driver ready to transmit video. pass a struct dv1394_init* as
|
||||
* the parameter (see below), or NULL to get default parameters */
|
||||
#define DV1394_IOC_INIT _IOW('#', 0x06, struct dv1394_init)
|
||||
|
||||
/* Stop transmitting video and free the ringbuffer */
|
||||
#define DV1394_IOC_SHUTDOWN _IO ('#', 0x07)
|
||||
|
||||
/* Submit N new frames to be transmitted, where the index of the first new
|
||||
* frame is first_clear_buffer, and the index of the last new frame is
|
||||
* (first_clear_buffer + N) % n_frames */
|
||||
#define DV1394_IOC_SUBMIT_FRAMES _IO ('#', 0x08)
|
||||
|
||||
/* Block until N buffers are clear (pass N as the parameter) Because we
|
||||
* re-transmit the last frame on underrun, there will at most be n_frames
|
||||
* - 1 clear frames at any time */
|
||||
#define DV1394_IOC_WAIT_FRAMES _IO ('#', 0x09)
|
||||
|
||||
/* Capture new frames that have been received, where the index of the
|
||||
* first new frame is first_clear_buffer, and the index of the last new
|
||||
* frame is (first_clear_buffer + N) % n_frames */
|
||||
#define DV1394_IOC_RECEIVE_FRAMES _IO ('#', 0x0a)
|
||||
|
||||
/* Tell card to start receiving DMA */
|
||||
#define DV1394_IOC_START_RECEIVE _IO ('#', 0x0b)
|
||||
|
||||
/* Pass a struct dv1394_status* as the parameter */
|
||||
#define DV1394_IOC_GET_STATUS _IOR('#', 0x0c, struct dv1394_status)
|
||||
|
||||
|
||||
/* Video1394 Gets 10 */
|
||||
|
||||
#define VIDEO1394_IOC_LISTEN_CHANNEL \
|
||||
_IOWR('#', 0x10, struct video1394_mmap)
|
||||
#define VIDEO1394_IOC_UNLISTEN_CHANNEL \
|
||||
_IOW ('#', 0x11, int)
|
||||
#define VIDEO1394_IOC_LISTEN_QUEUE_BUFFER \
|
||||
_IOW ('#', 0x12, struct video1394_wait)
|
||||
#define VIDEO1394_IOC_LISTEN_WAIT_BUFFER \
|
||||
_IOWR('#', 0x13, struct video1394_wait)
|
||||
#define VIDEO1394_IOC_TALK_CHANNEL \
|
||||
_IOWR('#', 0x14, struct video1394_mmap)
|
||||
#define VIDEO1394_IOC_UNTALK_CHANNEL \
|
||||
_IOW ('#', 0x15, int)
|
||||
/*
|
||||
* This one is broken: it really wanted
|
||||
* "sizeof (struct video1394_wait) + sizeof (struct video1394_queue_variable)"
|
||||
* but got just a "size_t"
|
||||
*/
|
||||
#define VIDEO1394_IOC_TALK_QUEUE_BUFFER \
|
||||
_IOW ('#', 0x16, size_t)
|
||||
#define VIDEO1394_IOC_TALK_WAIT_BUFFER \
|
||||
_IOW ('#', 0x17, struct video1394_wait)
|
||||
#define VIDEO1394_IOC_LISTEN_POLL_BUFFER \
|
||||
_IOWR('#', 0x18, struct video1394_wait)
|
||||
|
||||
|
||||
/* Raw1394's ISO interface */
|
||||
#define RAW1394_IOC_ISO_XMIT_INIT \
|
||||
_IOW ('#', 0x1a, struct raw1394_iso_status)
|
||||
#define RAW1394_IOC_ISO_RECV_INIT \
|
||||
_IOWR('#', 0x1b, struct raw1394_iso_status)
|
||||
#define RAW1394_IOC_ISO_RECV_START \
|
||||
_IOC (_IOC_WRITE, '#', 0x1c, sizeof(int) * 3)
|
||||
#define RAW1394_IOC_ISO_XMIT_START \
|
||||
_IOC (_IOC_WRITE, '#', 0x1d, sizeof(int) * 2)
|
||||
#define RAW1394_IOC_ISO_XMIT_RECV_STOP \
|
||||
_IO ('#', 0x1e)
|
||||
#define RAW1394_IOC_ISO_GET_STATUS \
|
||||
_IOR ('#', 0x1f, struct raw1394_iso_status)
|
||||
#define RAW1394_IOC_ISO_SHUTDOWN \
|
||||
_IO ('#', 0x20)
|
||||
#define RAW1394_IOC_ISO_QUEUE_ACTIVITY \
|
||||
_IO ('#', 0x21)
|
||||
#define RAW1394_IOC_ISO_RECV_LISTEN_CHANNEL \
|
||||
_IOW ('#', 0x22, unsigned char)
|
||||
#define RAW1394_IOC_ISO_RECV_UNLISTEN_CHANNEL \
|
||||
_IOW ('#', 0x23, unsigned char)
|
||||
#define RAW1394_IOC_ISO_RECV_SET_CHANNEL_MASK \
|
||||
_IOW ('#', 0x24, __u64)
|
||||
#define RAW1394_IOC_ISO_RECV_PACKETS \
|
||||
_IOW ('#', 0x25, struct raw1394_iso_packets)
|
||||
#define RAW1394_IOC_ISO_RECV_RELEASE_PACKETS \
|
||||
_IOW ('#', 0x26, unsigned int)
|
||||
#define RAW1394_IOC_ISO_XMIT_PACKETS \
|
||||
_IOW ('#', 0x27, struct raw1394_iso_packets)
|
||||
#define RAW1394_IOC_ISO_XMIT_SYNC \
|
||||
_IO ('#', 0x28)
|
||||
#define RAW1394_IOC_ISO_RECV_FLUSH \
|
||||
_IO ('#', 0x29)
|
||||
#define RAW1394_IOC_GET_CYCLE_TIMER \
|
||||
_IOR ('#', 0x30, struct raw1394_cycle_timer)
|
||||
|
||||
#endif /* __IEEE1394_IOCTL_H */
|
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
* Generic IEEE 1394 definitions
|
||||
*/
|
||||
|
||||
#ifndef _IEEE1394_IEEE1394_H
|
||||
#define _IEEE1394_IEEE1394_H
|
||||
|
||||
#define TCODE_WRITEQ 0x0
|
||||
#define TCODE_WRITEB 0x1
|
||||
#define TCODE_WRITE_RESPONSE 0x2
|
||||
#define TCODE_READQ 0x4
|
||||
#define TCODE_READB 0x5
|
||||
#define TCODE_READQ_RESPONSE 0x6
|
||||
#define TCODE_READB_RESPONSE 0x7
|
||||
#define TCODE_CYCLE_START 0x8
|
||||
#define TCODE_LOCK_REQUEST 0x9
|
||||
#define TCODE_ISO_DATA 0xa
|
||||
#define TCODE_STREAM_DATA 0xa
|
||||
#define TCODE_LOCK_RESPONSE 0xb
|
||||
|
||||
#define RCODE_COMPLETE 0x0
|
||||
#define RCODE_CONFLICT_ERROR 0x4
|
||||
#define RCODE_DATA_ERROR 0x5
|
||||
#define RCODE_TYPE_ERROR 0x6
|
||||
#define RCODE_ADDRESS_ERROR 0x7
|
||||
|
||||
#define EXTCODE_MASK_SWAP 0x1
|
||||
#define EXTCODE_COMPARE_SWAP 0x2
|
||||
#define EXTCODE_FETCH_ADD 0x3
|
||||
#define EXTCODE_LITTLE_ADD 0x4
|
||||
#define EXTCODE_BOUNDED_ADD 0x5
|
||||
#define EXTCODE_WRAP_ADD 0x6
|
||||
|
||||
#define ACK_COMPLETE 0x1
|
||||
#define ACK_PENDING 0x2
|
||||
#define ACK_BUSY_X 0x4
|
||||
#define ACK_BUSY_A 0x5
|
||||
#define ACK_BUSY_B 0x6
|
||||
#define ACK_TARDY 0xb
|
||||
#define ACK_CONFLICT_ERROR 0xc
|
||||
#define ACK_DATA_ERROR 0xd
|
||||
#define ACK_TYPE_ERROR 0xe
|
||||
#define ACK_ADDRESS_ERROR 0xf
|
||||
|
||||
/* Non-standard "ACK codes" for internal use */
|
||||
#define ACKX_NONE (-1)
|
||||
#define ACKX_SEND_ERROR (-2)
|
||||
#define ACKX_ABORTED (-3)
|
||||
#define ACKX_TIMEOUT (-4)
|
||||
|
||||
#define IEEE1394_SPEED_100 0x00
|
||||
#define IEEE1394_SPEED_200 0x01
|
||||
#define IEEE1394_SPEED_400 0x02
|
||||
#define IEEE1394_SPEED_800 0x03
|
||||
#define IEEE1394_SPEED_1600 0x04
|
||||
#define IEEE1394_SPEED_3200 0x05
|
||||
#define IEEE1394_SPEED_MAX IEEE1394_SPEED_3200
|
||||
|
||||
/* Maps speed values above to a string representation */
|
||||
extern const char *hpsb_speedto_str[];
|
||||
|
||||
/* 1394a cable PHY packets */
|
||||
#define SELFID_PWRCL_NO_POWER 0x0
|
||||
#define SELFID_PWRCL_PROVIDE_15W 0x1
|
||||
#define SELFID_PWRCL_PROVIDE_30W 0x2
|
||||
#define SELFID_PWRCL_PROVIDE_45W 0x3
|
||||
#define SELFID_PWRCL_USE_1W 0x4
|
||||
#define SELFID_PWRCL_USE_3W 0x5
|
||||
#define SELFID_PWRCL_USE_6W 0x6
|
||||
#define SELFID_PWRCL_USE_10W 0x7
|
||||
|
||||
#define SELFID_PORT_CHILD 0x3
|
||||
#define SELFID_PORT_PARENT 0x2
|
||||
#define SELFID_PORT_NCONN 0x1
|
||||
#define SELFID_PORT_NONE 0x0
|
||||
|
||||
#define SELFID_SPEED_UNKNOWN 0x3 /* 1394b PHY */
|
||||
|
||||
#define PHYPACKET_LINKON 0x40000000
|
||||
#define PHYPACKET_PHYCONFIG_R 0x00800000
|
||||
#define PHYPACKET_PHYCONFIG_T 0x00400000
|
||||
#define EXTPHYPACKET_TYPE_PING 0x00000000
|
||||
#define EXTPHYPACKET_TYPE_REMOTEACCESS_BASE 0x00040000
|
||||
#define EXTPHYPACKET_TYPE_REMOTEACCESS_PAGED 0x00140000
|
||||
#define EXTPHYPACKET_TYPE_REMOTEREPLY_BASE 0x000C0000
|
||||
#define EXTPHYPACKET_TYPE_REMOTEREPLY_PAGED 0x001C0000
|
||||
#define EXTPHYPACKET_TYPE_REMOTECOMMAND 0x00200000
|
||||
#define EXTPHYPACKET_TYPE_REMOTECONFIRMATION 0x00280000
|
||||
#define EXTPHYPACKET_TYPE_RESUME 0x003C0000
|
||||
|
||||
#define EXTPHYPACKET_TYPEMASK 0xC0FC0000
|
||||
|
||||
#define PHYPACKET_PORT_SHIFT 24
|
||||
#define PHYPACKET_GAPCOUNT_SHIFT 16
|
||||
|
||||
/* 1394a PHY register map bitmasks */
|
||||
#define PHY_00_PHYSICAL_ID 0xFC
|
||||
#define PHY_00_R 0x02 /* Root */
|
||||
#define PHY_00_PS 0x01 /* Power Status*/
|
||||
#define PHY_01_RHB 0x80 /* Root Hold-Off */
|
||||
#define PHY_01_IBR 0x80 /* Initiate Bus Reset */
|
||||
#define PHY_01_GAP_COUNT 0x3F
|
||||
#define PHY_02_EXTENDED 0xE0 /* 0x7 for 1394a-compliant PHY */
|
||||
#define PHY_02_TOTAL_PORTS 0x1F
|
||||
#define PHY_03_MAX_SPEED 0xE0
|
||||
#define PHY_03_DELAY 0x0F
|
||||
#define PHY_04_LCTRL 0x80 /* Link Active Report Control */
|
||||
#define PHY_04_CONTENDER 0x40
|
||||
#define PHY_04_JITTER 0x38
|
||||
#define PHY_04_PWR_CLASS 0x07 /* Power Class */
|
||||
#define PHY_05_WATCHDOG 0x80
|
||||
#define PHY_05_ISBR 0x40 /* Initiate Short Bus Reset */
|
||||
#define PHY_05_LOOP 0x20 /* Loop Detect */
|
||||
#define PHY_05_PWR_FAIL 0x10 /* Cable Power Failure Detect */
|
||||
#define PHY_05_TIMEOUT 0x08 /* Arbitration State Machine Timeout */
|
||||
#define PHY_05_PORT_EVENT 0x04 /* Port Event Detect */
|
||||
#define PHY_05_ENAB_ACCEL 0x02 /* Enable Arbitration Acceleration */
|
||||
#define PHY_05_ENAB_MULTI 0x01 /* Ena. Multispeed Packet Concatenation */
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/* '1' '3' '9' '4' in ASCII */
|
||||
#define IEEE1394_BUSID_MAGIC cpu_to_be32(0x31333934)
|
||||
|
||||
#ifdef __BIG_ENDIAN_BITFIELD
|
||||
|
||||
struct selfid {
|
||||
u32 packet_identifier:2; /* always binary 10 */
|
||||
u32 phy_id:6;
|
||||
/* byte */
|
||||
u32 extended:1; /* if true is struct ext_selfid */
|
||||
u32 link_active:1;
|
||||
u32 gap_count:6;
|
||||
/* byte */
|
||||
u32 speed:2;
|
||||
u32 phy_delay:2;
|
||||
u32 contender:1;
|
||||
u32 power_class:3;
|
||||
/* byte */
|
||||
u32 port0:2;
|
||||
u32 port1:2;
|
||||
u32 port2:2;
|
||||
u32 initiated_reset:1;
|
||||
u32 more_packets:1;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ext_selfid {
|
||||
u32 packet_identifier:2; /* always binary 10 */
|
||||
u32 phy_id:6;
|
||||
/* byte */
|
||||
u32 extended:1; /* if false is struct selfid */
|
||||
u32 seq_nr:3;
|
||||
u32 reserved:2;
|
||||
u32 porta:2;
|
||||
/* byte */
|
||||
u32 portb:2;
|
||||
u32 portc:2;
|
||||
u32 portd:2;
|
||||
u32 porte:2;
|
||||
/* byte */
|
||||
u32 portf:2;
|
||||
u32 portg:2;
|
||||
u32 porth:2;
|
||||
u32 reserved2:1;
|
||||
u32 more_packets:1;
|
||||
} __attribute__((packed));
|
||||
|
||||
#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
|
||||
|
||||
/*
|
||||
* Note: these mean to be bit fields of a big endian SelfID as seen on a little
|
||||
* endian machine. Without swapping.
|
||||
*/
|
||||
|
||||
struct selfid {
|
||||
u32 phy_id:6;
|
||||
u32 packet_identifier:2; /* always binary 10 */
|
||||
/* byte */
|
||||
u32 gap_count:6;
|
||||
u32 link_active:1;
|
||||
u32 extended:1; /* if true is struct ext_selfid */
|
||||
/* byte */
|
||||
u32 power_class:3;
|
||||
u32 contender:1;
|
||||
u32 phy_delay:2;
|
||||
u32 speed:2;
|
||||
/* byte */
|
||||
u32 more_packets:1;
|
||||
u32 initiated_reset:1;
|
||||
u32 port2:2;
|
||||
u32 port1:2;
|
||||
u32 port0:2;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct ext_selfid {
|
||||
u32 phy_id:6;
|
||||
u32 packet_identifier:2; /* always binary 10 */
|
||||
/* byte */
|
||||
u32 porta:2;
|
||||
u32 reserved:2;
|
||||
u32 seq_nr:3;
|
||||
u32 extended:1; /* if false is struct selfid */
|
||||
/* byte */
|
||||
u32 porte:2;
|
||||
u32 portd:2;
|
||||
u32 portc:2;
|
||||
u32 portb:2;
|
||||
/* byte */
|
||||
u32 more_packets:1;
|
||||
u32 reserved2:1;
|
||||
u32 porth:2;
|
||||
u32 portg:2;
|
||||
u32 portf:2;
|
||||
} __attribute__((packed));
|
||||
|
||||
#else
|
||||
#error What? PDP endian?
|
||||
#endif /* __BIG_ENDIAN_BITFIELD */
|
||||
|
||||
#endif /* _IEEE1394_IEEE1394_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,172 +0,0 @@
|
|||
#ifndef _IEEE1394_CORE_H
|
||||
#define _IEEE1394_CORE_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "hosts.h"
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
struct hpsb_packet {
|
||||
/* This struct is basically read-only for hosts with the exception of
|
||||
* the data buffer contents and driver_list. */
|
||||
|
||||
/* This can be used for host driver internal linking.
|
||||
*
|
||||
* NOTE: This must be left in init state when the driver is done
|
||||
* with it (e.g. by using list_del_init()), since the core does
|
||||
* some sanity checks to make sure the packet is not on a
|
||||
* driver_list when free'ing it. */
|
||||
struct list_head driver_list;
|
||||
|
||||
nodeid_t node_id;
|
||||
|
||||
/* hpsb_raw = send as-is, do not CRC (but still byte-swap it) */
|
||||
enum { hpsb_async, hpsb_raw } __attribute__((packed)) type;
|
||||
|
||||
/* Okay, this is core internal and a no care for hosts.
|
||||
* queued = queued for sending
|
||||
* pending = sent, waiting for response
|
||||
* complete = processing completed, successful or not
|
||||
*/
|
||||
enum {
|
||||
hpsb_unused, hpsb_queued, hpsb_pending, hpsb_complete
|
||||
} __attribute__((packed)) state;
|
||||
|
||||
/* These are core-internal. */
|
||||
signed char tlabel;
|
||||
signed char ack_code;
|
||||
unsigned char tcode;
|
||||
|
||||
unsigned expect_response:1;
|
||||
unsigned no_waiter:1;
|
||||
|
||||
/* Speed to transmit with: 0 = 100Mbps, 1 = 200Mbps, 2 = 400Mbps */
|
||||
unsigned speed_code:2;
|
||||
|
||||
struct hpsb_host *host;
|
||||
unsigned int generation;
|
||||
|
||||
atomic_t refcnt;
|
||||
struct list_head queue;
|
||||
|
||||
/* Function (and possible data to pass to it) to call when this
|
||||
* packet is completed. */
|
||||
void (*complete_routine)(void *);
|
||||
void *complete_data;
|
||||
|
||||
/* Store jiffies for implementing bus timeouts. */
|
||||
unsigned long sendtime;
|
||||
|
||||
/* Core-internal. */
|
||||
size_t allocated_data_size; /* as allocated */
|
||||
|
||||
/* Sizes are in bytes. To be set by caller of hpsb_alloc_packet. */
|
||||
size_t data_size; /* as filled in */
|
||||
size_t header_size; /* as filled in, not counting the CRC */
|
||||
|
||||
/* Buffers */
|
||||
quadlet_t *data; /* can be DMA-mapped */
|
||||
quadlet_t header[5];
|
||||
quadlet_t embedded_data[0]; /* keep as last member */
|
||||
};
|
||||
|
||||
void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
|
||||
void (*routine)(void *), void *data);
|
||||
static inline struct hpsb_packet *driver_packet(struct list_head *l)
|
||||
{
|
||||
return list_entry(l, struct hpsb_packet, driver_list);
|
||||
}
|
||||
void abort_timedouts(unsigned long __opaque);
|
||||
struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
|
||||
void hpsb_free_packet(struct hpsb_packet *packet);
|
||||
|
||||
/**
|
||||
* get_hpsb_generation - generation counter for the complete 1394 subsystem
|
||||
*
|
||||
* Generation gets incremented on every change in the subsystem (notably on bus
|
||||
* resets). Use the functions, not the variable.
|
||||
*/
|
||||
static inline unsigned int get_hpsb_generation(struct hpsb_host *host)
|
||||
{
|
||||
return atomic_read(&host->generation);
|
||||
}
|
||||
|
||||
int hpsb_send_phy_config(struct hpsb_host *host, int rootid, int gapcnt);
|
||||
int hpsb_send_packet(struct hpsb_packet *packet);
|
||||
int hpsb_send_packet_and_wait(struct hpsb_packet *packet);
|
||||
int hpsb_reset_bus(struct hpsb_host *host, int type);
|
||||
int hpsb_read_cycle_timer(struct hpsb_host *host, u32 *cycle_timer,
|
||||
u64 *local_time);
|
||||
|
||||
int hpsb_bus_reset(struct hpsb_host *host);
|
||||
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
|
||||
void hpsb_selfid_complete(struct hpsb_host *host, int phyid, int isroot);
|
||||
void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
|
||||
int ackcode);
|
||||
void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
|
||||
int write_acked);
|
||||
|
||||
/*
|
||||
* CHARACTER DEVICE DISPATCHING
|
||||
*
|
||||
* All ieee1394 character device drivers share the same major number
|
||||
* (major 171). The 256 minor numbers are allocated to the various
|
||||
* task-specific interfaces (raw1394, video1394, dv1394, etc) in
|
||||
* blocks of 16.
|
||||
*
|
||||
* The core ieee1394.o module allocates the device number region
|
||||
* 171:0-255, the various drivers must then cdev_add() their cdev
|
||||
* objects to handle their respective sub-regions.
|
||||
*
|
||||
* Minor device number block allocations:
|
||||
*
|
||||
* Block 0 ( 0- 15) raw1394
|
||||
* Block 1 ( 16- 31) video1394
|
||||
* Block 2 ( 32- 47) dv1394
|
||||
*
|
||||
* Blocks 3-14 free for future allocation
|
||||
*
|
||||
* Block 15 (240-255) reserved for drivers under development, etc.
|
||||
*/
|
||||
|
||||
#define IEEE1394_MAJOR 171
|
||||
|
||||
#define IEEE1394_MINOR_BLOCK_RAW1394 0
|
||||
#define IEEE1394_MINOR_BLOCK_VIDEO1394 1
|
||||
#define IEEE1394_MINOR_BLOCK_DV1394 2
|
||||
#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
|
||||
|
||||
#define IEEE1394_CORE_DEV MKDEV(IEEE1394_MAJOR, 0)
|
||||
#define IEEE1394_RAW1394_DEV MKDEV(IEEE1394_MAJOR, \
|
||||
IEEE1394_MINOR_BLOCK_RAW1394 * 16)
|
||||
#define IEEE1394_VIDEO1394_DEV MKDEV(IEEE1394_MAJOR, \
|
||||
IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
|
||||
#define IEEE1394_DV1394_DEV MKDEV(IEEE1394_MAJOR, \
|
||||
IEEE1394_MINOR_BLOCK_DV1394 * 16)
|
||||
#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
|
||||
IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
|
||||
|
||||
/**
|
||||
* ieee1394_file_to_instance - get the index within a minor number block
|
||||
*/
|
||||
static inline unsigned char ieee1394_file_to_instance(struct file *file)
|
||||
{
|
||||
int idx = cdev_index(file->f_path.dentry->d_inode);
|
||||
if (idx < 0)
|
||||
idx = 0;
|
||||
return idx;
|
||||
}
|
||||
|
||||
extern int hpsb_disable_irm;
|
||||
|
||||
/* Our sysfs bus entry */
|
||||
extern struct bus_type ieee1394_bus_type;
|
||||
extern struct class hpsb_host_class;
|
||||
extern struct class *hpsb_protocol_class;
|
||||
|
||||
#endif /* _IEEE1394_CORE_H */
|
|
@ -1,19 +0,0 @@
|
|||
#ifndef _IEEE1394_HOTPLUG_H
|
||||
#define _IEEE1394_HOTPLUG_H
|
||||
|
||||
/* Unit spec id and sw version entry for some protocols */
|
||||
#define AVC_UNIT_SPEC_ID_ENTRY 0x0000A02D
|
||||
#define AVC_SW_VERSION_ENTRY 0x00010001
|
||||
#define CAMERA_UNIT_SPEC_ID_ENTRY 0x0000A02D
|
||||
#define CAMERA_SW_VERSION_ENTRY 0x00000100
|
||||
|
||||
/* /include/linux/mod_devicetable.h defines:
|
||||
* IEEE1394_MATCH_VENDOR_ID
|
||||
* IEEE1394_MATCH_MODEL_ID
|
||||
* IEEE1394_MATCH_SPECIFIER_ID
|
||||
* IEEE1394_MATCH_VERSION
|
||||
* struct ieee1394_device_id
|
||||
*/
|
||||
#include <linux/mod_devicetable.h>
|
||||
|
||||
#endif /* _IEEE1394_HOTPLUG_H */
|
|
@ -1,595 +0,0 @@
|
|||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* Transaction support.
|
||||
*
|
||||
* Copyright (C) 1999 Andreas E. Bombe
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sched.h> /* because linux/wait.h is broken if CONFIG_SMP=n */
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <asm/bug.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#include "ieee1394.h"
|
||||
#include "ieee1394_types.h"
|
||||
#include "hosts.h"
|
||||
#include "ieee1394_core.h"
|
||||
#include "ieee1394_transactions.h"
|
||||
|
||||
#define PREP_ASYNC_HEAD_ADDRESS(tc) \
|
||||
packet->tcode = tc; \
|
||||
packet->header[0] = (packet->node_id << 16) | (packet->tlabel << 10) \
|
||||
| (1 << 8) | (tc << 4); \
|
||||
packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
|
||||
packet->header[2] = addr & 0xffffffff
|
||||
|
||||
#ifndef HPSB_DEBUG_TLABELS
|
||||
static
|
||||
#endif
|
||||
DEFINE_SPINLOCK(hpsb_tlabel_lock);
|
||||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
|
||||
|
||||
static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
|
||||
{
|
||||
PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
|
||||
packet->header_size = 12;
|
||||
packet->data_size = 0;
|
||||
packet->expect_response = 1;
|
||||
}
|
||||
|
||||
static void fill_async_readblock(struct hpsb_packet *packet, u64 addr,
|
||||
int length)
|
||||
{
|
||||
PREP_ASYNC_HEAD_ADDRESS(TCODE_READB);
|
||||
packet->header[3] = length << 16;
|
||||
packet->header_size = 16;
|
||||
packet->data_size = 0;
|
||||
packet->expect_response = 1;
|
||||
}
|
||||
|
||||
static void fill_async_writequad(struct hpsb_packet *packet, u64 addr,
|
||||
quadlet_t data)
|
||||
{
|
||||
PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEQ);
|
||||
packet->header[3] = data;
|
||||
packet->header_size = 16;
|
||||
packet->data_size = 0;
|
||||
packet->expect_response = 1;
|
||||
}
|
||||
|
||||
static void fill_async_writeblock(struct hpsb_packet *packet, u64 addr,
|
||||
int length)
|
||||
{
|
||||
PREP_ASYNC_HEAD_ADDRESS(TCODE_WRITEB);
|
||||
packet->header[3] = length << 16;
|
||||
packet->header_size = 16;
|
||||
packet->expect_response = 1;
|
||||
packet->data_size = length + (length % 4 ? 4 - (length % 4) : 0);
|
||||
}
|
||||
|
||||
static void fill_async_lock(struct hpsb_packet *packet, u64 addr, int extcode,
|
||||
int length)
|
||||
{
|
||||
PREP_ASYNC_HEAD_ADDRESS(TCODE_LOCK_REQUEST);
|
||||
packet->header[3] = (length << 16) | extcode;
|
||||
packet->header_size = 16;
|
||||
packet->data_size = length;
|
||||
packet->expect_response = 1;
|
||||
}
|
||||
|
||||
static void fill_phy_packet(struct hpsb_packet *packet, quadlet_t data)
|
||||
{
|
||||
packet->header[0] = data;
|
||||
packet->header[1] = ~data;
|
||||
packet->header_size = 8;
|
||||
packet->data_size = 0;
|
||||
packet->expect_response = 0;
|
||||
packet->type = hpsb_raw; /* No CRC added */
|
||||
packet->speed_code = IEEE1394_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;
|
||||
}
|
||||
|
||||
/* same as hpsb_get_tlabel, except that it returns immediately */
|
||||
static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
|
||||
{
|
||||
unsigned long flags, *tp;
|
||||
u8 *next;
|
||||
int tlabel, n = NODEID_TO_NODE(packet->node_id);
|
||||
|
||||
/* Broadcast transactions are complete once the request has been sent.
|
||||
* Use the same transaction label for all broadcast transactions. */
|
||||
if (unlikely(n == ALL_NODES)) {
|
||||
packet->tlabel = 0;
|
||||
return 0;
|
||||
}
|
||||
tp = packet->host->tl_pool[n].map;
|
||||
next = &packet->host->next_tl[n];
|
||||
|
||||
spin_lock_irqsave(&hpsb_tlabel_lock, flags);
|
||||
tlabel = find_next_zero_bit(tp, 64, *next);
|
||||
if (tlabel > 63)
|
||||
tlabel = find_first_zero_bit(tp, 64);
|
||||
if (tlabel > 63) {
|
||||
spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
|
||||
return -EAGAIN;
|
||||
}
|
||||
__set_bit(tlabel, tp);
|
||||
*next = (tlabel + 1) & 63;
|
||||
spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
|
||||
|
||||
packet->tlabel = tlabel;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_get_tlabel - allocate a transaction label
|
||||
* @packet: the packet whose tlabel and tl_pool we set
|
||||
*
|
||||
* Every asynchronous transaction on the 1394 bus needs a transaction
|
||||
* label to match the response to the request. This label has to be
|
||||
* different from any other transaction label in an outstanding request to
|
||||
* the same node to make matching possible without ambiguity.
|
||||
*
|
||||
* There are 64 different tlabels, so an allocated tlabel has to be freed
|
||||
* with hpsb_free_tlabel() after the transaction is complete (unless it's
|
||||
* reused again for the same target node).
|
||||
*
|
||||
* Return value: Zero on success, otherwise non-zero. A non-zero return
|
||||
* generally means there are no available tlabels. If this is called out
|
||||
* of interrupt or atomic context, then it will sleep until can return a
|
||||
* tlabel or a signal is received.
|
||||
*/
|
||||
int hpsb_get_tlabel(struct hpsb_packet *packet)
|
||||
{
|
||||
if (irqs_disabled() || in_atomic())
|
||||
return hpsb_get_tlabel_atomic(packet);
|
||||
|
||||
/* NB: The macro wait_event_interruptible() is called with a condition
|
||||
* argument with side effect. This is only possible because the side
|
||||
* effect does not occur until the condition became true, and
|
||||
* wait_event_interruptible() won't evaluate the condition again after
|
||||
* that. */
|
||||
return wait_event_interruptible(tlabel_wq,
|
||||
!hpsb_get_tlabel_atomic(packet));
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_free_tlabel - free an allocated transaction label
|
||||
* @packet: packet whose tlabel and tl_pool needs to be cleared
|
||||
*
|
||||
* Frees the transaction label allocated with hpsb_get_tlabel(). The
|
||||
* tlabel has to be freed after the transaction is complete (i.e. response
|
||||
* was received for a split transaction or packet was sent for a unified
|
||||
* transaction).
|
||||
*
|
||||
* A tlabel must not be freed twice.
|
||||
*/
|
||||
void hpsb_free_tlabel(struct hpsb_packet *packet)
|
||||
{
|
||||
unsigned long flags, *tp;
|
||||
int tlabel, n = NODEID_TO_NODE(packet->node_id);
|
||||
|
||||
if (unlikely(n == ALL_NODES))
|
||||
return;
|
||||
tp = packet->host->tl_pool[n].map;
|
||||
tlabel = packet->tlabel;
|
||||
BUG_ON(tlabel > 63 || tlabel < 0);
|
||||
|
||||
spin_lock_irqsave(&hpsb_tlabel_lock, flags);
|
||||
BUG_ON(!__test_and_clear_bit(tlabel, tp));
|
||||
spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
|
||||
|
||||
wake_up_interruptible(&tlabel_wq);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_packet_success - Make sense of the ack and reply codes
|
||||
*
|
||||
* Make sense of the ack and reply codes and return more convenient error codes:
|
||||
* 0 = success. -%EBUSY = node is busy, try again. -%EAGAIN = error which can
|
||||
* probably resolved by retry. -%EREMOTEIO = node suffers from an internal
|
||||
* error. -%EACCES = this transaction is not allowed on requested address.
|
||||
* -%EINVAL = invalid address at node.
|
||||
*/
|
||||
int hpsb_packet_success(struct hpsb_packet *packet)
|
||||
{
|
||||
switch (packet->ack_code) {
|
||||
case ACK_PENDING:
|
||||
switch ((packet->header[1] >> 12) & 0xf) {
|
||||
case RCODE_COMPLETE:
|
||||
return 0;
|
||||
case RCODE_CONFLICT_ERROR:
|
||||
return -EAGAIN;
|
||||
case RCODE_DATA_ERROR:
|
||||
return -EREMOTEIO;
|
||||
case RCODE_TYPE_ERROR:
|
||||
return -EACCES;
|
||||
case RCODE_ADDRESS_ERROR:
|
||||
return -EINVAL;
|
||||
default:
|
||||
HPSB_ERR("received reserved rcode %d from node %d",
|
||||
(packet->header[1] >> 12) & 0xf,
|
||||
packet->node_id);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
case ACK_BUSY_X:
|
||||
case ACK_BUSY_A:
|
||||
case ACK_BUSY_B:
|
||||
return -EBUSY;
|
||||
|
||||
case ACK_TYPE_ERROR:
|
||||
return -EACCES;
|
||||
|
||||
case ACK_COMPLETE:
|
||||
if (packet->tcode == TCODE_WRITEQ
|
||||
|| packet->tcode == TCODE_WRITEB) {
|
||||
return 0;
|
||||
} else {
|
||||
HPSB_ERR("impossible ack_complete from node %d "
|
||||
"(tcode %d)", packet->node_id, packet->tcode);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
case ACK_DATA_ERROR:
|
||||
if (packet->tcode == TCODE_WRITEB
|
||||
|| packet->tcode == TCODE_LOCK_REQUEST) {
|
||||
return -EAGAIN;
|
||||
} else {
|
||||
HPSB_ERR("impossible ack_data_error from node %d "
|
||||
"(tcode %d)", packet->node_id, packet->tcode);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
case ACK_ADDRESS_ERROR:
|
||||
return -EINVAL;
|
||||
|
||||
case ACK_TARDY:
|
||||
case ACK_CONFLICT_ERROR:
|
||||
case ACKX_NONE:
|
||||
case ACKX_SEND_ERROR:
|
||||
case ACKX_ABORTED:
|
||||
case ACKX_TIMEOUT:
|
||||
/* error while sending */
|
||||
return -EAGAIN;
|
||||
|
||||
default:
|
||||
HPSB_ERR("got invalid ack %d from node %d (tcode %d)",
|
||||
packet->ack_code, packet->node_id, packet->tcode);
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
|
||||
u64 addr, size_t length)
|
||||
{
|
||||
struct hpsb_packet *packet;
|
||||
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
|
||||
packet = hpsb_alloc_packet(length);
|
||||
if (!packet)
|
||||
return NULL;
|
||||
|
||||
packet->host = host;
|
||||
packet->node_id = node;
|
||||
|
||||
if (hpsb_get_tlabel(packet)) {
|
||||
hpsb_free_packet(packet);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (length == 4)
|
||||
fill_async_readquad(packet, addr);
|
||||
else
|
||||
fill_async_readblock(packet, addr, length);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host, nodeid_t node,
|
||||
u64 addr, quadlet_t * buffer,
|
||||
size_t length)
|
||||
{
|
||||
struct hpsb_packet *packet;
|
||||
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
|
||||
packet = hpsb_alloc_packet(length);
|
||||
if (!packet)
|
||||
return NULL;
|
||||
|
||||
if (length % 4) { /* zero padding bytes */
|
||||
packet->data[length >> 2] = 0;
|
||||
}
|
||||
packet->host = host;
|
||||
packet->node_id = node;
|
||||
|
||||
if (hpsb_get_tlabel(packet)) {
|
||||
hpsb_free_packet(packet);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (length == 4) {
|
||||
fill_async_writequad(packet, addr, buffer ? *buffer : 0);
|
||||
} else {
|
||||
fill_async_writeblock(packet, addr, length);
|
||||
if (buffer)
|
||||
memcpy(packet->data, buffer, length);
|
||||
}
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 * buffer,
|
||||
int length, int channel, int tag,
|
||||
int sync)
|
||||
{
|
||||
struct hpsb_packet *packet;
|
||||
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
|
||||
packet = hpsb_alloc_packet(length);
|
||||
if (!packet)
|
||||
return NULL;
|
||||
|
||||
if (length % 4) { /* zero padding bytes */
|
||||
packet->data[length >> 2] = 0;
|
||||
}
|
||||
packet->host = host;
|
||||
|
||||
/* Because it is too difficult to determine all PHY speeds and link
|
||||
* speeds here, we use S100... */
|
||||
packet->speed_code = IEEE1394_SPEED_100;
|
||||
|
||||
/* ...and prevent hpsb_send_packet() from overriding it. */
|
||||
packet->node_id = LOCAL_BUS | ALL_NODES;
|
||||
|
||||
if (hpsb_get_tlabel(packet)) {
|
||||
hpsb_free_packet(packet);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fill_async_stream_packet(packet, length, channel, tag, sync);
|
||||
if (buffer)
|
||||
memcpy(packet->data, buffer, length);
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
|
||||
u64 addr, int extcode,
|
||||
quadlet_t * data, quadlet_t arg)
|
||||
{
|
||||
struct hpsb_packet *p;
|
||||
u32 length;
|
||||
|
||||
p = hpsb_alloc_packet(8);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
p->host = host;
|
||||
p->node_id = node;
|
||||
if (hpsb_get_tlabel(p)) {
|
||||
hpsb_free_packet(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (extcode) {
|
||||
case EXTCODE_FETCH_ADD:
|
||||
case EXTCODE_LITTLE_ADD:
|
||||
length = 4;
|
||||
if (data)
|
||||
p->data[0] = *data;
|
||||
break;
|
||||
default:
|
||||
length = 8;
|
||||
if (data) {
|
||||
p->data[0] = arg;
|
||||
p->data[1] = *data;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fill_async_lock(p, addr, extcode, length);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
|
||||
nodeid_t node, u64 addr, int extcode,
|
||||
octlet_t * data, octlet_t arg)
|
||||
{
|
||||
struct hpsb_packet *p;
|
||||
u32 length;
|
||||
|
||||
p = hpsb_alloc_packet(16);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
p->host = host;
|
||||
p->node_id = node;
|
||||
if (hpsb_get_tlabel(p)) {
|
||||
hpsb_free_packet(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (extcode) {
|
||||
case EXTCODE_FETCH_ADD:
|
||||
case EXTCODE_LITTLE_ADD:
|
||||
length = 8;
|
||||
if (data) {
|
||||
p->data[0] = *data >> 32;
|
||||
p->data[1] = *data & 0xffffffff;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
length = 16;
|
||||
if (data) {
|
||||
p->data[0] = arg >> 32;
|
||||
p->data[1] = arg & 0xffffffff;
|
||||
p->data[2] = *data >> 32;
|
||||
p->data[3] = *data & 0xffffffff;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fill_async_lock(p, addr, extcode, length);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data)
|
||||
{
|
||||
struct hpsb_packet *p;
|
||||
|
||||
p = hpsb_alloc_packet(0);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
p->host = host;
|
||||
fill_phy_packet(p, data);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME - these functions should probably read from / write to user space to
|
||||
* avoid in kernel buffers for user space callers
|
||||
*/
|
||||
|
||||
/**
|
||||
* hpsb_read - generic read function
|
||||
*
|
||||
* Recognizes the local node ID and act accordingly. Automatically uses a
|
||||
* quadlet read request if @length == 4 and and a block read request otherwise.
|
||||
* It does not yet 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, unsigned int generation,
|
||||
u64 addr, quadlet_t * buffer, size_t length)
|
||||
{
|
||||
struct hpsb_packet *packet;
|
||||
int retval = 0;
|
||||
|
||||
if (length == 0)
|
||||
return -EINVAL;
|
||||
|
||||
packet = hpsb_make_readpacket(host, node, addr, length);
|
||||
|
||||
if (!packet) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
packet->generation = generation;
|
||||
retval = hpsb_send_packet_and_wait(packet);
|
||||
if (retval < 0)
|
||||
goto hpsb_read_fail;
|
||||
|
||||
retval = hpsb_packet_success(packet);
|
||||
|
||||
if (retval == 0) {
|
||||
if (length == 4) {
|
||||
*buffer = packet->header[3];
|
||||
} else {
|
||||
memcpy(buffer, packet->data, length);
|
||||
}
|
||||
}
|
||||
|
||||
hpsb_read_fail:
|
||||
hpsb_free_tlabel(packet);
|
||||
hpsb_free_packet(packet);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_write - generic write function
|
||||
*
|
||||
* Recognizes the local node ID and act accordingly. Automatically uses a
|
||||
* quadlet write request if @length == 4 and and a block write request
|
||||
* otherwise. It does not yet 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_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;
|
||||
|
||||
if (length == 0)
|
||||
return -EINVAL;
|
||||
|
||||
packet = hpsb_make_writepacket(host, node, addr, buffer, length);
|
||||
|
||||
if (!packet)
|
||||
return -ENOMEM;
|
||||
|
||||
packet->generation = generation;
|
||||
retval = hpsb_send_packet_and_wait(packet);
|
||||
if (retval < 0)
|
||||
goto hpsb_write_fail;
|
||||
|
||||
retval = hpsb_packet_success(packet);
|
||||
|
||||
hpsb_write_fail:
|
||||
hpsb_free_tlabel(packet);
|
||||
hpsb_free_packet(packet);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
|
||||
if (!packet)
|
||||
return -ENOMEM;
|
||||
|
||||
packet->generation = generation;
|
||||
retval = hpsb_send_packet_and_wait(packet);
|
||||
if (retval < 0)
|
||||
goto hpsb_lock_fail;
|
||||
|
||||
retval = hpsb_packet_success(packet);
|
||||
|
||||
if (retval == 0)
|
||||
*data = packet->data[0];
|
||||
|
||||
hpsb_lock_fail:
|
||||
hpsb_free_tlabel(packet);
|
||||
hpsb_free_packet(packet);
|
||||
|
||||
return retval;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
#ifndef _IEEE1394_TRANSACTIONS_H
|
||||
#define _IEEE1394_TRANSACTIONS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
struct hpsb_packet;
|
||||
struct hpsb_host;
|
||||
|
||||
int hpsb_get_tlabel(struct hpsb_packet *packet);
|
||||
void hpsb_free_tlabel(struct hpsb_packet *packet);
|
||||
struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
|
||||
u64 addr, size_t length);
|
||||
struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
|
||||
u64 addr, int extcode, quadlet_t *data,
|
||||
quadlet_t arg);
|
||||
struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
|
||||
nodeid_t node, u64 addr, int extcode,
|
||||
octlet_t *data, octlet_t arg);
|
||||
struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data);
|
||||
struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
|
||||
nodeid_t node, u64 addr,
|
||||
quadlet_t *buffer, size_t length);
|
||||
struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
|
||||
int length, int channel, int tag,
|
||||
int sync);
|
||||
int hpsb_packet_success(struct hpsb_packet *packet);
|
||||
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);
|
||||
|
||||
#ifdef HPSB_DEBUG_TLABELS
|
||||
extern spinlock_t hpsb_tlabel_lock;
|
||||
#endif
|
||||
|
||||
#endif /* _IEEE1394_TRANSACTIONS_H */
|
|
@ -1,69 +0,0 @@
|
|||
#ifndef _IEEE1394_TYPES_H
|
||||
#define _IEEE1394_TYPES_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
typedef u32 quadlet_t;
|
||||
typedef u64 octlet_t;
|
||||
typedef u16 nodeid_t;
|
||||
|
||||
typedef u8 byte_t;
|
||||
typedef u64 nodeaddr_t;
|
||||
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 "%d-%02d:%04d"
|
||||
#define NODE_BUS_ARGS(__host, __nodeid) \
|
||||
__host->id, NODEID_TO_NODE(__nodeid), NODEID_TO_BUS(__nodeid)
|
||||
|
||||
#define HPSB_PRINT(level, fmt, args...) \
|
||||
printk(level "ieee1394: " fmt "\n" , ## args)
|
||||
|
||||
#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
|
||||
#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args)
|
||||
#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args)
|
||||
#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args)
|
||||
#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args)
|
||||
|
||||
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
|
||||
#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
|
||||
#define HPSB_DEBUG_TLABELS
|
||||
#else
|
||||
#define HPSB_VERBOSE(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
|
||||
static inline void *memcpy_le32(u32 *dest, const u32 *__src, size_t count)
|
||||
{
|
||||
void *tmp = dest;
|
||||
u32 *src = (u32 *)__src;
|
||||
|
||||
count /= 4;
|
||||
while (count--)
|
||||
*dest++ = swab32p(src++);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count)
|
||||
{
|
||||
return memcpy(dest, src, count);
|
||||
}
|
||||
|
||||
#endif /* __BIG_ENDIAN */
|
||||
|
||||
#endif /* _IEEE1394_TYPES_H */
|
|
@ -1,568 +0,0 @@
|
|||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* kernel ISO transmission/reception
|
||||
*
|
||||
* Copyright (C) 2002 Maas Digital LLC
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "hosts.h"
|
||||
#include "iso.h"
|
||||
|
||||
/**
|
||||
* hpsb_iso_stop - stop DMA
|
||||
*/
|
||||
void hpsb_iso_stop(struct hpsb_iso *iso)
|
||||
{
|
||||
if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
|
||||
return;
|
||||
|
||||
iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
|
||||
XMIT_STOP : RECV_STOP, 0);
|
||||
iso->flags &= ~HPSB_ISO_DRIVER_STARTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_shutdown - deallocate buffer and DMA context
|
||||
*/
|
||||
void hpsb_iso_shutdown(struct hpsb_iso *iso)
|
||||
{
|
||||
if (iso->flags & HPSB_ISO_DRIVER_INIT) {
|
||||
hpsb_iso_stop(iso);
|
||||
iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
|
||||
XMIT_SHUTDOWN : RECV_SHUTDOWN, 0);
|
||||
iso->flags &= ~HPSB_ISO_DRIVER_INIT;
|
||||
}
|
||||
|
||||
dma_region_free(&iso->data_buf);
|
||||
kfree(iso);
|
||||
}
|
||||
|
||||
static struct hpsb_iso *hpsb_iso_common_init(struct hpsb_host *host,
|
||||
enum hpsb_iso_type type,
|
||||
unsigned int data_buf_size,
|
||||
unsigned int buf_packets,
|
||||
int channel, int dma_mode,
|
||||
int irq_interval,
|
||||
void (*callback) (struct hpsb_iso
|
||||
*))
|
||||
{
|
||||
struct hpsb_iso *iso;
|
||||
int dma_direction;
|
||||
|
||||
/* make sure driver supports the ISO API */
|
||||
if (!host->driver->isoctl) {
|
||||
printk(KERN_INFO
|
||||
"ieee1394: host driver '%s' does not support the rawiso API\n",
|
||||
host->driver->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* sanitize parameters */
|
||||
|
||||
if (buf_packets < 2)
|
||||
buf_packets = 2;
|
||||
|
||||
if ((dma_mode < HPSB_ISO_DMA_DEFAULT)
|
||||
|| (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
|
||||
dma_mode = HPSB_ISO_DMA_DEFAULT;
|
||||
|
||||
if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
|
||||
irq_interval = buf_packets / 4;
|
||||
if (irq_interval == 0) /* really interrupt for each packet */
|
||||
irq_interval = 1;
|
||||
|
||||
if (channel < -1 || channel >= 64)
|
||||
return NULL;
|
||||
|
||||
/* channel = -1 is OK for multi-channel recv but not for xmit */
|
||||
if (type == HPSB_ISO_XMIT && channel < 0)
|
||||
return NULL;
|
||||
|
||||
/* allocate and write the struct hpsb_iso */
|
||||
|
||||
iso =
|
||||
kmalloc(sizeof(*iso) +
|
||||
buf_packets * sizeof(struct hpsb_iso_packet_info),
|
||||
GFP_KERNEL);
|
||||
if (!iso)
|
||||
return NULL;
|
||||
|
||||
iso->infos = (struct hpsb_iso_packet_info *)(iso + 1);
|
||||
|
||||
iso->type = type;
|
||||
iso->host = host;
|
||||
iso->hostdata = NULL;
|
||||
iso->callback = callback;
|
||||
init_waitqueue_head(&iso->waitq);
|
||||
iso->channel = channel;
|
||||
iso->irq_interval = irq_interval;
|
||||
iso->dma_mode = dma_mode;
|
||||
dma_region_init(&iso->data_buf);
|
||||
iso->buf_size = PAGE_ALIGN(data_buf_size);
|
||||
iso->buf_packets = buf_packets;
|
||||
iso->pkt_dma = 0;
|
||||
iso->first_packet = 0;
|
||||
spin_lock_init(&iso->lock);
|
||||
|
||||
if (iso->type == HPSB_ISO_XMIT) {
|
||||
iso->n_ready_packets = iso->buf_packets;
|
||||
dma_direction = PCI_DMA_TODEVICE;
|
||||
} else {
|
||||
iso->n_ready_packets = 0;
|
||||
dma_direction = PCI_DMA_FROMDEVICE;
|
||||
}
|
||||
|
||||
atomic_set(&iso->overflows, 0);
|
||||
iso->bytes_discarded = 0;
|
||||
iso->flags = 0;
|
||||
iso->prebuffer = 0;
|
||||
|
||||
/* allocate the packet buffer */
|
||||
if (dma_region_alloc
|
||||
(&iso->data_buf, iso->buf_size, host->pdev, dma_direction))
|
||||
goto err;
|
||||
|
||||
return iso;
|
||||
|
||||
err:
|
||||
hpsb_iso_shutdown(iso);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_n_ready - returns number of packets ready to send or receive
|
||||
*/
|
||||
int hpsb_iso_n_ready(struct hpsb_iso *iso)
|
||||
{
|
||||
unsigned long flags;
|
||||
int val;
|
||||
|
||||
spin_lock_irqsave(&iso->lock, flags);
|
||||
val = iso->n_ready_packets;
|
||||
spin_unlock_irqrestore(&iso->lock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_xmit_init - allocate the buffer and DMA context
|
||||
*/
|
||||
struct hpsb_iso *hpsb_iso_xmit_init(struct hpsb_host *host,
|
||||
unsigned int data_buf_size,
|
||||
unsigned int buf_packets,
|
||||
int channel,
|
||||
int speed,
|
||||
int irq_interval,
|
||||
void (*callback) (struct hpsb_iso *))
|
||||
{
|
||||
struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_XMIT,
|
||||
data_buf_size, buf_packets,
|
||||
channel,
|
||||
HPSB_ISO_DMA_DEFAULT,
|
||||
irq_interval, callback);
|
||||
if (!iso)
|
||||
return NULL;
|
||||
|
||||
iso->speed = speed;
|
||||
|
||||
/* tell the driver to start working */
|
||||
if (host->driver->isoctl(iso, XMIT_INIT, 0))
|
||||
goto err;
|
||||
|
||||
iso->flags |= HPSB_ISO_DRIVER_INIT;
|
||||
return iso;
|
||||
|
||||
err:
|
||||
hpsb_iso_shutdown(iso);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_init - allocate the buffer and DMA context
|
||||
*
|
||||
* Note, if channel = -1, multi-channel receive is enabled.
|
||||
*/
|
||||
struct hpsb_iso *hpsb_iso_recv_init(struct hpsb_host *host,
|
||||
unsigned int data_buf_size,
|
||||
unsigned int buf_packets,
|
||||
int channel,
|
||||
int dma_mode,
|
||||
int irq_interval,
|
||||
void (*callback) (struct hpsb_iso *))
|
||||
{
|
||||
struct hpsb_iso *iso = hpsb_iso_common_init(host, HPSB_ISO_RECV,
|
||||
data_buf_size, buf_packets,
|
||||
channel, dma_mode,
|
||||
irq_interval, callback);
|
||||
if (!iso)
|
||||
return NULL;
|
||||
|
||||
/* tell the driver to start working */
|
||||
if (host->driver->isoctl(iso, RECV_INIT, 0))
|
||||
goto err;
|
||||
|
||||
iso->flags |= HPSB_ISO_DRIVER_INIT;
|
||||
return iso;
|
||||
|
||||
err:
|
||||
hpsb_iso_shutdown(iso);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_listen_channel
|
||||
*
|
||||
* multi-channel only
|
||||
*/
|
||||
int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
|
||||
return -EINVAL;
|
||||
return iso->host->driver->isoctl(iso, RECV_LISTEN_CHANNEL, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_unlisten_channel
|
||||
*
|
||||
* multi-channel only
|
||||
*/
|
||||
int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_RECV || iso->channel != -1 || channel >= 64)
|
||||
return -EINVAL;
|
||||
return iso->host->driver->isoctl(iso, RECV_UNLISTEN_CHANNEL, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_set_channel_mask
|
||||
*
|
||||
* multi-channel only
|
||||
*/
|
||||
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_RECV || iso->channel != -1)
|
||||
return -EINVAL;
|
||||
return iso->host->driver->isoctl(iso, RECV_SET_CHANNEL_MASK,
|
||||
(unsigned long)&mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_flush - check for arrival of new packets
|
||||
*
|
||||
* check for arrival of new packets immediately (even if irq_interval
|
||||
* has not yet been reached)
|
||||
*/
|
||||
int hpsb_iso_recv_flush(struct hpsb_iso *iso)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_RECV)
|
||||
return -EINVAL;
|
||||
return iso->host->driver->isoctl(iso, RECV_FLUSH, 0);
|
||||
}
|
||||
|
||||
static int do_iso_xmit_start(struct hpsb_iso *iso, int cycle)
|
||||
{
|
||||
int retval = iso->host->driver->isoctl(iso, XMIT_START, cycle);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
iso->flags |= HPSB_ISO_DRIVER_STARTED;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_xmit_start - start DMA
|
||||
*/
|
||||
int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_XMIT)
|
||||
return -1;
|
||||
|
||||
if (iso->flags & HPSB_ISO_DRIVER_STARTED)
|
||||
return 0;
|
||||
|
||||
if (cycle < -1)
|
||||
cycle = -1;
|
||||
else if (cycle >= 8000)
|
||||
cycle %= 8000;
|
||||
|
||||
iso->xmit_cycle = cycle;
|
||||
|
||||
if (prebuffer < 0)
|
||||
prebuffer = iso->buf_packets - 1;
|
||||
else if (prebuffer == 0)
|
||||
prebuffer = 1;
|
||||
|
||||
if (prebuffer >= iso->buf_packets)
|
||||
prebuffer = iso->buf_packets - 1;
|
||||
|
||||
iso->prebuffer = prebuffer;
|
||||
|
||||
/* remember the starting cycle; DMA will commence from xmit_queue_packets()
|
||||
once enough packets have been buffered */
|
||||
iso->start_cycle = cycle;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_start - start DMA
|
||||
*/
|
||||
int hpsb_iso_recv_start(struct hpsb_iso *iso, int cycle, int tag_mask, int sync)
|
||||
{
|
||||
int retval = 0;
|
||||
int isoctl_args[3];
|
||||
|
||||
if (iso->type != HPSB_ISO_RECV)
|
||||
return -1;
|
||||
|
||||
if (iso->flags & HPSB_ISO_DRIVER_STARTED)
|
||||
return 0;
|
||||
|
||||
if (cycle < -1)
|
||||
cycle = -1;
|
||||
else if (cycle >= 8000)
|
||||
cycle %= 8000;
|
||||
|
||||
isoctl_args[0] = cycle;
|
||||
|
||||
if (tag_mask < 0)
|
||||
/* match all tags */
|
||||
tag_mask = 0xF;
|
||||
isoctl_args[1] = tag_mask;
|
||||
|
||||
isoctl_args[2] = sync;
|
||||
|
||||
retval =
|
||||
iso->host->driver->isoctl(iso, RECV_START,
|
||||
(unsigned long)&isoctl_args[0]);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
iso->flags |= HPSB_ISO_DRIVER_STARTED;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* check to make sure the user has not supplied bogus values of offset/len
|
||||
* that would cause the kernel to access memory outside the buffer */
|
||||
static int hpsb_iso_check_offset_len(struct hpsb_iso *iso,
|
||||
unsigned int offset, unsigned short len,
|
||||
unsigned int *out_offset,
|
||||
unsigned short *out_len)
|
||||
{
|
||||
if (offset >= iso->buf_size)
|
||||
return -EFAULT;
|
||||
|
||||
/* make sure the packet does not go beyond the end of the buffer */
|
||||
if (offset + len > iso->buf_size)
|
||||
return -EFAULT;
|
||||
|
||||
/* check for wrap-around */
|
||||
if (offset + len < offset)
|
||||
return -EFAULT;
|
||||
|
||||
/* now we can trust 'offset' and 'length' */
|
||||
*out_offset = offset;
|
||||
*out_len = len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_xmit_queue_packet - queue a packet for transmission.
|
||||
*
|
||||
* @offset is relative to the beginning of the DMA buffer, where the packet's
|
||||
* data payload should already have been placed.
|
||||
*/
|
||||
int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
|
||||
u8 tag, u8 sy)
|
||||
{
|
||||
struct hpsb_iso_packet_info *info;
|
||||
unsigned long flags;
|
||||
int rv;
|
||||
|
||||
if (iso->type != HPSB_ISO_XMIT)
|
||||
return -EINVAL;
|
||||
|
||||
/* is there space in the buffer? */
|
||||
if (iso->n_ready_packets <= 0) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
info = &iso->infos[iso->first_packet];
|
||||
|
||||
/* check for bogus offset/length */
|
||||
if (hpsb_iso_check_offset_len
|
||||
(iso, offset, len, &info->offset, &info->len))
|
||||
return -EFAULT;
|
||||
|
||||
info->tag = tag;
|
||||
info->sy = sy;
|
||||
|
||||
spin_lock_irqsave(&iso->lock, flags);
|
||||
|
||||
rv = iso->host->driver->isoctl(iso, XMIT_QUEUE, (unsigned long)info);
|
||||
if (rv)
|
||||
goto out;
|
||||
|
||||
/* increment cursors */
|
||||
iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
|
||||
iso->xmit_cycle = (iso->xmit_cycle + 1) % 8000;
|
||||
iso->n_ready_packets--;
|
||||
|
||||
if (iso->prebuffer != 0) {
|
||||
iso->prebuffer--;
|
||||
if (iso->prebuffer <= 0) {
|
||||
iso->prebuffer = 0;
|
||||
rv = do_iso_xmit_start(iso, iso->start_cycle);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&iso->lock, flags);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_xmit_sync - wait until all queued packets have been transmitted
|
||||
*/
|
||||
int hpsb_iso_xmit_sync(struct hpsb_iso *iso)
|
||||
{
|
||||
if (iso->type != HPSB_ISO_XMIT)
|
||||
return -EINVAL;
|
||||
|
||||
return wait_event_interruptible(iso->waitq,
|
||||
hpsb_iso_n_ready(iso) ==
|
||||
iso->buf_packets);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_packet_sent
|
||||
*
|
||||
* Available to low-level drivers.
|
||||
*
|
||||
* Call after a packet has been transmitted to the bus (interrupt context is
|
||||
* OK). @cycle is the _exact_ cycle the packet was sent on. @error should be
|
||||
* non-zero if some sort of error occurred when sending the packet.
|
||||
*/
|
||||
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&iso->lock, flags);
|
||||
|
||||
/* predict the cycle of the next packet to be queued */
|
||||
|
||||
/* jump ahead by the number of packets that are already buffered */
|
||||
cycle += iso->buf_packets - iso->n_ready_packets;
|
||||
cycle %= 8000;
|
||||
|
||||
iso->xmit_cycle = cycle;
|
||||
iso->n_ready_packets++;
|
||||
iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
|
||||
|
||||
if (iso->n_ready_packets == iso->buf_packets || error != 0) {
|
||||
/* the buffer has run empty! */
|
||||
atomic_inc(&iso->overflows);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&iso->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_packet_received
|
||||
*
|
||||
* Available to low-level drivers.
|
||||
*
|
||||
* Call after a packet has been received (interrupt context is OK).
|
||||
*/
|
||||
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
|
||||
u16 total_len, u16 cycle, u8 channel, u8 tag,
|
||||
u8 sy)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&iso->lock, flags);
|
||||
|
||||
if (iso->n_ready_packets == iso->buf_packets) {
|
||||
/* overflow! */
|
||||
atomic_inc(&iso->overflows);
|
||||
/* Record size of this discarded packet */
|
||||
iso->bytes_discarded += total_len;
|
||||
} else {
|
||||
struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
|
||||
info->offset = offset;
|
||||
info->len = len;
|
||||
info->total_len = total_len;
|
||||
info->cycle = cycle;
|
||||
info->channel = channel;
|
||||
info->tag = tag;
|
||||
info->sy = sy;
|
||||
|
||||
iso->pkt_dma = (iso->pkt_dma + 1) % iso->buf_packets;
|
||||
iso->n_ready_packets++;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&iso->lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_recv_release_packets - release packets, reuse buffer
|
||||
*
|
||||
* @n_packets have been read out of the buffer, re-use the buffer space
|
||||
*/
|
||||
int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int i;
|
||||
int rv = 0;
|
||||
|
||||
if (iso->type != HPSB_ISO_RECV)
|
||||
return -1;
|
||||
|
||||
spin_lock_irqsave(&iso->lock, flags);
|
||||
for (i = 0; i < n_packets; i++) {
|
||||
rv = iso->host->driver->isoctl(iso, RECV_RELEASE,
|
||||
(unsigned long)&iso->infos[iso->
|
||||
first_packet]);
|
||||
if (rv)
|
||||
break;
|
||||
|
||||
iso->first_packet = (iso->first_packet + 1) % iso->buf_packets;
|
||||
iso->n_ready_packets--;
|
||||
|
||||
/* release memory from packets discarded when queue was full */
|
||||
if (iso->n_ready_packets == 0) { /* Release only after all prior packets handled */
|
||||
if (iso->bytes_discarded != 0) {
|
||||
struct hpsb_iso_packet_info inf;
|
||||
inf.total_len = iso->bytes_discarded;
|
||||
iso->host->driver->isoctl(iso, RECV_RELEASE,
|
||||
(unsigned long)&inf);
|
||||
iso->bytes_discarded = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&iso->lock, flags);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* hpsb_iso_wake
|
||||
*
|
||||
* Available to low-level drivers.
|
||||
*
|
||||
* Call to wake waiting processes after buffer space has opened up.
|
||||
*/
|
||||
void hpsb_iso_wake(struct hpsb_iso *iso)
|
||||
{
|
||||
wake_up_interruptible(&iso->waitq);
|
||||
|
||||
if (iso->callback)
|
||||
iso->callback(iso);
|
||||
}
|
|
@ -1,195 +0,0 @@
|
|||
/*
|
||||
* IEEE 1394 for Linux
|
||||
*
|
||||
* kernel ISO transmission/reception
|
||||
*
|
||||
* Copyright (C) 2002 Maas Digital LLC
|
||||
*
|
||||
* This code is licensed under the GPL. See the file COPYING in the root
|
||||
* directory of the kernel sources for details.
|
||||
*/
|
||||
|
||||
#ifndef IEEE1394_ISO_H
|
||||
#define IEEE1394_ISO_H
|
||||
|
||||
#include <linux/spinlock_types.h>
|
||||
#include <linux/wait.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#include "dma.h"
|
||||
|
||||
struct hpsb_host;
|
||||
|
||||
/* high-level ISO interface */
|
||||
|
||||
/*
|
||||
* This API sends and receives isochronous packets on a large,
|
||||
* virtually-contiguous kernel memory buffer. The buffer may be mapped
|
||||
* into a user-space process for zero-copy transmission and reception.
|
||||
*
|
||||
* There are no explicit boundaries between packets in the buffer. A
|
||||
* packet may be transmitted or received at any location. However,
|
||||
* low-level drivers may impose certain restrictions on alignment or
|
||||
* size of packets. (e.g. in OHCI no packet may cross a page boundary,
|
||||
* and packets should be quadlet-aligned)
|
||||
*/
|
||||
|
||||
/* Packet descriptor - the API maintains a ring buffer of these packet
|
||||
* descriptors in kernel memory (hpsb_iso.infos[]). */
|
||||
struct hpsb_iso_packet_info {
|
||||
/* offset of data payload relative to the first byte of the buffer */
|
||||
__u32 offset;
|
||||
|
||||
/* length of the data payload, in bytes (not including the isochronous
|
||||
* header) */
|
||||
__u16 len;
|
||||
|
||||
/* (recv only) the cycle number (mod 8000) on which the packet was
|
||||
* received */
|
||||
__u16 cycle;
|
||||
|
||||
/* (recv only) channel on which the packet was received */
|
||||
__u8 channel;
|
||||
|
||||
/* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */
|
||||
__u8 tag;
|
||||
__u8 sy;
|
||||
|
||||
/* length in bytes of the packet including header/trailer.
|
||||
* MUST be at structure end, since the first part of this structure is
|
||||
* also defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is
|
||||
* copied to userspace and is accessed there through libraw1394. */
|
||||
__u16 total_len;
|
||||
};
|
||||
|
||||
enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 };
|
||||
|
||||
/* The mode of the dma when receiving iso data. Must be supported by chip */
|
||||
enum raw1394_iso_dma_recv_mode {
|
||||
HPSB_ISO_DMA_DEFAULT = -1,
|
||||
HPSB_ISO_DMA_OLD_ABI = 0,
|
||||
HPSB_ISO_DMA_BUFFERFILL = 1,
|
||||
HPSB_ISO_DMA_PACKET_PER_BUFFER = 2
|
||||
};
|
||||
|
||||
struct hpsb_iso {
|
||||
enum hpsb_iso_type type;
|
||||
|
||||
/* pointer to low-level driver and its private data */
|
||||
struct hpsb_host *host;
|
||||
void *hostdata;
|
||||
|
||||
/* a function to be called (from interrupt context) after
|
||||
* outgoing packets have been sent, or incoming packets have
|
||||
* arrived */
|
||||
void (*callback)(struct hpsb_iso*);
|
||||
|
||||
/* wait for buffer space */
|
||||
wait_queue_head_t waitq;
|
||||
|
||||
int speed; /* IEEE1394_SPEED_100, 200, or 400 */
|
||||
int channel; /* -1 if multichannel */
|
||||
int dma_mode; /* dma receive mode */
|
||||
|
||||
|
||||
/* greatest # of packets between interrupts - controls
|
||||
* the maximum latency of the buffer */
|
||||
int irq_interval;
|
||||
|
||||
/* the buffer for packet data payloads */
|
||||
struct dma_region data_buf;
|
||||
|
||||
/* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */
|
||||
unsigned int buf_size;
|
||||
|
||||
/* # of packets in the ringbuffer */
|
||||
unsigned int buf_packets;
|
||||
|
||||
/* protects packet cursors */
|
||||
spinlock_t lock;
|
||||
|
||||
/* the index of the next packet that will be produced
|
||||
or consumed by the user */
|
||||
int first_packet;
|
||||
|
||||
/* the index of the next packet that will be transmitted
|
||||
or received by the 1394 hardware */
|
||||
int pkt_dma;
|
||||
|
||||
/* how many packets, starting at first_packet:
|
||||
* (transmit) are ready to be filled with data
|
||||
* (receive) contain received data */
|
||||
int n_ready_packets;
|
||||
|
||||
/* how many times the buffer has overflowed or underflowed */
|
||||
atomic_t overflows;
|
||||
/* how many cycles were skipped for a given context */
|
||||
atomic_t skips;
|
||||
|
||||
/* Current number of bytes lost in discarded packets */
|
||||
int bytes_discarded;
|
||||
|
||||
/* private flags to track initialization progress */
|
||||
#define HPSB_ISO_DRIVER_INIT (1<<0)
|
||||
#define HPSB_ISO_DRIVER_STARTED (1<<1)
|
||||
unsigned int flags;
|
||||
|
||||
/* # of packets left to prebuffer (xmit only) */
|
||||
int prebuffer;
|
||||
|
||||
/* starting cycle for DMA (xmit only) */
|
||||
int start_cycle;
|
||||
|
||||
/* cycle at which next packet will be transmitted,
|
||||
* -1 if not known */
|
||||
int xmit_cycle;
|
||||
|
||||
/* ringbuffer of packet descriptors in regular kernel memory
|
||||
* XXX Keep this last, since we use over-allocated memory from
|
||||
* this entry to fill this field. */
|
||||
struct hpsb_iso_packet_info *infos;
|
||||
};
|
||||
|
||||
/* functions available to high-level drivers (e.g. raw1394) */
|
||||
|
||||
struct hpsb_iso* hpsb_iso_xmit_init(struct hpsb_host *host,
|
||||
unsigned int data_buf_size,
|
||||
unsigned int buf_packets,
|
||||
int channel,
|
||||
int speed,
|
||||
int irq_interval,
|
||||
void (*callback)(struct hpsb_iso*));
|
||||
struct hpsb_iso* hpsb_iso_recv_init(struct hpsb_host *host,
|
||||
unsigned int data_buf_size,
|
||||
unsigned int buf_packets,
|
||||
int channel,
|
||||
int dma_mode,
|
||||
int irq_interval,
|
||||
void (*callback)(struct hpsb_iso*));
|
||||
int hpsb_iso_recv_listen_channel(struct hpsb_iso *iso, unsigned char channel);
|
||||
int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
|
||||
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
|
||||
int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle,
|
||||
int prebuffer);
|
||||
int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle,
|
||||
int tag_mask, int sync);
|
||||
void hpsb_iso_stop(struct hpsb_iso *iso);
|
||||
void hpsb_iso_shutdown(struct hpsb_iso *iso);
|
||||
int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
|
||||
u8 tag, u8 sy);
|
||||
int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
|
||||
int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
|
||||
unsigned int n_packets);
|
||||
int hpsb_iso_recv_flush(struct hpsb_iso *iso);
|
||||
int hpsb_iso_n_ready(struct hpsb_iso *iso);
|
||||
|
||||
/* the following are callbacks available to low-level drivers */
|
||||
|
||||
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
|
||||
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
|
||||
u16 total_len, u16 cycle, u8 channel, u8 tag,
|
||||
u8 sy);
|
||||
void hpsb_iso_wake(struct hpsb_iso *iso);
|
||||
|
||||
#endif /* IEEE1394_ISO_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,186 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2000 Andreas E. Bombe
|
||||
* 2001 Ben Collins <bcollins@debian.org>
|
||||
*
|
||||
* 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 _IEEE1394_NODEMGR_H
|
||||
#define _IEEE1394_NODEMGR_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#include "ieee1394_core.h"
|
||||
#include "ieee1394_transactions.h"
|
||||
#include "ieee1394_types.h"
|
||||
|
||||
struct csr1212_csr;
|
||||
struct csr1212_keyval;
|
||||
struct hpsb_host;
|
||||
struct ieee1394_device_id;
|
||||
|
||||
/* This is the start of a Node entry structure. It should be a stable API
|
||||
* for which to gather info from the Node Manager about devices attached
|
||||
* to the bus. */
|
||||
struct bus_options {
|
||||
u8 irmc; /* Iso Resource Manager Capable */
|
||||
u8 cmc; /* Cycle Master Capable */
|
||||
u8 isc; /* Iso Capable */
|
||||
u8 bmc; /* Bus Master Capable */
|
||||
u8 pmc; /* Power Manager Capable (PNP spec) */
|
||||
u8 cyc_clk_acc; /* Cycle clock accuracy */
|
||||
u8 max_rom; /* Maximum block read supported in the CSR */
|
||||
u8 generation; /* Incremented when configrom changes */
|
||||
u8 lnkspd; /* Link speed */
|
||||
u16 max_rec; /* Maximum packet size node can receive */
|
||||
};
|
||||
|
||||
#define UNIT_DIRECTORY_VENDOR_ID 0x01
|
||||
#define UNIT_DIRECTORY_MODEL_ID 0x02
|
||||
#define UNIT_DIRECTORY_SPECIFIER_ID 0x04
|
||||
#define UNIT_DIRECTORY_VERSION 0x08
|
||||
#define UNIT_DIRECTORY_HAS_LUN_DIRECTORY 0x10
|
||||
#define UNIT_DIRECTORY_LUN_DIRECTORY 0x20
|
||||
#define UNIT_DIRECTORY_HAS_LUN 0x40
|
||||
|
||||
/*
|
||||
* A unit directory corresponds to a protocol supported by the
|
||||
* node. If a node supports eg. IP/1394 and AV/C, its config rom has a
|
||||
* unit directory for each of these protocols.
|
||||
*/
|
||||
struct unit_directory {
|
||||
struct node_entry *ne; /* The node which this directory belongs to */
|
||||
octlet_t address; /* Address of the unit directory on the node */
|
||||
u8 flags; /* Indicates which entries were read */
|
||||
|
||||
quadlet_t vendor_id;
|
||||
struct csr1212_keyval *vendor_name_kv;
|
||||
|
||||
quadlet_t model_id;
|
||||
struct csr1212_keyval *model_name_kv;
|
||||
quadlet_t specifier_id;
|
||||
quadlet_t version;
|
||||
quadlet_t directory_id;
|
||||
|
||||
unsigned int id;
|
||||
|
||||
int ignore_driver;
|
||||
|
||||
int length; /* Number of quadlets */
|
||||
|
||||
struct device device;
|
||||
struct device unit_dev;
|
||||
|
||||
struct csr1212_keyval *ud_kv;
|
||||
u32 lun; /* logical unit number immediate value */
|
||||
};
|
||||
|
||||
struct node_entry {
|
||||
u64 guid; /* GUID of this node */
|
||||
u32 guid_vendor_id; /* Top 24bits of guid */
|
||||
|
||||
struct hpsb_host *host; /* Host this node is attached to */
|
||||
nodeid_t nodeid; /* NodeID */
|
||||
struct bus_options busopt; /* Bus Options */
|
||||
bool needs_probe;
|
||||
unsigned int generation; /* Synced with hpsb generation */
|
||||
|
||||
/* The following is read from the config rom */
|
||||
u32 vendor_id;
|
||||
struct csr1212_keyval *vendor_name_kv;
|
||||
|
||||
u32 capabilities;
|
||||
|
||||
struct device device;
|
||||
struct device node_dev;
|
||||
|
||||
/* Means this node is not attached anymore */
|
||||
bool in_limbo;
|
||||
|
||||
struct csr1212_csr *csr;
|
||||
};
|
||||
|
||||
struct hpsb_protocol_driver {
|
||||
/* The name of the driver, e.g. SBP2 or IP1394 */
|
||||
const char *name;
|
||||
|
||||
/*
|
||||
* The device id table describing the protocols and/or devices
|
||||
* supported by this driver. This is used by the nodemgr to
|
||||
* decide if a driver could support a given node, but the
|
||||
* probe function below can implement further protocol
|
||||
* dependent or vendor dependent checking.
|
||||
*/
|
||||
const struct ieee1394_device_id *id_table;
|
||||
|
||||
/*
|
||||
* The update function is called when the node has just
|
||||
* survived a bus reset, i.e. it is still present on the bus.
|
||||
* However, it may be necessary to reestablish the connection
|
||||
* or login into the node again, depending on the protocol. If the
|
||||
* probe fails (returns non-zero), we unbind the driver from this
|
||||
* device.
|
||||
*/
|
||||
int (*update)(struct unit_directory *ud);
|
||||
|
||||
/* Our LDM structure */
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
int __hpsb_register_protocol(struct hpsb_protocol_driver *, struct module *);
|
||||
static inline int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
|
||||
{
|
||||
return __hpsb_register_protocol(driver, THIS_MODULE);
|
||||
}
|
||||
|
||||
void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver);
|
||||
|
||||
static inline int hpsb_node_entry_valid(struct node_entry *ne)
|
||||
{
|
||||
return ne->generation == get_hpsb_generation(ne->host);
|
||||
}
|
||||
void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet);
|
||||
int hpsb_node_write(struct node_entry *ne, u64 addr,
|
||||
quadlet_t *buffer, size_t length);
|
||||
static inline int hpsb_node_read(struct node_entry *ne, u64 addr,
|
||||
quadlet_t *buffer, size_t length)
|
||||
{
|
||||
unsigned int g = ne->generation;
|
||||
|
||||
smp_rmb();
|
||||
return hpsb_read(ne->host, ne->nodeid, g, addr, buffer, length);
|
||||
}
|
||||
static inline int hpsb_node_lock(struct node_entry *ne, u64 addr, int extcode,
|
||||
quadlet_t *buffer, quadlet_t arg)
|
||||
{
|
||||
unsigned int g = ne->generation;
|
||||
|
||||
smp_rmb();
|
||||
return hpsb_lock(ne->host, ne->nodeid, g, addr, extcode, buffer, arg);
|
||||
}
|
||||
int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *));
|
||||
|
||||
int init_ieee1394_nodemgr(void);
|
||||
void cleanup_ieee1394_nodemgr(void);
|
||||
|
||||
/* The template for a host device */
|
||||
extern struct device nodemgr_dev_template_host;
|
||||
|
||||
/* Bus attributes we export */
|
||||
extern struct bus_attribute *const fw_bus_attrs[];
|
||||
|
||||
#endif /* _IEEE1394_NODEMGR_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,453 +0,0 @@
|
|||
/*
|
||||
* ohci1394.h - driver for OHCI 1394 boards
|
||||
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
|
||||
* Gord Peters <GordPeters@smarttech.com>
|
||||
*
|
||||
* 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 _OHCI1394_H
|
||||
#define _OHCI1394_H
|
||||
|
||||
#include "ieee1394_types.h"
|
||||
#include <asm/io.h>
|
||||
|
||||
#define OHCI1394_DRIVER_NAME "ohci1394"
|
||||
|
||||
#define OHCI1394_MAX_AT_REQ_RETRIES 0xf
|
||||
#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
|
||||
#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
|
||||
#define OHCI1394_MAX_SELF_ID_ERRORS 16
|
||||
|
||||
#define AR_REQ_NUM_DESC 4 /* number of AR req descriptors */
|
||||
#define AR_REQ_BUF_SIZE PAGE_SIZE /* size of AR req buffers */
|
||||
#define AR_REQ_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
|
||||
|
||||
#define AR_RESP_NUM_DESC 4 /* number of AR resp descriptors */
|
||||
#define AR_RESP_BUF_SIZE PAGE_SIZE /* size of AR resp buffers */
|
||||
#define AR_RESP_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
|
||||
|
||||
#define IR_NUM_DESC 16 /* number of IR descriptors */
|
||||
#define IR_BUF_SIZE PAGE_SIZE /* 4096 bytes/buffer */
|
||||
#define IR_SPLIT_BUF_SIZE PAGE_SIZE /* split packet buffer */
|
||||
|
||||
#define IT_NUM_DESC 16 /* number of IT descriptors */
|
||||
|
||||
#define AT_REQ_NUM_DESC 32 /* number of AT req descriptors */
|
||||
#define AT_RESP_NUM_DESC 32 /* number of AT resp descriptors */
|
||||
|
||||
#define OHCI_LOOP_COUNT 100 /* Number of loops for reg read waits */
|
||||
|
||||
#define OHCI_CONFIG_ROM_LEN 1024 /* Length of the mapped configrom space */
|
||||
|
||||
#define OHCI1394_SI_DMA_BUF_SIZE 8192 /* length of the selfid buffer */
|
||||
|
||||
/* PCI configuration space addresses */
|
||||
#define OHCI1394_PCI_HCI_Control 0x40
|
||||
|
||||
struct dma_cmd {
|
||||
u32 control;
|
||||
u32 address;
|
||||
u32 branchAddress;
|
||||
u32 status;
|
||||
};
|
||||
|
||||
/*
|
||||
* FIXME:
|
||||
* It is important that a single at_dma_prg does not cross a page boundary
|
||||
* The proper way to do it would be to do the check dynamically as the
|
||||
* programs are inserted into the AT fifo.
|
||||
*/
|
||||
struct at_dma_prg {
|
||||
struct dma_cmd begin;
|
||||
quadlet_t data[4];
|
||||
struct dma_cmd end;
|
||||
quadlet_t pad[4]; /* FIXME: quick hack for memory alignment */
|
||||
};
|
||||
|
||||
/* identify whether a DMA context is asynchronous or isochronous */
|
||||
enum context_type { DMA_CTX_ASYNC_REQ, DMA_CTX_ASYNC_RESP, DMA_CTX_ISO };
|
||||
|
||||
/* DMA receive context */
|
||||
struct dma_rcv_ctx {
|
||||
struct ti_ohci *ohci;
|
||||
enum context_type type;
|
||||
int ctx;
|
||||
unsigned int num_desc;
|
||||
|
||||
unsigned int buf_size;
|
||||
unsigned int split_buf_size;
|
||||
|
||||
/* dma block descriptors */
|
||||
struct dma_cmd **prg_cpu;
|
||||
dma_addr_t *prg_bus;
|
||||
struct pci_pool *prg_pool;
|
||||
|
||||
/* dma buffers */
|
||||
quadlet_t **buf_cpu;
|
||||
dma_addr_t *buf_bus;
|
||||
|
||||
unsigned int buf_ind;
|
||||
unsigned int buf_offset;
|
||||
quadlet_t *spb;
|
||||
spinlock_t lock;
|
||||
struct tasklet_struct task;
|
||||
int ctrlClear;
|
||||
int ctrlSet;
|
||||
int cmdPtr;
|
||||
int ctxtMatch;
|
||||
};
|
||||
|
||||
/* DMA transmit context */
|
||||
struct dma_trm_ctx {
|
||||
struct ti_ohci *ohci;
|
||||
enum context_type type;
|
||||
int ctx;
|
||||
unsigned int num_desc;
|
||||
|
||||
/* dma block descriptors */
|
||||
struct at_dma_prg **prg_cpu;
|
||||
dma_addr_t *prg_bus;
|
||||
struct pci_pool *prg_pool;
|
||||
|
||||
unsigned int prg_ind;
|
||||
unsigned int sent_ind;
|
||||
int free_prgs;
|
||||
quadlet_t *branchAddrPtr;
|
||||
|
||||
/* list of packets inserted in the AT FIFO */
|
||||
struct list_head fifo_list;
|
||||
|
||||
/* list of pending packets to be inserted in the AT FIFO */
|
||||
struct list_head pending_list;
|
||||
|
||||
spinlock_t lock;
|
||||
struct tasklet_struct task;
|
||||
int ctrlClear;
|
||||
int ctrlSet;
|
||||
int cmdPtr;
|
||||
};
|
||||
|
||||
struct ohci1394_iso_tasklet {
|
||||
struct tasklet_struct tasklet;
|
||||
struct list_head link;
|
||||
int context;
|
||||
enum { OHCI_ISO_TRANSMIT, OHCI_ISO_RECEIVE,
|
||||
OHCI_ISO_MULTICHANNEL_RECEIVE } type;
|
||||
};
|
||||
|
||||
struct ti_ohci {
|
||||
struct pci_dev *dev;
|
||||
|
||||
enum {
|
||||
OHCI_INIT_ALLOC_HOST,
|
||||
OHCI_INIT_HAVE_MEM_REGION,
|
||||
OHCI_INIT_HAVE_IOMAPPING,
|
||||
OHCI_INIT_HAVE_CONFIG_ROM_BUFFER,
|
||||
OHCI_INIT_HAVE_SELFID_BUFFER,
|
||||
OHCI_INIT_HAVE_TXRX_BUFFERS__MAYBE,
|
||||
OHCI_INIT_HAVE_IRQ,
|
||||
OHCI_INIT_DONE,
|
||||
} init_state;
|
||||
|
||||
/* remapped memory spaces */
|
||||
void __iomem *registers;
|
||||
|
||||
/* dma buffer for self-id packets */
|
||||
quadlet_t *selfid_buf_cpu;
|
||||
dma_addr_t selfid_buf_bus;
|
||||
|
||||
/* buffer for csr config rom */
|
||||
quadlet_t *csr_config_rom_cpu;
|
||||
dma_addr_t csr_config_rom_bus;
|
||||
int csr_config_rom_length;
|
||||
|
||||
unsigned int max_packet_size;
|
||||
|
||||
/* async receive */
|
||||
struct dma_rcv_ctx ar_resp_context;
|
||||
struct dma_rcv_ctx ar_req_context;
|
||||
|
||||
/* async transmit */
|
||||
struct dma_trm_ctx at_resp_context;
|
||||
struct dma_trm_ctx at_req_context;
|
||||
|
||||
/* iso receive */
|
||||
int nb_iso_rcv_ctx;
|
||||
unsigned long ir_ctx_usage; /* use test_and_set_bit() for atomicity */
|
||||
unsigned long ir_multichannel_used; /* ditto */
|
||||
spinlock_t IR_channel_lock;
|
||||
|
||||
/* iso transmit */
|
||||
int nb_iso_xmit_ctx;
|
||||
unsigned long it_ctx_usage; /* use test_and_set_bit() for atomicity */
|
||||
|
||||
u64 ISO_channel_usage;
|
||||
|
||||
/* IEEE-1394 part follows */
|
||||
struct hpsb_host *host;
|
||||
|
||||
int phyid, isroot;
|
||||
|
||||
spinlock_t phy_reg_lock;
|
||||
spinlock_t event_lock;
|
||||
|
||||
int self_id_errors;
|
||||
|
||||
/* Tasklets for iso receive and transmit, used by video1394
|
||||
* and dv1394 */
|
||||
struct list_head iso_tasklet_list;
|
||||
spinlock_t iso_tasklet_list_lock;
|
||||
|
||||
/* Swap the selfid buffer? */
|
||||
unsigned int selfid_swap:1;
|
||||
/* Some Apple chipset seem to swap incoming headers for us */
|
||||
unsigned int no_swap_incoming:1;
|
||||
|
||||
/* Force extra paranoia checking on bus-reset handling */
|
||||
unsigned int check_busreset:1;
|
||||
};
|
||||
|
||||
static inline int cross_bound(unsigned long addr, unsigned int size)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
if (size > PAGE_SIZE)
|
||||
return 1;
|
||||
|
||||
if (addr >> PAGE_SHIFT != (addr + size - 1) >> PAGE_SHIFT)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Register read and write helper functions.
|
||||
*/
|
||||
static inline void reg_write(const struct ti_ohci *ohci, int offset, u32 data)
|
||||
{
|
||||
writel(data, ohci->registers + offset);
|
||||
}
|
||||
|
||||
static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
|
||||
{
|
||||
return readl(ohci->registers + offset);
|
||||
}
|
||||
|
||||
|
||||
/* 2 KiloBytes of register space */
|
||||
#define OHCI1394_REGISTER_SIZE 0x800
|
||||
|
||||
/* Offsets relative to context bases defined below */
|
||||
|
||||
#define OHCI1394_ContextControlSet 0x000
|
||||
#define OHCI1394_ContextControlClear 0x004
|
||||
#define OHCI1394_ContextCommandPtr 0x00C
|
||||
|
||||
/* register map */
|
||||
#define OHCI1394_Version 0x000
|
||||
#define OHCI1394_GUID_ROM 0x004
|
||||
#define OHCI1394_ATRetries 0x008
|
||||
#define OHCI1394_CSRData 0x00C
|
||||
#define OHCI1394_CSRCompareData 0x010
|
||||
#define OHCI1394_CSRControl 0x014
|
||||
#define OHCI1394_ConfigROMhdr 0x018
|
||||
#define OHCI1394_BusID 0x01C
|
||||
#define OHCI1394_BusOptions 0x020
|
||||
#define OHCI1394_GUIDHi 0x024
|
||||
#define OHCI1394_GUIDLo 0x028
|
||||
#define OHCI1394_ConfigROMmap 0x034
|
||||
#define OHCI1394_PostedWriteAddressLo 0x038
|
||||
#define OHCI1394_PostedWriteAddressHi 0x03C
|
||||
#define OHCI1394_VendorID 0x040
|
||||
#define OHCI1394_HCControlSet 0x050
|
||||
#define OHCI1394_HCControlClear 0x054
|
||||
#define OHCI1394_HCControl_noByteSwap 0x40000000
|
||||
#define OHCI1394_HCControl_programPhyEnable 0x00800000
|
||||
#define OHCI1394_HCControl_aPhyEnhanceEnable 0x00400000
|
||||
#define OHCI1394_HCControl_LPS 0x00080000
|
||||
#define OHCI1394_HCControl_postedWriteEnable 0x00040000
|
||||
#define OHCI1394_HCControl_linkEnable 0x00020000
|
||||
#define OHCI1394_HCControl_softReset 0x00010000
|
||||
#define OHCI1394_SelfIDBuffer 0x064
|
||||
#define OHCI1394_SelfIDCount 0x068
|
||||
#define OHCI1394_IRMultiChanMaskHiSet 0x070
|
||||
#define OHCI1394_IRMultiChanMaskHiClear 0x074
|
||||
#define OHCI1394_IRMultiChanMaskLoSet 0x078
|
||||
#define OHCI1394_IRMultiChanMaskLoClear 0x07C
|
||||
#define OHCI1394_IntEventSet 0x080
|
||||
#define OHCI1394_IntEventClear 0x084
|
||||
#define OHCI1394_IntMaskSet 0x088
|
||||
#define OHCI1394_IntMaskClear 0x08C
|
||||
#define OHCI1394_IsoXmitIntEventSet 0x090
|
||||
#define OHCI1394_IsoXmitIntEventClear 0x094
|
||||
#define OHCI1394_IsoXmitIntMaskSet 0x098
|
||||
#define OHCI1394_IsoXmitIntMaskClear 0x09C
|
||||
#define OHCI1394_IsoRecvIntEventSet 0x0A0
|
||||
#define OHCI1394_IsoRecvIntEventClear 0x0A4
|
||||
#define OHCI1394_IsoRecvIntMaskSet 0x0A8
|
||||
#define OHCI1394_IsoRecvIntMaskClear 0x0AC
|
||||
#define OHCI1394_InitialBandwidthAvailable 0x0B0
|
||||
#define OHCI1394_InitialChannelsAvailableHi 0x0B4
|
||||
#define OHCI1394_InitialChannelsAvailableLo 0x0B8
|
||||
#define OHCI1394_FairnessControl 0x0DC
|
||||
#define OHCI1394_LinkControlSet 0x0E0
|
||||
#define OHCI1394_LinkControlClear 0x0E4
|
||||
#define OHCI1394_LinkControl_RcvSelfID 0x00000200
|
||||
#define OHCI1394_LinkControl_RcvPhyPkt 0x00000400
|
||||
#define OHCI1394_LinkControl_CycleTimerEnable 0x00100000
|
||||
#define OHCI1394_LinkControl_CycleMaster 0x00200000
|
||||
#define OHCI1394_LinkControl_CycleSource 0x00400000
|
||||
#define OHCI1394_NodeID 0x0E8
|
||||
#define OHCI1394_PhyControl 0x0EC
|
||||
#define OHCI1394_IsochronousCycleTimer 0x0F0
|
||||
#define OHCI1394_AsReqFilterHiSet 0x100
|
||||
#define OHCI1394_AsReqFilterHiClear 0x104
|
||||
#define OHCI1394_AsReqFilterLoSet 0x108
|
||||
#define OHCI1394_AsReqFilterLoClear 0x10C
|
||||
#define OHCI1394_PhyReqFilterHiSet 0x110
|
||||
#define OHCI1394_PhyReqFilterHiClear 0x114
|
||||
#define OHCI1394_PhyReqFilterLoSet 0x118
|
||||
#define OHCI1394_PhyReqFilterLoClear 0x11C
|
||||
#define OHCI1394_PhyUpperBound 0x120
|
||||
|
||||
#define OHCI1394_AsReqTrContextBase 0x180
|
||||
#define OHCI1394_AsReqTrContextControlSet 0x180
|
||||
#define OHCI1394_AsReqTrContextControlClear 0x184
|
||||
#define OHCI1394_AsReqTrCommandPtr 0x18C
|
||||
|
||||
#define OHCI1394_AsRspTrContextBase 0x1A0
|
||||
#define OHCI1394_AsRspTrContextControlSet 0x1A0
|
||||
#define OHCI1394_AsRspTrContextControlClear 0x1A4
|
||||
#define OHCI1394_AsRspTrCommandPtr 0x1AC
|
||||
|
||||
#define OHCI1394_AsReqRcvContextBase 0x1C0
|
||||
#define OHCI1394_AsReqRcvContextControlSet 0x1C0
|
||||
#define OHCI1394_AsReqRcvContextControlClear 0x1C4
|
||||
#define OHCI1394_AsReqRcvCommandPtr 0x1CC
|
||||
|
||||
#define OHCI1394_AsRspRcvContextBase 0x1E0
|
||||
#define OHCI1394_AsRspRcvContextControlSet 0x1E0
|
||||
#define OHCI1394_AsRspRcvContextControlClear 0x1E4
|
||||
#define OHCI1394_AsRspRcvCommandPtr 0x1EC
|
||||
|
||||
/* Isochronous transmit registers */
|
||||
/* Add (16 * n) for context n */
|
||||
#define OHCI1394_IsoXmitContextBase 0x200
|
||||
#define OHCI1394_IsoXmitContextControlSet 0x200
|
||||
#define OHCI1394_IsoXmitContextControlClear 0x204
|
||||
#define OHCI1394_IsoXmitCommandPtr 0x20C
|
||||
|
||||
/* Isochronous receive registers */
|
||||
/* Add (32 * n) for context n */
|
||||
#define OHCI1394_IsoRcvContextBase 0x400
|
||||
#define OHCI1394_IsoRcvContextControlSet 0x400
|
||||
#define OHCI1394_IsoRcvContextControlClear 0x404
|
||||
#define OHCI1394_IsoRcvCommandPtr 0x40C
|
||||
#define OHCI1394_IsoRcvContextMatch 0x410
|
||||
|
||||
/* Interrupts Mask/Events */
|
||||
|
||||
#define OHCI1394_reqTxComplete 0x00000001
|
||||
#define OHCI1394_respTxComplete 0x00000002
|
||||
#define OHCI1394_ARRQ 0x00000004
|
||||
#define OHCI1394_ARRS 0x00000008
|
||||
#define OHCI1394_RQPkt 0x00000010
|
||||
#define OHCI1394_RSPkt 0x00000020
|
||||
#define OHCI1394_isochTx 0x00000040
|
||||
#define OHCI1394_isochRx 0x00000080
|
||||
#define OHCI1394_postedWriteErr 0x00000100
|
||||
#define OHCI1394_lockRespErr 0x00000200
|
||||
#define OHCI1394_selfIDComplete 0x00010000
|
||||
#define OHCI1394_busReset 0x00020000
|
||||
#define OHCI1394_phy 0x00080000
|
||||
#define OHCI1394_cycleSynch 0x00100000
|
||||
#define OHCI1394_cycle64Seconds 0x00200000
|
||||
#define OHCI1394_cycleLost 0x00400000
|
||||
#define OHCI1394_cycleInconsistent 0x00800000
|
||||
#define OHCI1394_unrecoverableError 0x01000000
|
||||
#define OHCI1394_cycleTooLong 0x02000000
|
||||
#define OHCI1394_phyRegRcvd 0x04000000
|
||||
#define OHCI1394_masterIntEnable 0x80000000
|
||||
|
||||
/* DMA Control flags */
|
||||
#define DMA_CTL_OUTPUT_MORE 0x00000000
|
||||
#define DMA_CTL_OUTPUT_LAST 0x10000000
|
||||
#define DMA_CTL_INPUT_MORE 0x20000000
|
||||
#define DMA_CTL_INPUT_LAST 0x30000000
|
||||
#define DMA_CTL_UPDATE 0x08000000
|
||||
#define DMA_CTL_IMMEDIATE 0x02000000
|
||||
#define DMA_CTL_IRQ 0x00300000
|
||||
#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_A 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 occurred while host was
|
||||
reading a descriptor block */
|
||||
#define EVT_DATA_READ 0x7 /* An error occurred while host controller was
|
||||
attempting to read from host memory in the data
|
||||
stage of descriptor processing */
|
||||
#define EVT_DATA_WRITE 0x8 /* An error occurred 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 EVT_TIMEOUT 0xa /* Indicates that the asynchronous transmit response
|
||||
packet expired and was not transmitted, or that an
|
||||
IT DMA context experienced a skip processing overflow */
|
||||
#define EVT_TCODE_ERR 0xb /* A bad tCode is associated with this packet.
|
||||
The packet was flushed */
|
||||
#define EVT_RESERVED_B 0xc /* Reserved, not used !!! */
|
||||
#define EVT_RESERVED_C 0xd /* Reserved, not used !!! */
|
||||
#define EVT_UNKNOWN 0xe /* An error condition has occurred that cannot be
|
||||
represented by any other event codes defined herein. */
|
||||
#define EVT_FLUSHED 0xf /* Send by the link side of output FIFO when asynchronous
|
||||
packets are being flushed due to a bus reset. */
|
||||
|
||||
#define OHCI1394_TCODE_PHY 0xE
|
||||
|
||||
/* Node offset map (phys DMA area, posted write area).
|
||||
* The value of OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED may be modified but must
|
||||
* be lower than OHCI1394_MIDDLE_ADDRESS_SPACE.
|
||||
* OHCI1394_PHYS_UPPER_BOUND_FIXED and OHCI1394_MIDDLE_ADDRESS_SPACE are
|
||||
* constants given by the OHCI spec.
|
||||
*/
|
||||
#define OHCI1394_PHYS_UPPER_BOUND_FIXED 0x000100000000ULL /* 4 GB */
|
||||
#define OHCI1394_PHYS_UPPER_BOUND_PROGRAMMED 0x010000000000ULL /* 1 TB */
|
||||
#define OHCI1394_MIDDLE_ADDRESS_SPACE 0xffff00000000ULL
|
||||
|
||||
void ohci1394_init_iso_tasklet(struct ohci1394_iso_tasklet *tasklet,
|
||||
int type,
|
||||
void (*func)(unsigned long),
|
||||
unsigned long data);
|
||||
int ohci1394_register_iso_tasklet(struct ti_ohci *ohci,
|
||||
struct ohci1394_iso_tasklet *tasklet);
|
||||
void ohci1394_unregister_iso_tasklet(struct ti_ohci *ohci,
|
||||
struct ohci1394_iso_tasklet *tasklet);
|
||||
int ohci1394_stop_context(struct ti_ohci *ohci, int reg, char *msg);
|
||||
struct ti_ohci *ohci1394_get_struct(int card_num);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,468 +0,0 @@
|
|||
#ifndef __PCILYNX_H__
|
||||
#define __PCILYNX_H__
|
||||
|
||||
|
||||
#define PCILYNX_DRIVER_NAME "pcilynx"
|
||||
#define PCILYNX_MAJOR 177
|
||||
|
||||
#define PCILYNX_MINOR_AUX_START 0
|
||||
#define PCILYNX_MINOR_ROM_START 16
|
||||
#define PCILYNX_MINOR_RAM_START 32
|
||||
|
||||
#define PCILYNX_MAX_REGISTER 0xfff
|
||||
#define PCILYNX_MAX_MEMORY 0xffff
|
||||
|
||||
#define PCI_DEVICE_ID_TI_PCILYNX 0x8000
|
||||
#define MAX_PCILYNX_CARDS 4
|
||||
#define LOCALRAM_SIZE 4096
|
||||
|
||||
#define NUM_ISORCV_PCL 4
|
||||
#define MAX_ISORCV_SIZE 2048
|
||||
#define ISORCV_PER_PAGE (PAGE_SIZE / MAX_ISORCV_SIZE)
|
||||
#define ISORCV_PAGES (NUM_ISORCV_PCL / ISORCV_PER_PAGE)
|
||||
|
||||
#define CHANNEL_LOCALBUS 0
|
||||
#define CHANNEL_ASYNC_RCV 1
|
||||
#define CHANNEL_ISO_RCV 2
|
||||
#define CHANNEL_ASYNC_SEND 3
|
||||
#define CHANNEL_ISO_SEND 4
|
||||
|
||||
#define PCILYNX_CONFIG_ROM_LENGTH 1024
|
||||
|
||||
typedef int pcl_t;
|
||||
|
||||
struct ti_lynx {
|
||||
int id; /* sequential card number */
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
struct pci_dev *dev;
|
||||
|
||||
struct {
|
||||
unsigned reg_1394a:1;
|
||||
u32 vendor;
|
||||
u32 product;
|
||||
} phyic;
|
||||
|
||||
enum { clear, have_intr, have_aux_buf, have_pcl_mem,
|
||||
have_1394_buffers, have_iomappings, is_host } state;
|
||||
|
||||
/* remapped memory spaces */
|
||||
void __iomem *registers;
|
||||
void __iomem *local_rom;
|
||||
void __iomem *local_ram;
|
||||
void __iomem *aux_port;
|
||||
__be32 bus_info_block[5];
|
||||
|
||||
/*
|
||||
* use local RAM of LOCALRAM_SIZE bytes for PCLs, which allows for
|
||||
* LOCALRAM_SIZE * 8 PCLs (each sized 128 bytes);
|
||||
* the following is an allocation bitmap
|
||||
*/
|
||||
u8 pcl_bmap[LOCALRAM_SIZE / 1024];
|
||||
|
||||
/* point to PCLs memory area if needed */
|
||||
void *pcl_mem;
|
||||
dma_addr_t pcl_mem_dma;
|
||||
|
||||
/* PCLs for local mem / aux transfers */
|
||||
pcl_t dmem_pcl;
|
||||
|
||||
/* IEEE-1394 part follows */
|
||||
struct hpsb_host *host;
|
||||
|
||||
int phyid, isroot;
|
||||
int selfid_size;
|
||||
int phy_reg0;
|
||||
|
||||
spinlock_t phy_reg_lock;
|
||||
|
||||
pcl_t rcv_pcl_start, rcv_pcl;
|
||||
void *rcv_page;
|
||||
dma_addr_t rcv_page_dma;
|
||||
int rcv_active;
|
||||
|
||||
struct lynx_send_data {
|
||||
pcl_t pcl_start, pcl;
|
||||
struct list_head queue;
|
||||
struct list_head pcl_queue; /* this queue contains at most one packet */
|
||||
spinlock_t queue_lock;
|
||||
dma_addr_t header_dma, data_dma;
|
||||
int channel;
|
||||
} async, iso_send;
|
||||
|
||||
struct {
|
||||
pcl_t pcl[NUM_ISORCV_PCL];
|
||||
u32 stat[NUM_ISORCV_PCL];
|
||||
void *page[ISORCV_PAGES];
|
||||
dma_addr_t page_dma[ISORCV_PAGES];
|
||||
pcl_t pcl_start;
|
||||
int chan_count;
|
||||
int next, last, used, running;
|
||||
struct tasklet_struct tq;
|
||||
spinlock_t lock;
|
||||
} iso_rcv;
|
||||
|
||||
u32 i2c_driven_state; /* the state we currently drive the Serial EEPROM Control register */
|
||||
};
|
||||
|
||||
/* the per-file data structure for mem space access */
|
||||
struct memdata {
|
||||
struct ti_lynx *lynx;
|
||||
int cid;
|
||||
atomic_t aux_intr_last_seen;
|
||||
/* enum values are the same as LBUS_ADDR_SEL_* values below */
|
||||
enum { rom = 0x10000, aux = 0x20000, ram = 0 } type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Register read and write helper functions.
|
||||
*/
|
||||
static inline void reg_write(const struct ti_lynx *lynx, int offset, u32 data)
|
||||
{
|
||||
writel(data, lynx->registers + offset);
|
||||
}
|
||||
|
||||
static inline u32 reg_read(const struct ti_lynx *lynx, int offset)
|
||||
{
|
||||
return readl(lynx->registers + offset);
|
||||
}
|
||||
|
||||
static inline void reg_set_bits(const struct ti_lynx *lynx, int offset,
|
||||
u32 mask)
|
||||
{
|
||||
reg_write(lynx, offset, (reg_read(lynx, offset) | mask));
|
||||
}
|
||||
|
||||
static inline void reg_clear_bits(const struct ti_lynx *lynx, int offset,
|
||||
u32 mask)
|
||||
{
|
||||
reg_write(lynx, offset, (reg_read(lynx, offset) & ~mask));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* chip register definitions follow */
|
||||
|
||||
#define PCI_LATENCY_CACHELINE 0x0c
|
||||
|
||||
#define MISC_CONTROL 0x40
|
||||
#define MISC_CONTROL_SWRESET (1<<0)
|
||||
|
||||
#define SERIAL_EEPROM_CONTROL 0x44
|
||||
|
||||
#define PCI_INT_STATUS 0x48
|
||||
#define PCI_INT_ENABLE 0x4c
|
||||
/* status and enable have identical bit numbers */
|
||||
#define PCI_INT_INT_PEND (1<<31)
|
||||
#define PCI_INT_FORCED_INT (1<<30)
|
||||
#define PCI_INT_SLV_ADR_PERR (1<<28)
|
||||
#define PCI_INT_SLV_DAT_PERR (1<<27)
|
||||
#define PCI_INT_MST_DAT_PERR (1<<26)
|
||||
#define PCI_INT_MST_DEV_TIMEOUT (1<<25)
|
||||
#define PCI_INT_INTERNAL_SLV_TIMEOUT (1<<23)
|
||||
#define PCI_INT_AUX_TIMEOUT (1<<18)
|
||||
#define PCI_INT_AUX_INT (1<<17)
|
||||
#define PCI_INT_1394 (1<<16)
|
||||
#define PCI_INT_DMA4_PCL (1<<9)
|
||||
#define PCI_INT_DMA4_HLT (1<<8)
|
||||
#define PCI_INT_DMA3_PCL (1<<7)
|
||||
#define PCI_INT_DMA3_HLT (1<<6)
|
||||
#define PCI_INT_DMA2_PCL (1<<5)
|
||||
#define PCI_INT_DMA2_HLT (1<<4)
|
||||
#define PCI_INT_DMA1_PCL (1<<3)
|
||||
#define PCI_INT_DMA1_HLT (1<<2)
|
||||
#define PCI_INT_DMA0_PCL (1<<1)
|
||||
#define PCI_INT_DMA0_HLT (1<<0)
|
||||
/* all DMA interrupts combined: */
|
||||
#define PCI_INT_DMA_ALL 0x3ff
|
||||
|
||||
#define PCI_INT_DMA_HLT(chan) (1 << (chan * 2))
|
||||
#define PCI_INT_DMA_PCL(chan) (1 << (chan * 2 + 1))
|
||||
|
||||
#define LBUS_ADDR 0xb4
|
||||
#define LBUS_ADDR_SEL_RAM (0x0<<16)
|
||||
#define LBUS_ADDR_SEL_ROM (0x1<<16)
|
||||
#define LBUS_ADDR_SEL_AUX (0x2<<16)
|
||||
#define LBUS_ADDR_SEL_ZV (0x3<<16)
|
||||
|
||||
#define GPIO_CTRL_A 0xb8
|
||||
#define GPIO_CTRL_B 0xbc
|
||||
#define GPIO_DATA_BASE 0xc0
|
||||
|
||||
#define DMA_BREG(base, chan) (base + chan * 0x20)
|
||||
#define DMA_SREG(base, chan) (base + chan * 0x10)
|
||||
|
||||
#define DMA0_PREV_PCL 0x100
|
||||
#define DMA1_PREV_PCL 0x120
|
||||
#define DMA2_PREV_PCL 0x140
|
||||
#define DMA3_PREV_PCL 0x160
|
||||
#define DMA4_PREV_PCL 0x180
|
||||
#define DMA_PREV_PCL(chan) (DMA_BREG(DMA0_PREV_PCL, chan))
|
||||
|
||||
#define DMA0_CURRENT_PCL 0x104
|
||||
#define DMA1_CURRENT_PCL 0x124
|
||||
#define DMA2_CURRENT_PCL 0x144
|
||||
#define DMA3_CURRENT_PCL 0x164
|
||||
#define DMA4_CURRENT_PCL 0x184
|
||||
#define DMA_CURRENT_PCL(chan) (DMA_BREG(DMA0_CURRENT_PCL, chan))
|
||||
|
||||
#define DMA0_CHAN_STAT 0x10c
|
||||
#define DMA1_CHAN_STAT 0x12c
|
||||
#define DMA2_CHAN_STAT 0x14c
|
||||
#define DMA3_CHAN_STAT 0x16c
|
||||
#define DMA4_CHAN_STAT 0x18c
|
||||
#define DMA_CHAN_STAT(chan) (DMA_BREG(DMA0_CHAN_STAT, chan))
|
||||
/* CHAN_STATUS registers share bits */
|
||||
#define DMA_CHAN_STAT_SELFID (1<<31)
|
||||
#define DMA_CHAN_STAT_ISOPKT (1<<30)
|
||||
#define DMA_CHAN_STAT_PCIERR (1<<29)
|
||||
#define DMA_CHAN_STAT_PKTERR (1<<28)
|
||||
#define DMA_CHAN_STAT_PKTCMPL (1<<27)
|
||||
#define DMA_CHAN_STAT_SPECIALACK (1<<14)
|
||||
|
||||
|
||||
#define DMA0_CHAN_CTRL 0x110
|
||||
#define DMA1_CHAN_CTRL 0x130
|
||||
#define DMA2_CHAN_CTRL 0x150
|
||||
#define DMA3_CHAN_CTRL 0x170
|
||||
#define DMA4_CHAN_CTRL 0x190
|
||||
#define DMA_CHAN_CTRL(chan) (DMA_BREG(DMA0_CHAN_CTRL, chan))
|
||||
/* CHAN_CTRL registers share bits */
|
||||
#define DMA_CHAN_CTRL_ENABLE (1<<31)
|
||||
#define DMA_CHAN_CTRL_BUSY (1<<30)
|
||||
#define DMA_CHAN_CTRL_LINK (1<<29)
|
||||
|
||||
#define DMA0_READY 0x114
|
||||
#define DMA1_READY 0x134
|
||||
#define DMA2_READY 0x154
|
||||
#define DMA3_READY 0x174
|
||||
#define DMA4_READY 0x194
|
||||
#define DMA_READY(chan) (DMA_BREG(DMA0_READY, chan))
|
||||
|
||||
#define DMA_GLOBAL_REGISTER 0x908
|
||||
|
||||
#define FIFO_SIZES 0xa00
|
||||
|
||||
#define FIFO_CONTROL 0xa10
|
||||
#define FIFO_CONTROL_GRF_FLUSH (1<<4)
|
||||
#define FIFO_CONTROL_ITF_FLUSH (1<<3)
|
||||
#define FIFO_CONTROL_ATF_FLUSH (1<<2)
|
||||
|
||||
#define FIFO_XMIT_THRESHOLD 0xa14
|
||||
|
||||
#define DMA0_WORD0_CMP_VALUE 0xb00
|
||||
#define DMA1_WORD0_CMP_VALUE 0xb10
|
||||
#define DMA2_WORD0_CMP_VALUE 0xb20
|
||||
#define DMA3_WORD0_CMP_VALUE 0xb30
|
||||
#define DMA4_WORD0_CMP_VALUE 0xb40
|
||||
#define DMA_WORD0_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD0_CMP_VALUE, chan))
|
||||
|
||||
#define DMA0_WORD0_CMP_ENABLE 0xb04
|
||||
#define DMA1_WORD0_CMP_ENABLE 0xb14
|
||||
#define DMA2_WORD0_CMP_ENABLE 0xb24
|
||||
#define DMA3_WORD0_CMP_ENABLE 0xb34
|
||||
#define DMA4_WORD0_CMP_ENABLE 0xb44
|
||||
#define DMA_WORD0_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD0_CMP_ENABLE,chan))
|
||||
|
||||
#define DMA0_WORD1_CMP_VALUE 0xb08
|
||||
#define DMA1_WORD1_CMP_VALUE 0xb18
|
||||
#define DMA2_WORD1_CMP_VALUE 0xb28
|
||||
#define DMA3_WORD1_CMP_VALUE 0xb38
|
||||
#define DMA4_WORD1_CMP_VALUE 0xb48
|
||||
#define DMA_WORD1_CMP_VALUE(chan) (DMA_SREG(DMA0_WORD1_CMP_VALUE, chan))
|
||||
|
||||
#define DMA0_WORD1_CMP_ENABLE 0xb0c
|
||||
#define DMA1_WORD1_CMP_ENABLE 0xb1c
|
||||
#define DMA2_WORD1_CMP_ENABLE 0xb2c
|
||||
#define DMA3_WORD1_CMP_ENABLE 0xb3c
|
||||
#define DMA4_WORD1_CMP_ENABLE 0xb4c
|
||||
#define DMA_WORD1_CMP_ENABLE(chan) (DMA_SREG(DMA0_WORD1_CMP_ENABLE,chan))
|
||||
/* word 1 compare enable flags */
|
||||
#define DMA_WORD1_CMP_MATCH_OTHERBUS (1<<15)
|
||||
#define DMA_WORD1_CMP_MATCH_BROADCAST (1<<14)
|
||||
#define DMA_WORD1_CMP_MATCH_BUS_BCAST (1<<13)
|
||||
#define DMA_WORD1_CMP_MATCH_LOCAL_NODE (1<<12)
|
||||
#define DMA_WORD1_CMP_MATCH_EXACT (1<<11)
|
||||
#define DMA_WORD1_CMP_ENABLE_SELF_ID (1<<10)
|
||||
#define DMA_WORD1_CMP_ENABLE_MASTER (1<<8)
|
||||
|
||||
#define LINK_ID 0xf00
|
||||
#define LINK_ID_BUS(id) (id<<22)
|
||||
#define LINK_ID_NODE(id) (id<<16)
|
||||
|
||||
#define LINK_CONTROL 0xf04
|
||||
#define LINK_CONTROL_BUSY (1<<29)
|
||||
#define LINK_CONTROL_TX_ISO_EN (1<<26)
|
||||
#define LINK_CONTROL_RX_ISO_EN (1<<25)
|
||||
#define LINK_CONTROL_TX_ASYNC_EN (1<<24)
|
||||
#define LINK_CONTROL_RX_ASYNC_EN (1<<23)
|
||||
#define LINK_CONTROL_RESET_TX (1<<21)
|
||||
#define LINK_CONTROL_RESET_RX (1<<20)
|
||||
#define LINK_CONTROL_CYCMASTER (1<<11)
|
||||
#define LINK_CONTROL_CYCSOURCE (1<<10)
|
||||
#define LINK_CONTROL_CYCTIMEREN (1<<9)
|
||||
#define LINK_CONTROL_RCV_CMP_VALID (1<<7)
|
||||
#define LINK_CONTROL_SNOOP_ENABLE (1<<6)
|
||||
|
||||
#define CYCLE_TIMER 0xf08
|
||||
|
||||
#define LINK_PHY 0xf0c
|
||||
#define LINK_PHY_READ (1<<31)
|
||||
#define LINK_PHY_WRITE (1<<30)
|
||||
#define LINK_PHY_ADDR(addr) (addr<<24)
|
||||
#define LINK_PHY_WDATA(data) (data<<16)
|
||||
#define LINK_PHY_RADDR(addr) (addr<<8)
|
||||
|
||||
|
||||
#define LINK_INT_STATUS 0xf14
|
||||
#define LINK_INT_ENABLE 0xf18
|
||||
/* status and enable have identical bit numbers */
|
||||
#define LINK_INT_LINK_INT (1<<31)
|
||||
#define LINK_INT_PHY_TIMEOUT (1<<30)
|
||||
#define LINK_INT_PHY_REG_RCVD (1<<29)
|
||||
#define LINK_INT_PHY_BUSRESET (1<<28)
|
||||
#define LINK_INT_TX_RDY (1<<26)
|
||||
#define LINK_INT_RX_DATA_RDY (1<<25)
|
||||
#define LINK_INT_ISO_STUCK (1<<20)
|
||||
#define LINK_INT_ASYNC_STUCK (1<<19)
|
||||
#define LINK_INT_SENT_REJECT (1<<17)
|
||||
#define LINK_INT_HDR_ERR (1<<16)
|
||||
#define LINK_INT_TX_INVALID_TC (1<<15)
|
||||
#define LINK_INT_CYC_SECOND (1<<11)
|
||||
#define LINK_INT_CYC_START (1<<10)
|
||||
#define LINK_INT_CYC_DONE (1<<9)
|
||||
#define LINK_INT_CYC_PENDING (1<<8)
|
||||
#define LINK_INT_CYC_LOST (1<<7)
|
||||
#define LINK_INT_CYC_ARB_FAILED (1<<6)
|
||||
#define LINK_INT_GRF_OVERFLOW (1<<5)
|
||||
#define LINK_INT_ITF_UNDERFLOW (1<<4)
|
||||
#define LINK_INT_ATF_UNDERFLOW (1<<3)
|
||||
#define LINK_INT_ISOARB_FAILED (1<<0)
|
||||
|
||||
/* PHY specifics */
|
||||
#define PHY_VENDORID_TI 0x800028
|
||||
#define PHY_PRODUCTID_TSB41LV03 0x000000
|
||||
|
||||
|
||||
/* this is the physical layout of a PCL, its size is 128 bytes */
|
||||
struct ti_pcl {
|
||||
u32 next;
|
||||
u32 async_error_next;
|
||||
u32 user_data;
|
||||
u32 pcl_status;
|
||||
u32 remaining_transfer_count;
|
||||
u32 next_data_buffer;
|
||||
struct {
|
||||
u32 control;
|
||||
u32 pointer;
|
||||
} buffer[13] __attribute__ ((packed));
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#define pcloffs(MEMBER) (offsetof(struct ti_pcl, MEMBER))
|
||||
|
||||
|
||||
static inline void put_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
const struct ti_pcl *pcl)
|
||||
{
|
||||
memcpy_le32((u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
|
||||
(u32 *)pcl, sizeof(struct ti_pcl));
|
||||
}
|
||||
|
||||
static inline void get_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
struct ti_pcl *pcl)
|
||||
{
|
||||
memcpy_le32((u32 *)pcl,
|
||||
(u32 *)(lynx->pcl_mem + pclid * sizeof(struct ti_pcl)),
|
||||
sizeof(struct ti_pcl));
|
||||
}
|
||||
|
||||
static inline u32 pcl_bus(const struct ti_lynx *lynx, pcl_t pclid)
|
||||
{
|
||||
return lynx->pcl_mem_dma + pclid * sizeof(struct ti_pcl);
|
||||
}
|
||||
|
||||
|
||||
#if defined (__BIG_ENDIAN)
|
||||
typedef struct ti_pcl pcltmp_t;
|
||||
|
||||
static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
pcltmp_t *tmp)
|
||||
{
|
||||
get_pcl(lynx, pclid, tmp);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
pcltmp_t *tmp)
|
||||
{
|
||||
put_pcl(lynx, pclid, tmp);
|
||||
}
|
||||
|
||||
#else
|
||||
typedef int pcltmp_t; /* just a dummy */
|
||||
|
||||
static inline struct ti_pcl *edit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
pcltmp_t *tmp)
|
||||
{
|
||||
return lynx->pcl_mem + pclid * sizeof(struct ti_pcl);
|
||||
}
|
||||
|
||||
static inline void commit_pcl(const struct ti_lynx *lynx, pcl_t pclid,
|
||||
pcltmp_t *tmp)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static inline void run_sub_pcl(const struct ti_lynx *lynx, pcl_t pclid, int idx,
|
||||
int dmachan)
|
||||
{
|
||||
reg_write(lynx, DMA0_CURRENT_PCL + dmachan * 0x20,
|
||||
pcl_bus(lynx, pclid) + idx * 4);
|
||||
reg_write(lynx, DMA0_CHAN_CTRL + dmachan * 0x20,
|
||||
DMA_CHAN_CTRL_ENABLE | DMA_CHAN_CTRL_LINK);
|
||||
}
|
||||
|
||||
static inline void run_pcl(const struct ti_lynx *lynx, pcl_t pclid, int dmachan)
|
||||
{
|
||||
run_sub_pcl(lynx, pclid, 0, dmachan);
|
||||
}
|
||||
|
||||
#define PCL_NEXT_INVALID (1<<0)
|
||||
|
||||
/* transfer commands */
|
||||
#define PCL_CMD_RCV (0x1<<24)
|
||||
#define PCL_CMD_RCV_AND_UPDATE (0xa<<24)
|
||||
#define PCL_CMD_XMT (0x2<<24)
|
||||
#define PCL_CMD_UNFXMT (0xc<<24)
|
||||
#define PCL_CMD_PCI_TO_LBUS (0x8<<24)
|
||||
#define PCL_CMD_LBUS_TO_PCI (0x9<<24)
|
||||
|
||||
/* aux commands */
|
||||
#define PCL_CMD_NOP (0x0<<24)
|
||||
#define PCL_CMD_LOAD (0x3<<24)
|
||||
#define PCL_CMD_STOREQ (0x4<<24)
|
||||
#define PCL_CMD_STORED (0xb<<24)
|
||||
#define PCL_CMD_STORE0 (0x5<<24)
|
||||
#define PCL_CMD_STORE1 (0x6<<24)
|
||||
#define PCL_CMD_COMPARE (0xe<<24)
|
||||
#define PCL_CMD_SWAP_COMPARE (0xf<<24)
|
||||
#define PCL_CMD_ADD (0xd<<24)
|
||||
#define PCL_CMD_BRANCH (0x7<<24)
|
||||
|
||||
/* BRANCH condition codes */
|
||||
#define PCL_COND_DMARDY_SET (0x1<<20)
|
||||
#define PCL_COND_DMARDY_CLEAR (0x2<<20)
|
||||
|
||||
#define PCL_GEN_INTR (1<<19)
|
||||
#define PCL_LAST_BUFF (1<<18)
|
||||
#define PCL_LAST_CMD (PCL_LAST_BUFF)
|
||||
#define PCL_WAITSTAT (1<<17)
|
||||
#define PCL_BIGENDIAN (1<<16)
|
||||
#define PCL_ISOMODE (1<<12)
|
||||
|
||||
#endif
|
|
@ -1,81 +0,0 @@
|
|||
#ifndef IEEE1394_RAW1394_PRIVATE_H
|
||||
#define IEEE1394_RAW1394_PRIVATE_H
|
||||
|
||||
/* header for definitions that are private to the raw1394 driver
|
||||
and not visible to user-space */
|
||||
|
||||
#define RAW1394_DEVICE_MAJOR 171
|
||||
#define RAW1394_DEVICE_NAME "raw1394"
|
||||
|
||||
#define RAW1394_MAX_USER_CSR_DIRS 16
|
||||
|
||||
struct iso_block_store {
|
||||
atomic_t refcount;
|
||||
size_t data_size;
|
||||
quadlet_t data[0];
|
||||
};
|
||||
|
||||
enum raw1394_iso_state { RAW1394_ISO_INACTIVE = 0,
|
||||
RAW1394_ISO_RECV = 1,
|
||||
RAW1394_ISO_XMIT = 2 };
|
||||
|
||||
struct file_info {
|
||||
struct list_head list;
|
||||
|
||||
struct mutex state_mutex;
|
||||
enum { opened, initialized, connected } state;
|
||||
unsigned int protocol_version;
|
||||
|
||||
struct hpsb_host *host;
|
||||
|
||||
struct list_head req_pending; /* protected by reqlists_lock */
|
||||
struct list_head req_complete; /* protected by reqlists_lock */
|
||||
spinlock_t reqlists_lock;
|
||||
wait_queue_head_t wait_complete;
|
||||
|
||||
struct list_head addr_list; /* protected by host_info_lock */
|
||||
|
||||
u8 __user *fcp_buffer;
|
||||
|
||||
u8 notification; /* (busreset-notification) RAW1394_NOTIFY_OFF/ON */
|
||||
|
||||
/* new rawiso API */
|
||||
enum raw1394_iso_state iso_state;
|
||||
struct hpsb_iso *iso_handle;
|
||||
|
||||
/* User space's CSR1212 dynamic ConfigROM directories */
|
||||
struct csr1212_keyval *csr1212_dirs[RAW1394_MAX_USER_CSR_DIRS];
|
||||
|
||||
/* Legacy ConfigROM update flag */
|
||||
u8 cfgrom_upd;
|
||||
};
|
||||
|
||||
struct arm_addr {
|
||||
struct list_head addr_list; /* file_info list */
|
||||
u64 start, end;
|
||||
u64 arm_tag;
|
||||
u8 access_rights;
|
||||
u8 notification_options;
|
||||
u8 client_transactions;
|
||||
u64 recvb;
|
||||
u16 rec_length;
|
||||
u8 *addr_space_buffer; /* accessed by read/write/lock requests */
|
||||
};
|
||||
|
||||
struct pending_request {
|
||||
struct list_head list;
|
||||
struct file_info *file_info;
|
||||
struct hpsb_packet *packet;
|
||||
struct iso_block_store *ibs;
|
||||
quadlet_t *data;
|
||||
int free_data;
|
||||
struct raw1394_request req;
|
||||
};
|
||||
|
||||
struct host_info {
|
||||
struct list_head list;
|
||||
struct hpsb_host *host;
|
||||
struct list_head file_info_list; /* protected by host_info_lock */
|
||||
};
|
||||
|
||||
#endif /* IEEE1394_RAW1394_PRIVATE_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,191 +0,0 @@
|
|||
#ifndef IEEE1394_RAW1394_H
|
||||
#define IEEE1394_RAW1394_H
|
||||
|
||||
/* header for the raw1394 API that is exported to user-space */
|
||||
|
||||
#define RAW1394_KERNELAPI_VERSION 4
|
||||
|
||||
/* state: opened */
|
||||
#define RAW1394_REQ_INITIALIZE 1
|
||||
|
||||
/* state: initialized */
|
||||
#define RAW1394_REQ_LIST_CARDS 2
|
||||
#define RAW1394_REQ_SET_CARD 3
|
||||
|
||||
/* state: connected */
|
||||
#define RAW1394_REQ_ASYNC_READ 100
|
||||
#define RAW1394_REQ_ASYNC_WRITE 101
|
||||
#define RAW1394_REQ_LOCK 102
|
||||
#define RAW1394_REQ_LOCK64 103
|
||||
#define RAW1394_REQ_ISO_SEND 104 /* removed ABI, now a no-op */
|
||||
#define RAW1394_REQ_ASYNC_SEND 105
|
||||
#define RAW1394_REQ_ASYNC_STREAM 106
|
||||
|
||||
#define RAW1394_REQ_ISO_LISTEN 200 /* removed ABI, now a no-op */
|
||||
#define RAW1394_REQ_FCP_LISTEN 201
|
||||
#define RAW1394_REQ_RESET_BUS 202
|
||||
#define RAW1394_REQ_GET_ROM 203
|
||||
#define RAW1394_REQ_UPDATE_ROM 204
|
||||
#define RAW1394_REQ_ECHO 205
|
||||
#define RAW1394_REQ_MODIFY_ROM 206
|
||||
|
||||
#define RAW1394_REQ_ARM_REGISTER 300
|
||||
#define RAW1394_REQ_ARM_UNREGISTER 301
|
||||
#define RAW1394_REQ_ARM_SET_BUF 302
|
||||
#define RAW1394_REQ_ARM_GET_BUF 303
|
||||
|
||||
#define RAW1394_REQ_RESET_NOTIFY 400
|
||||
|
||||
#define RAW1394_REQ_PHYPACKET 500
|
||||
|
||||
/* kernel to user */
|
||||
#define RAW1394_REQ_BUS_RESET 10000
|
||||
#define RAW1394_REQ_ISO_RECEIVE 10001
|
||||
#define RAW1394_REQ_FCP_REQUEST 10002
|
||||
#define RAW1394_REQ_ARM 10003
|
||||
#define RAW1394_REQ_RAWISO_ACTIVITY 10004
|
||||
|
||||
/* error codes */
|
||||
#define RAW1394_ERROR_NONE 0
|
||||
#define RAW1394_ERROR_COMPAT (-1001)
|
||||
#define RAW1394_ERROR_STATE_ORDER (-1002)
|
||||
#define RAW1394_ERROR_GENERATION (-1003)
|
||||
#define RAW1394_ERROR_INVALID_ARG (-1004)
|
||||
#define RAW1394_ERROR_MEMFAULT (-1005)
|
||||
#define RAW1394_ERROR_ALREADY (-1006)
|
||||
|
||||
#define RAW1394_ERROR_EXCESSIVE (-1020)
|
||||
#define RAW1394_ERROR_UNTIDY_LEN (-1021)
|
||||
|
||||
#define RAW1394_ERROR_SEND_ERROR (-1100)
|
||||
#define RAW1394_ERROR_ABORTED (-1101)
|
||||
#define RAW1394_ERROR_TIMEOUT (-1102)
|
||||
|
||||
/* arm_codes */
|
||||
#define ARM_READ 1
|
||||
#define ARM_WRITE 2
|
||||
#define ARM_LOCK 4
|
||||
|
||||
#define RAW1394_LONG_RESET 0
|
||||
#define RAW1394_SHORT_RESET 1
|
||||
|
||||
/* busresetnotify ... */
|
||||
#define RAW1394_NOTIFY_OFF 0
|
||||
#define RAW1394_NOTIFY_ON 1
|
||||
|
||||
#include <asm/types.h>
|
||||
|
||||
struct raw1394_request {
|
||||
__u32 type;
|
||||
__s32 error;
|
||||
__u32 misc;
|
||||
|
||||
__u32 generation;
|
||||
__u32 length;
|
||||
|
||||
__u64 address;
|
||||
|
||||
__u64 tag;
|
||||
|
||||
__u64 sendb;
|
||||
__u64 recvb;
|
||||
};
|
||||
|
||||
struct raw1394_khost_list {
|
||||
__u32 nodes;
|
||||
__u8 name[32];
|
||||
};
|
||||
|
||||
typedef struct arm_request {
|
||||
__u16 destination_nodeid;
|
||||
__u16 source_nodeid;
|
||||
__u64 destination_offset;
|
||||
__u8 tlabel;
|
||||
__u8 tcode;
|
||||
__u8 extended_transaction_code;
|
||||
__u32 generation;
|
||||
__u16 buffer_length;
|
||||
__u8 __user *buffer;
|
||||
} *arm_request_t;
|
||||
|
||||
typedef struct arm_response {
|
||||
__s32 response_code;
|
||||
__u16 buffer_length;
|
||||
__u8 __user *buffer;
|
||||
} *arm_response_t;
|
||||
|
||||
typedef struct arm_request_response {
|
||||
struct arm_request __user *request;
|
||||
struct arm_response __user *response;
|
||||
} *arm_request_response_t;
|
||||
|
||||
/* rawiso API */
|
||||
#include "ieee1394-ioctl.h"
|
||||
|
||||
/* per-packet metadata embedded in the ringbuffer */
|
||||
/* must be identical to hpsb_iso_packet_info in iso.h! */
|
||||
struct raw1394_iso_packet_info {
|
||||
__u32 offset;
|
||||
__u16 len;
|
||||
__u16 cycle; /* recv only */
|
||||
__u8 channel; /* recv only */
|
||||
__u8 tag;
|
||||
__u8 sy;
|
||||
};
|
||||
|
||||
/* argument for RAW1394_ISO_RECV/XMIT_PACKETS ioctls */
|
||||
struct raw1394_iso_packets {
|
||||
__u32 n_packets;
|
||||
struct raw1394_iso_packet_info __user *infos;
|
||||
};
|
||||
|
||||
struct raw1394_iso_config {
|
||||
/* size of packet data buffer, in bytes (will be rounded up to PAGE_SIZE) */
|
||||
__u32 data_buf_size;
|
||||
|
||||
/* # of packets to buffer */
|
||||
__u32 buf_packets;
|
||||
|
||||
/* iso channel (set to -1 for multi-channel recv) */
|
||||
__s32 channel;
|
||||
|
||||
/* xmit only - iso transmission speed */
|
||||
__u8 speed;
|
||||
|
||||
/* The mode of the dma when receiving iso data. Must be supported by chip */
|
||||
__u8 dma_mode;
|
||||
|
||||
/* max. latency of buffer, in packets (-1 if you don't care) */
|
||||
__s32 irq_interval;
|
||||
};
|
||||
|
||||
/* argument to RAW1394_ISO_XMIT/RECV_INIT and RAW1394_ISO_GET_STATUS */
|
||||
struct raw1394_iso_status {
|
||||
/* current settings */
|
||||
struct raw1394_iso_config config;
|
||||
|
||||
/* number of packets waiting to be filled with data (ISO transmission)
|
||||
or containing data received (ISO reception) */
|
||||
__u32 n_packets;
|
||||
|
||||
/* approximate number of packets dropped due to overflow or
|
||||
underflow of the packet buffer (a value of zero guarantees
|
||||
that no packets have been dropped) */
|
||||
__u32 overflows;
|
||||
|
||||
/* cycle number at which next packet will be transmitted;
|
||||
-1 if not known */
|
||||
__s16 xmit_cycle;
|
||||
};
|
||||
|
||||
/* argument to RAW1394_IOC_GET_CYCLE_TIMER ioctl */
|
||||
struct raw1394_cycle_timer {
|
||||
/* contents of Isochronous Cycle Timer register,
|
||||
as in OHCI 1.1 clause 5.13 (also with non-OHCI hosts) */
|
||||
__u32 cycle_timer;
|
||||
|
||||
/* local time in microseconds since Epoch,
|
||||
simultaneously read with cycle timer */
|
||||
__u64 local_time;
|
||||
};
|
||||
#endif /* IEEE1394_RAW1394_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,346 +0,0 @@
|
|||
/*
|
||||
* sbp2.h - Defines and prototypes for sbp2.c
|
||||
*
|
||||
* Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
|
||||
* jamesg@filanet.com
|
||||
*
|
||||
* 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 SBP2_H
|
||||
#define SBP2_H
|
||||
|
||||
#define SBP2_DEVICE_NAME "sbp2"
|
||||
|
||||
/*
|
||||
* There is no transport protocol limit to the CDB length, but we implement
|
||||
* a fixed length only. 16 bytes is enough for disks larger than 2 TB.
|
||||
*/
|
||||
#define SBP2_MAX_CDB_SIZE 16
|
||||
|
||||
/*
|
||||
* SBP-2 specific definitions
|
||||
*/
|
||||
|
||||
#define ORB_DIRECTION_WRITE_TO_MEDIA 0x0
|
||||
#define ORB_DIRECTION_READ_FROM_MEDIA 0x1
|
||||
#define ORB_DIRECTION_NO_DATA_TRANSFER 0x2
|
||||
|
||||
#define ORB_SET_NULL_PTR(v) (((v) & 0x1) << 31)
|
||||
#define ORB_SET_NOTIFY(v) (((v) & 0x1) << 31)
|
||||
#define ORB_SET_RQ_FMT(v) (((v) & 0x3) << 29)
|
||||
#define ORB_SET_NODE_ID(v) (((v) & 0xffff) << 16)
|
||||
#define ORB_SET_STATUS_FIFO_HI(v, id) ((v) >> 32 | ORB_SET_NODE_ID(id))
|
||||
#define ORB_SET_STATUS_FIFO_LO(v) ((v) & 0xffffffff)
|
||||
#define ORB_SET_DATA_SIZE(v) ((v) & 0xffff)
|
||||
#define ORB_SET_PAGE_SIZE(v) (((v) & 0x7) << 16)
|
||||
#define ORB_SET_PAGE_TABLE_PRESENT(v) (((v) & 0x1) << 19)
|
||||
#define ORB_SET_MAX_PAYLOAD(v) (((v) & 0xf) << 20)
|
||||
#define ORB_SET_SPEED(v) (((v) & 0x7) << 24)
|
||||
#define ORB_SET_DIRECTION(v) (((v) & 0x1) << 27)
|
||||
|
||||
struct sbp2_command_orb {
|
||||
u32 next_ORB_hi;
|
||||
u32 next_ORB_lo;
|
||||
u32 data_descriptor_hi;
|
||||
u32 data_descriptor_lo;
|
||||
u32 misc;
|
||||
u8 cdb[SBP2_MAX_CDB_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
#define SBP2_LOGIN_REQUEST 0x0
|
||||
#define SBP2_QUERY_LOGINS_REQUEST 0x1
|
||||
#define SBP2_RECONNECT_REQUEST 0x3
|
||||
#define SBP2_SET_PASSWORD_REQUEST 0x4
|
||||
#define SBP2_LOGOUT_REQUEST 0x7
|
||||
#define SBP2_ABORT_TASK_REQUEST 0xb
|
||||
#define SBP2_ABORT_TASK_SET 0xc
|
||||
#define SBP2_LOGICAL_UNIT_RESET 0xe
|
||||
#define SBP2_TARGET_RESET_REQUEST 0xf
|
||||
|
||||
#define ORB_SET_LUN(v) ((v) & 0xffff)
|
||||
#define ORB_SET_FUNCTION(v) (((v) & 0xf) << 16)
|
||||
#define ORB_SET_RECONNECT(v) (((v) & 0xf) << 20)
|
||||
#define ORB_SET_EXCLUSIVE(v) ((v) ? 1 << 28 : 0)
|
||||
#define ORB_SET_LOGIN_RESP_LENGTH(v) ((v) & 0xffff)
|
||||
#define ORB_SET_PASSWD_LENGTH(v) (((v) & 0xffff) << 16)
|
||||
|
||||
struct sbp2_login_orb {
|
||||
u32 password_hi;
|
||||
u32 password_lo;
|
||||
u32 login_response_hi;
|
||||
u32 login_response_lo;
|
||||
u32 lun_misc;
|
||||
u32 passwd_resp_lengths;
|
||||
u32 status_fifo_hi;
|
||||
u32 status_fifo_lo;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define RESPONSE_GET_LOGIN_ID(v) ((v) & 0xffff)
|
||||
#define RESPONSE_GET_LENGTH(v) (((v) >> 16) & 0xffff)
|
||||
#define RESPONSE_GET_RECONNECT_HOLD(v) ((v) & 0xffff)
|
||||
|
||||
struct sbp2_login_response {
|
||||
u32 length_login_ID;
|
||||
u32 command_block_agent_hi;
|
||||
u32 command_block_agent_lo;
|
||||
u32 reconnect_hold;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define ORB_SET_LOGIN_ID(v) ((v) & 0xffff)
|
||||
#define ORB_SET_QUERY_LOGINS_RESP_LENGTH(v) ((v) & 0xffff)
|
||||
|
||||
struct sbp2_query_logins_orb {
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 query_response_hi;
|
||||
u32 query_response_lo;
|
||||
u32 lun_misc;
|
||||
u32 reserved_resp_length;
|
||||
u32 status_fifo_hi;
|
||||
u32 status_fifo_lo;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define RESPONSE_GET_MAX_LOGINS(v) ((v) & 0xffff)
|
||||
#define RESPONSE_GET_ACTIVE_LOGINS(v) ((RESPONSE_GET_LENGTH((v)) - 4) / 12)
|
||||
|
||||
struct sbp2_query_logins_response {
|
||||
u32 length_max_logins;
|
||||
u32 misc_IDs;
|
||||
u32 initiator_misc_hi;
|
||||
u32 initiator_misc_lo;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sbp2_reconnect_orb {
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 reserved3;
|
||||
u32 reserved4;
|
||||
u32 login_ID_misc;
|
||||
u32 reserved5;
|
||||
u32 status_fifo_hi;
|
||||
u32 status_fifo_lo;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sbp2_logout_orb {
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 reserved3;
|
||||
u32 reserved4;
|
||||
u32 login_ID_misc;
|
||||
u32 reserved5;
|
||||
u32 status_fifo_hi;
|
||||
u32 status_fifo_lo;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct sbp2_unrestricted_page_table {
|
||||
__be32 high;
|
||||
__be32 low;
|
||||
};
|
||||
|
||||
#define RESP_STATUS_REQUEST_COMPLETE 0x0
|
||||
#define RESP_STATUS_TRANSPORT_FAILURE 0x1
|
||||
#define RESP_STATUS_ILLEGAL_REQUEST 0x2
|
||||
#define RESP_STATUS_VENDOR_DEPENDENT 0x3
|
||||
|
||||
#define SBP2_STATUS_NO_ADDITIONAL_INFO 0x0
|
||||
#define SBP2_STATUS_REQ_TYPE_NOT_SUPPORTED 0x1
|
||||
#define SBP2_STATUS_SPEED_NOT_SUPPORTED 0x2
|
||||
#define SBP2_STATUS_PAGE_SIZE_NOT_SUPPORTED 0x3
|
||||
#define SBP2_STATUS_ACCESS_DENIED 0x4
|
||||
#define SBP2_STATUS_LU_NOT_SUPPORTED 0x5
|
||||
#define SBP2_STATUS_MAX_PAYLOAD_TOO_SMALL 0x6
|
||||
#define SBP2_STATUS_RESOURCES_UNAVAILABLE 0x8
|
||||
#define SBP2_STATUS_FUNCTION_REJECTED 0x9
|
||||
#define SBP2_STATUS_LOGIN_ID_NOT_RECOGNIZED 0xa
|
||||
#define SBP2_STATUS_DUMMY_ORB_COMPLETED 0xb
|
||||
#define SBP2_STATUS_REQUEST_ABORTED 0xc
|
||||
#define SBP2_STATUS_UNSPECIFIED_ERROR 0xff
|
||||
|
||||
#define SFMT_CURRENT_ERROR 0x0
|
||||
#define SFMT_DEFERRED_ERROR 0x1
|
||||
#define SFMT_VENDOR_DEPENDENT_STATUS 0x3
|
||||
|
||||
#define STATUS_GET_SRC(v) (((v) >> 30) & 0x3)
|
||||
#define STATUS_GET_RESP(v) (((v) >> 28) & 0x3)
|
||||
#define STATUS_GET_LEN(v) (((v) >> 24) & 0x7)
|
||||
#define STATUS_GET_SBP_STATUS(v) (((v) >> 16) & 0xff)
|
||||
#define STATUS_GET_ORB_OFFSET_HI(v) ((v) & 0x0000ffff)
|
||||
#define STATUS_TEST_DEAD(v) ((v) & 0x08000000)
|
||||
/* test 'resp' | 'dead' | 'sbp2_status' */
|
||||
#define STATUS_TEST_RDS(v) ((v) & 0x38ff0000)
|
||||
|
||||
struct sbp2_status_block {
|
||||
u32 ORB_offset_hi_misc;
|
||||
u32 ORB_offset_lo;
|
||||
u8 command_set_dependent[24];
|
||||
} __attribute__((packed));
|
||||
|
||||
|
||||
/*
|
||||
* SBP2 related configuration ROM definitions
|
||||
*/
|
||||
|
||||
#define SBP2_UNIT_DIRECTORY_OFFSET_KEY 0xd1
|
||||
#define SBP2_CSR_OFFSET_KEY 0x54
|
||||
#define SBP2_UNIT_SPEC_ID_KEY 0x12
|
||||
#define SBP2_UNIT_SW_VERSION_KEY 0x13
|
||||
#define SBP2_COMMAND_SET_SPEC_ID_KEY 0x38
|
||||
#define SBP2_COMMAND_SET_KEY 0x39
|
||||
#define SBP2_UNIT_CHARACTERISTICS_KEY 0x3a
|
||||
#define SBP2_DEVICE_TYPE_AND_LUN_KEY 0x14
|
||||
#define SBP2_FIRMWARE_REVISION_KEY 0x3c
|
||||
|
||||
#define SBP2_AGENT_STATE_OFFSET 0x00ULL
|
||||
#define SBP2_AGENT_RESET_OFFSET 0x04ULL
|
||||
#define SBP2_ORB_POINTER_OFFSET 0x08ULL
|
||||
#define SBP2_DOORBELL_OFFSET 0x10ULL
|
||||
#define SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET 0x14ULL
|
||||
#define SBP2_UNSOLICITED_STATUS_VALUE 0xf
|
||||
|
||||
#define SBP2_BUSY_TIMEOUT_ADDRESS 0xfffff0000210ULL
|
||||
/* biggest possible value for Single Phase Retry count is 0xf */
|
||||
#define SBP2_BUSY_TIMEOUT_VALUE 0xf
|
||||
|
||||
#define SBP2_AGENT_RESET_DATA 0xf
|
||||
|
||||
#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e
|
||||
#define SBP2_SW_VERSION_ENTRY 0x00010483
|
||||
|
||||
/*
|
||||
* The default maximum s/g segment size of a FireWire controller is
|
||||
* usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
|
||||
* be quadlet-aligned, we set the length limit to 0xffff & ~3.
|
||||
*/
|
||||
#define SBP2_MAX_SEG_SIZE 0xfffc
|
||||
|
||||
/*
|
||||
* There is no real limitation of the queue depth (i.e. length of the linked
|
||||
* list of command ORBs) at the target. The chosen depth is merely an
|
||||
* implementation detail of the sbp2 driver.
|
||||
*/
|
||||
#define SBP2_MAX_CMDS 8
|
||||
|
||||
#define SBP2_SCSI_STATUS_GOOD 0x0
|
||||
#define SBP2_SCSI_STATUS_CHECK_CONDITION 0x2
|
||||
#define SBP2_SCSI_STATUS_CONDITION_MET 0x4
|
||||
#define SBP2_SCSI_STATUS_BUSY 0x8
|
||||
#define SBP2_SCSI_STATUS_RESERVATION_CONFLICT 0x18
|
||||
#define SBP2_SCSI_STATUS_COMMAND_TERMINATED 0x22
|
||||
#define SBP2_SCSI_STATUS_SELECTION_TIMEOUT 0xff
|
||||
|
||||
|
||||
/*
|
||||
* Representations of commands and devices
|
||||
*/
|
||||
|
||||
/* Per SCSI command */
|
||||
struct sbp2_command_info {
|
||||
struct list_head list;
|
||||
struct sbp2_command_orb command_orb;
|
||||
dma_addr_t command_orb_dma;
|
||||
struct scsi_cmnd *Current_SCpnt;
|
||||
void (*Current_done)(struct scsi_cmnd *);
|
||||
|
||||
/* Also need s/g structure for each sbp2 command */
|
||||
struct sbp2_unrestricted_page_table
|
||||
scatter_gather_element[SG_ALL] __attribute__((aligned(8)));
|
||||
dma_addr_t sge_dma;
|
||||
};
|
||||
|
||||
/* Per FireWire host */
|
||||
struct sbp2_fwhost_info {
|
||||
struct hpsb_host *host;
|
||||
struct list_head logical_units;
|
||||
};
|
||||
|
||||
/* Per logical unit */
|
||||
struct sbp2_lu {
|
||||
/* Operation request blocks */
|
||||
struct sbp2_command_orb *last_orb;
|
||||
dma_addr_t last_orb_dma;
|
||||
struct sbp2_login_orb *login_orb;
|
||||
dma_addr_t login_orb_dma;
|
||||
struct sbp2_login_response *login_response;
|
||||
dma_addr_t login_response_dma;
|
||||
struct sbp2_query_logins_orb *query_logins_orb;
|
||||
dma_addr_t query_logins_orb_dma;
|
||||
struct sbp2_query_logins_response *query_logins_response;
|
||||
dma_addr_t query_logins_response_dma;
|
||||
struct sbp2_reconnect_orb *reconnect_orb;
|
||||
dma_addr_t reconnect_orb_dma;
|
||||
struct sbp2_logout_orb *logout_orb;
|
||||
dma_addr_t logout_orb_dma;
|
||||
struct sbp2_status_block status_block;
|
||||
|
||||
/* How to talk to the unit */
|
||||
u64 management_agent_addr;
|
||||
u64 command_block_agent_addr;
|
||||
u32 speed_code;
|
||||
u32 max_payload_size;
|
||||
u16 lun;
|
||||
|
||||
/* Address for the unit to write status blocks to */
|
||||
u64 status_fifo_addr;
|
||||
|
||||
/* Waitqueue flag for logins, reconnects, logouts, query logins */
|
||||
unsigned int access_complete:1;
|
||||
|
||||
/* Pool of command ORBs for this logical unit */
|
||||
spinlock_t cmd_orb_lock;
|
||||
struct list_head cmd_orb_inuse;
|
||||
struct list_head cmd_orb_completed;
|
||||
|
||||
/* Backlink to FireWire host; list of units attached to the host */
|
||||
struct sbp2_fwhost_info *hi;
|
||||
struct list_head lu_list;
|
||||
|
||||
/* IEEE 1394 core's device representations */
|
||||
struct node_entry *ne;
|
||||
struct unit_directory *ud;
|
||||
|
||||
/* SCSI core's device representations */
|
||||
struct scsi_device *sdev;
|
||||
struct Scsi_Host *shost;
|
||||
|
||||
/* Device specific workarounds/brokeness */
|
||||
unsigned workarounds;
|
||||
|
||||
/* Connection state */
|
||||
atomic_t state;
|
||||
|
||||
/* For deferred requests to the fetch agent */
|
||||
struct work_struct protocol_work;
|
||||
};
|
||||
|
||||
/* For use in sbp2_lu.state */
|
||||
enum sbp2lu_state_types {
|
||||
SBP2LU_STATE_RUNNING, /* all normal */
|
||||
SBP2LU_STATE_IN_RESET, /* between bus reset and reconnect */
|
||||
SBP2LU_STATE_IN_SHUTDOWN /* when sbp2_remove was called */
|
||||
};
|
||||
|
||||
/* For use in sbp2_lu.workarounds and in the corresponding
|
||||
* module load parameter */
|
||||
#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
|
||||
#define SBP2_WORKAROUND_INQUIRY_36 0x2
|
||||
#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
|
||||
#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
|
||||
#define SBP2_WORKAROUND_DELAY_INQUIRY 0x10
|
||||
#define SBP2_INQUIRY_DELAY 12
|
||||
#define SBP2_WORKAROUND_POWER_CONDITION 0x20
|
||||
#define SBP2_WORKAROUND_OVERRIDE 0x100
|
||||
|
||||
#endif /* SBP2_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* video1394.h - driver for OHCI 1394 boards
|
||||
* Copyright (C)1999,2000 Sebastien Rougeaux <sebastien.rougeaux@anu.edu.au>
|
||||
* Peter Schlaile <udbz@rz.uni-karlsruhe.de>
|
||||
*
|
||||
* 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 _VIDEO_1394_H
|
||||
#define _VIDEO_1394_H
|
||||
|
||||
#include "ieee1394-ioctl.h"
|
||||
|
||||
#define VIDEO1394_DRIVER_NAME "video1394"
|
||||
|
||||
#define VIDEO1394_MAX_SIZE 0x4000000
|
||||
|
||||
enum {
|
||||
VIDEO1394_BUFFER_FREE = 0,
|
||||
VIDEO1394_BUFFER_QUEUED,
|
||||
VIDEO1394_BUFFER_READY
|
||||
};
|
||||
|
||||
#define VIDEO1394_SYNC_FRAMES 0x00000001
|
||||
#define VIDEO1394_INCLUDE_ISO_HEADERS 0x00000002
|
||||
#define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004
|
||||
|
||||
struct video1394_mmap {
|
||||
int channel; /* -1 to find an open channel in LISTEN/TALK */
|
||||
unsigned int sync_tag;
|
||||
unsigned int nb_buffers;
|
||||
unsigned int buf_size;
|
||||
unsigned int packet_size; /* For VARIABLE_PACKET_SIZE:
|
||||
Maximum packet size */
|
||||
unsigned int fps;
|
||||
unsigned int syt_offset;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* For TALK_QUEUE_BUFFER with VIDEO1394_VARIABLE_PACKET_SIZE use */
|
||||
struct video1394_queue_variable {
|
||||
unsigned int channel;
|
||||
unsigned int buffer;
|
||||
unsigned int __user * packet_sizes; /* Buffer of size:
|
||||
buf_size / packet_size */
|
||||
};
|
||||
|
||||
struct video1394_wait {
|
||||
unsigned int channel;
|
||||
unsigned int buffer;
|
||||
struct timeval filltime; /* time of buffer full */
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue