work from JiSheng Zhang : fwcontrol with firewire headers from FreeBSD current. Thanks!

clean up


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21616 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2007-07-15 17:43:02 +00:00
parent 84f03dd594
commit 2ff0a95e11
14 changed files with 4394 additions and 0 deletions

View File

@ -0,0 +1,57 @@
/*-
* Copyright 2004 The Aerospace Corporation. All rights reserved.
*
* 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 Aerospace Corporation may not be used to endorse or
* promote products derived from this software.
*
* THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION "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 AEROSPACE CORPORATION 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.
*
* $FreeBSD: src/sys/sys/eui64.h,v 1.2 2005/01/07 02:29:23 imp Exp $
*/
#ifndef _SYS_EUI64_H
#define _SYS_EUI64_H
/*
* Size of the ASCII representation of an EUI-64.
*/
#define EUI64_SIZ 24
/*
* The number of bytes in an EUI-64.
*/
#define EUI64_LEN 8
/*
* Structure of an IEEE EUI-64.
*/
struct eui64 {
u_char octet[EUI64_LEN];
};
#ifndef _KERNEL
int eui64_aton(const char *, struct eui64 *);
int eui64_ntoa(const struct eui64 *, char *, size_t);
int eui64_ntohost(char *, size_t, const struct eui64 *);
int eui64_hostton(const char *, struct eui64 *);
#endif /* !_KERNEL */
#endif /* !_SYS_EUI64_H */

View File

@ -0,0 +1,437 @@
/*-
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the acknowledgement as bellow:
*
* This product includes software developed by K. Kobayashi and H. Shimokawa
*
* 4. 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.
*
* $FreeBSD: src/sys/dev/firewire/firewire.h,v 1.21 2007/04/24 12:15:05 simokawa Exp $
*
*/
#ifndef _FIREWIRE_H
#define _FIREWIRE_H 1
#ifdef __HAIKU__
#include <stdint.h>
#include <sys/ioccom.h>
#endif
#define DEV_DEF 0
#define DEV_DV 2
struct fw_isochreq {
unsigned char ch:6,
tag:2;
};
struct fw_isobufreq {
struct fw_bufspec {
unsigned int nchunk;
unsigned int npacket;
unsigned int psize;
} tx, rx;
};
struct fw_addr {
uint32_t hi;
uint32_t lo;
};
struct fw_asybindreq {
struct fw_addr start;
unsigned long len;
};
struct fw_reg_req_t {
uint32_t addr;
uint32_t data;
};
#define MAXREC(x) (2 << (x))
#define FWPMAX_S400 (2048 + 20) /* MAXREC plus space for control data */
#define FWMAXQUEUE 128
#define FWLOCALBUS 0xffc0
#define FWTCODE_WREQQ 0
#define FWTCODE_WREQB 1
#define FWTCODE_WRES 2
#define FWTCODE_RREQQ 4
#define FWTCODE_RREQB 5
#define FWTCODE_RRESQ 6
#define FWTCODE_RRESB 7
#define FWTCODE_CYCS 8
#define FWTCODE_LREQ 9
#define FWTCODE_STREAM 0xa
#define FWTCODE_LRES 0xb
#define FWTCODE_PHY 0xe
#define FWRETRY_1 0
#define FWRETRY_X 1
#define FWRETRY_A 2
#define FWRETRY_B 3
#define FWRCODE_COMPLETE 0
#define FWRCODE_ER_CONFL 4
#define FWRCODE_ER_DATA 5
#define FWRCODE_ER_TYPE 6
#define FWRCODE_ER_ADDR 7
#define FWSPD_S100 0
#define FWSPD_S200 1
#define FWSPD_S400 2
#define FWP_TL_VALID (1 << 7)
struct fw_isohdr {
uint32_t hdr[1];
};
struct fw_asyhdr {
uint32_t hdr[4];
};
#if BYTE_ORDER == BIG_ENDIAN
#define BIT4x2(x,y) uint8_t x:4, y:4
#define BIT16x2(x,y) uint32_t x:16, y:16
#else
#define BIT4x2(x,y) uint8_t y:4, x:4
#define BIT16x2(x,y) uint32_t y:16, x:16
#endif
#if BYTE_ORDER == BIG_ENDIAN
#define COMMON_HDR(a,b,c,d) uint32_t a:16,b:8,c:4,d:4
#define COMMON_RES(a,b,c,d) uint32_t a:16,b:4,c:4,d:8
#else
#define COMMON_HDR(a,b,c,d) uint32_t d:4,c:4,b:8,a:16
#define COMMON_RES(a,b,c,d) uint32_t d:8,c:4,b:4,a:16
#endif
struct fw_pkt {
union {
uint32_t ld[0];
struct {
COMMON_HDR(, , tcode, );
} common;
struct {
COMMON_HDR(len, chtag, tcode, sy);
uint32_t payload[0];
} stream;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, );
} hdr;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
uint32_t dest_lo;
} rreqq;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
COMMON_RES(src, rtcode, , );
uint32_t :32;
} wres;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
uint32_t dest_lo;
BIT16x2(len, extcode);
} rreqb;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
uint32_t dest_lo;
uint32_t data;
} wreqq;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
uint32_t dest_lo;
uint32_t data;
} cyc;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
COMMON_RES(src, rtcode, , );
uint32_t :32;
uint32_t data;
} rresq;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
uint32_t dest_lo;
BIT16x2(len, extcode);
uint32_t payload[0];
} wreqb;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
BIT16x2(src, dest_hi);
uint32_t dest_lo;
BIT16x2(len, extcode);
uint32_t payload[0];
} lreq;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
COMMON_RES(src, rtcode, , );
uint32_t :32;
BIT16x2(len, extcode);
uint32_t payload[0];
} rresb;
struct {
COMMON_HDR(dst, tlrt, tcode, pri);
COMMON_RES(src, rtcode, , );
uint32_t :32;
BIT16x2(len, extcode);
uint32_t payload[0];
} lres;
} mode;
};
/*
* Response code (rtcode)
*/
/* The node has successfully completed the command. */
#define RESP_CMP 0
/* A resource conflict was detected. The request may be retried. */
#define RESP_CONFLICT_ERROR 4
/* Hardware error, data is unavailable. */
#define RESP_DATA_ERROR 5
/* A field in the request packet header was set to an unsupported or incorrect
* value, or an invalid transaction was attempted (e.g., a write to a read-only
* address). */
#define RESP_TYPE_ERROR 6
/* The destination offset field in the request was set to an address not
* accessible in the destination node. */
#define RESP_ADDRESS_ERROR 7
/*
* Extended transaction code (extcode)
*/
#define EXTCODE_MASK_SWAP 1
#define EXTCODE_CMP_SWAP 2
#define EXTCODE_FETCH_ADD 3
#define EXTCODE_LITTLE_ADD 4
#define EXTCODE_BOUNDED_ADD 5
#define EXTCODE_WRAP_ADD 6
struct fw_eui64 {
uint32_t hi, lo;
};
#define FW_EUI64_BYTE(eui, x) \
((((x)<4)? \
((eui)->hi >> (8*(3-(x)))): \
((eui)->lo >> (8*(7-(x)))) \
) & 0xff)
#define FW_EUI64_EQUAL(x, y) \
((x).hi == (y).hi && (x).lo == (y).lo)
struct fw_asyreq {
struct fw_asyreq_t{
unsigned char sped;
unsigned int type;
#define FWASREQNODE 0
#define FWASREQEUI 1
#define FWASRESTL 2
#define FWASREQSTREAM 3
unsigned short len;
union {
struct fw_eui64 eui;
}dst;
}req;
struct fw_pkt pkt;
uint32_t data[512];
};
struct fw_devinfo {
struct fw_eui64 eui;
uint16_t dst;
uint16_t status;
};
#define FW_MAX_DEVLST 70
struct fw_devlstreq {
uint16_t n;
uint16_t info_len;
struct fw_devinfo dev[FW_MAX_DEVLST];
};
#define FW_SELF_ID_PORT_CONNECTED_TO_CHILD 3
#define FW_SELF_ID_PORT_CONNECTED_TO_PARENT 2
#define FW_SELF_ID_PORT_NOT_CONNECTED 1
#define FW_SELF_ID_PORT_NOT_EXISTS 0
#if BYTE_ORDER == BIG_ENDIAN
union fw_self_id {
struct {
uint32_t id:2,
phy_id:6,
sequel:1,
link_active:1,
gap_count:6,
phy_speed:2,
phy_delay:2,
contender:1,
power_class:3,
port0:2,
port1:2,
port2:2,
initiated_reset:1,
more_packets:1;
} p0;
struct {
uint32_t
id:2,
phy_id:6,
sequel:1,
sequence_num:3,
:2,
porta:2,
portb:2,
portc:2,
portd:2,
porte:2,
portf:2,
portg:2,
porth:2,
:1,
more_packets:1;
} p1;
};
#else
union fw_self_id {
struct {
uint32_t more_packets:1,
initiated_reset:1,
port2:2,
port1:2,
port0:2,
power_class:3,
contender:1,
phy_delay:2,
phy_speed:2,
gap_count:6,
link_active:1,
sequel:1,
phy_id:6,
id:2;
} p0;
struct {
uint32_t more_packets:1,
reserved1:1,
porth:2,
portg:2,
portf:2,
porte:2,
portd:2,
portc:2,
portb:2,
porta:2,
reserved2:2,
sequence_num:3,
sequel:1,
phy_id:6,
id:2;
} p1;
};
#endif
struct fw_topology_map {
uint32_t crc:16,
crc_len:16;
uint32_t generation;
uint32_t self_id_count:16,
node_count:16;
union fw_self_id self_id[4*64];
};
struct fw_speed_map {
uint32_t crc:16,
crc_len:16;
uint32_t generation;
uint8_t speed[64][64];
};
struct fw_crom_buf {
struct fw_eui64 eui;
uint32_t len;
void *ptr;
};
/*
* FireWire specific system requests.
*/
#define FW_SSTBUF _IOWR('S', 86, struct fw_isobufreq)
#define FW_GSTBUF _IOWR('S', 87, struct fw_isobufreq)
#define FW_SRSTREAM _IOWR('S', 88, struct fw_isochreq)
#define FW_GRSTREAM _IOWR('S', 89, struct fw_isochreq)
#define FW_STSTREAM _IOWR('S', 90, struct fw_isochreq)
#define FW_GTSTREAM _IOWR('S', 91, struct fw_isochreq)
#define FW_ASYREQ _IOWR('S', 92, struct fw_asyreq)
#define FW_IBUSRST _IOR('S', 1, unsigned int)
#define FW_GDEVLST _IOWR('S', 2, struct fw_devlstreq)
#define FW_SBINDADDR _IOWR('S', 3, struct fw_asybindreq)
#define FW_CBINDADDR _IOWR('S', 4, struct fw_asybindreq)
#define FW_GTPMAP _IOR('S', 5, struct fw_topology_map)
#define FW_GCROM _IOWR('S', 7, struct fw_crom_buf)
#define FW_SDEUI64 _IOW('S', 20, struct fw_eui64)
#define FW_GDEUI64 _IOR('S', 21, struct fw_eui64)
#define FWOHCI_RDREG _IOWR('S', 80, struct fw_reg_req_t)
#define FWOHCI_WRREG _IOWR('S', 81, struct fw_reg_req_t)
#define FWOHCI_RDPHYREG _IOWR('S', 82, struct fw_reg_req_t)
#define FWOHCI_WRPHYREG _IOWR('S', 83, struct fw_reg_req_t)
#define DUMPDMA _IOWR('S', 82, uint32_t)
#ifdef _KERNEL
#define FWMAXNDMA 0x100 /* 8 bits DMA channel id. in device No. */
#ifndef __HAIKU__
#if defined(__DragonFly__) || __FreeBSD_version < 500000
#define dev2unit(x) ((minor(x) & 0xff) | (minor(x) >> 8))
#define unit2minor(x) (((x) & 0xff) | (((x) << 8) & ~0xffff))
#endif
#define MAKEMINOR(f, u, s) \
unit2minor((f) | (((u) & 0xff) << 8) | (s & 0xff))
#define DEV2UNIT(x) ((dev2unit(x) & 0xff00) >> 8)
#define DEV2SUB(x) (dev2unit(x) & 0xff)
#define FWMEM_FLAG 0x10000
#define DEV_FWMEM(x) (dev2unit(x) & FWMEM_FLAG)
#endif /* __HAIKU__ */
#endif
#ifdef __HAIKU__
#define EX_NOINPUT 66
#define EX_USAGE 64
#endif /* __HAIKU__*/
#endif

View File

@ -0,0 +1,168 @@
/*-
* Copyright (C) 2003
* Hidetoshi Shimokawa. All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by Hidetoshi Shimokawa.
*
* 4. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* $FreeBSD: src/sys/dev/firewire/fwphyreg.h,v 1.3 2005/01/06 01:42:41 imp Exp $
*/
struct phyreg_base {
#if BYTE_ORDER == BIG_ENDIAN
uint8_t phy_id:6,
r:1,
cps:1;
uint8_t rhb:1,
ibr:1,
gap_count:6;
uint8_t extended:3,
num_ports:5;
uint8_t phy_speed:3,
:1,
delay:4;
uint8_t lctrl:1,
c:1,
jitter:3,
pwr_class:3;
uint8_t wdie:1,
isbr:1,
ctoi:1,
cpsi:1,
stoi:1,
pei:1,
eaa:1,
emc:1;
uint8_t legacy_spd:3,
blink:1,
bridge:2,
:2;
uint8_t page_select:3,
:1,
port_select:4;
#else
uint8_t cps:1,
r:1,
phy_id:6;
uint8_t gap_count:6,
ibr:1,
rhb:1;
uint8_t num_ports:5,
extended:3;
uint8_t delay:4,
:1,
phy_speed:3;
uint8_t pwr_class:3,
jitter:3,
c:1,
lctrl:1;
uint8_t emc:1,
eaa:1,
pei:1,
stoi:1,
cpsi:1,
ctoi:1,
isbr:1,
wdie:1;
uint8_t :2,
bridge:2,
blink:1,
legacy_spd:3;
uint8_t port_select:4,
:1,
page_select:3;
#endif
};
struct phyreg_page0 {
#if BYTE_ORDER == BIG_ENDIAN
uint8_t astat:2,
bstat:2,
ch:1,
con:1,
rxok:1,
dis:1;
uint8_t negotiated_speed:3,
pie:1,
fault:1,
stanby_fault:1,
disscrm:1,
b_only:1;
uint8_t dc_connected:1,
max_port_speed:3,
lpp:1,
cable_speed:3;
uint8_t connection_unreliable:1,
:3,
beta_mode:1,
:3;
uint8_t port_error;
uint8_t :5,
loop_disable:1,
in_standby:1,
hard_disable:1;
uint8_t :8;
uint8_t :8;
#else
uint8_t dis:1,
rxok:1,
con:1,
ch:1,
bstat:2,
astat:2;
uint8_t b_only:1,
disscrm:1,
stanby_fault:1,
fault:1,
pie:1,
negotiated_speed:3;
uint8_t cable_speed:3,
lpp:1,
max_port_speed:3,
dc_connected:1;
uint8_t :3,
beta_mode:1,
:3,
connection_unreliable:1;
uint8_t port_error;
uint8_t hard_disable:1,
in_standby:1,
loop_disable:1,
:5;
uint8_t :8;
uint8_t :8;
#endif
};
struct phyreg_page1 {
uint8_t compliance;
uint8_t :8;
uint8_t vendor_id[3];
uint8_t product_id[3];
};

View File

@ -0,0 +1,251 @@
/*-
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the acknowledgement as bellow:
*
* This product includes software developed by K. Kobayashi and H. Shimokawa
*
* 4. 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.
*
* $FreeBSD: src/sys/dev/firewire/iec13213.h,v 1.14 2005/01/06 01:42:41 imp Exp $
*
*/
#define STATE_CLEAR 0x0000
#define STATE_SET 0x0004
#define NODE_IDS 0x0008
#define RESET_START 0x000c
#define SPLIT_TIMEOUT_HI 0x0018
#define SPLIT_TIMEOUT_LO 0x001c
#define CYCLE_TIME 0x0200
#define BUS_TIME 0x0204
#define BUSY_TIMEOUT 0x0210
#define PRIORITY_BUDGET 0x0218
#define BUS_MGR_ID 0x021c
#define BANDWIDTH_AV 0x0220
#define CHANNELS_AV_HI 0x0224
#define CHANNELS_AV_LO 0x0228
#define IP_CHANNELS 0x0234
#define CONF_ROM 0x0400
#define TOPO_MAP 0x1000
#define SPED_MAP 0x2000
#define CSRTYPE_SHIFT 6
#define CSRTYPE_MASK (3 << CSRTYPE_SHIFT)
#define CSRTYPE_I (0 << CSRTYPE_SHIFT) /* Immediate */
#define CSRTYPE_C (1 << CSRTYPE_SHIFT) /* CSR offset */
#define CSRTYPE_L (2 << CSRTYPE_SHIFT) /* Leaf */
#define CSRTYPE_D (3 << CSRTYPE_SHIFT) /* Directory */
/*
* CSR keys
* 00 - 2F: defined by CSR architecture standards.
* 30 - 37: defined by BUS starndards
* 38 - 3F: defined by Vendor/Specifier
*/
#define CSRKEY_MASK 0x3f
#define CSRKEY_DESC 0x01 /* Descriptor */
#define CSRKEY_BDINFO 0x02 /* Bus_Dependent_Info */
#define CSRKEY_VENDOR 0x03 /* Vendor */
#define CSRKEY_HW 0x04 /* Hardware_Version */
#define CSRKEY_MODULE 0x07 /* Module */
#define CSRKEY_NCAP 0x0c /* Node_Capabilities */
#define CSRKEY_EUI64 0x0d /* EUI_64 */
#define CSRKEY_UNIT 0x11 /* Unit */
#define CSRKEY_SPEC 0x12 /* Specifier_ID */
#define CSRKEY_VER 0x13 /* Version */
#define CSRKEY_DINFO 0x14 /* Dependent_Info */
#define CSRKEY_ULOC 0x15 /* Unit_Location */
#define CSRKEY_MODEL 0x17 /* Model */
#define CSRKEY_INST 0x18 /* Instance */
#define CSRKEY_KEYW 0x19 /* Keyword */
#define CSRKEY_FEAT 0x1a /* Feature */
#define CSRKEY_EROM 0x1b /* Extended_ROM */
#define CSRKEY_EKSID 0x1c /* Extended_Key_Specifier_ID */
#define CSRKEY_EKEY 0x1d /* Extended_Key */
#define CSRKEY_EDATA 0x1e /* Extended_Data */
#define CSRKEY_MDESC 0x1f /* Modifiable_Descriptor */
#define CSRKEY_DID 0x20 /* Directory_ID */
#define CSRKEY_REV 0x21 /* Revision */
#define CSRKEY_FIRM_VER 0x3c /* Firmware version */
#define CSRKEY_UNIT_CH 0x3a /* Unit characteristics */
#define CSRKEY_COM_SPEC 0x38 /* Command set revision */
#define CSRKEY_COM_SET 0x39 /* Command set */
#define CROM_UDIR (CSRTYPE_D | CSRKEY_UNIT) /* 0x81 Unit directory */
#define CROM_TEXTLEAF (CSRTYPE_L | CSRKEY_DESC) /* 0x81 Text leaf */
#define CROM_LUN (CSRTYPE_I | CSRKEY_DINFO) /* 0x14 Logical unit num. */
#define CROM_MGM (CSRTYPE_C | CSRKEY_DINFO) /* 0x54 Management agent */
#define CSRVAL_VENDOR_PRIVATE 0xacde48
#define CSRVAL_1394TA 0x00a02d
#define CSRVAL_ANSIT10 0x00609e
#define CSRVAL_IETF 0x00005e
#define CSR_PROTAVC 0x010001
#define CSR_PROTCAL 0x010002
#define CSR_PROTEHS 0x010004
#define CSR_PROTHAVI 0x010008
#define CSR_PROTCAM104 0x000100
#define CSR_PROTCAM120 0x000101
#define CSR_PROTCAM130 0x000102
#define CSR_PROTDPP 0x0a6be2
#define CSR_PROTIICP 0x4b661f
#define CSRVAL_T10SBP2 0x010483
#define CSRVAL_SCSI 0x0104d8
struct csrreg {
#if BYTE_ORDER == BIG_ENDIAN
uint32_t key:8,
val:24;
#else
uint32_t val:24,
key:8;
#endif
};
struct csrhdr {
#if BYTE_ORDER == BIG_ENDIAN
uint32_t info_len:8,
crc_len:8,
crc:16;
#else
uint32_t crc:16,
crc_len:8,
info_len:8;
#endif
};
struct csrdirectory {
BIT16x2(crc_len, crc);
struct csrreg entry[0];
};
struct csrtext {
BIT16x2(crc_len, crc);
#if BYTE_ORDER == BIG_ENDIAN
uint32_t spec_type:8,
spec_id:24;
#else
uint32_t spec_id:24,
spec_type:8;
#endif
uint32_t lang_id;
uint32_t text[0];
};
struct bus_info {
#define CSR_BUS_NAME_IEEE1394 0x31333934
uint32_t bus_name;
#if BYTE_ORDER == BIG_ENDIAN
uint32_t irmc:1, /* iso. resource manager capable */
cmc:1, /* cycle master capable */
isc:1, /* iso. operation support */
bmc:1, /* bus manager capable */
pmc:1, /* power manager capable */
:3,
cyc_clk_acc:8, /* 0 <= ppm <= 100 */
max_rec:4, /* (2 << max_rec) bytes */
:2,
max_rom:2,
generation:4,
:1,
link_spd:3;
#else
uint32_t link_spd:3,
:1,
generation:4,
max_rom:2,
:2,
max_rec:4, /* (2 << max_rec) bytes */
cyc_clk_acc:8, /* 0 <= ppm <= 100 */
:3,
pmc:1, /* power manager capable */
bmc:1, /* bus manager capable */
isc:1, /* iso. operation support */
cmc:1, /* cycle master capable */
irmc:1; /* iso. resource manager capable */
#endif
struct fw_eui64 eui64;
};
/* max_rom */
#define MAXROM_4 0
#define MAXROM_64 1
#define MAXROM_1024 2
#define CROM_MAX_DEPTH 10
struct crom_ptr {
struct csrdirectory *dir;
int index;
};
struct crom_context {
int depth;
struct crom_ptr stack[CROM_MAX_DEPTH];
};
void crom_init_context(struct crom_context *, uint32_t *);
struct csrreg *crom_get(struct crom_context *);
void crom_next(struct crom_context *);
void crom_parse_text(struct crom_context *, char *, int);
uint16_t crom_crc(uint32_t *r, int);
struct csrreg *crom_search_key(struct crom_context *, uint8_t);
int crom_has_specver(uint32_t *, uint32_t, uint32_t);
#if !defined(_KERNEL) && !defined(_BOOT)
char *crom_desc(struct crom_context *, char *, int);
#endif
/* For CROM build */
#if defined(_KERNEL) || defined(_BOOT) || defined(TEST)
#define CROM_MAX_CHUNK_LEN 20
struct crom_src {
struct csrhdr hdr;
struct bus_info businfo;
STAILQ_HEAD(, crom_chunk) chunk_list;
};
struct crom_chunk {
STAILQ_ENTRY(crom_chunk) link;
struct crom_chunk *ref_chunk;
int ref_index;
int offset;
struct {
BIT16x2(crc_len, crc);
uint32_t buf[CROM_MAX_CHUNK_LEN];
} data;
};
extern int crom_add_quad(struct crom_chunk *, uint32_t);
extern int crom_add_entry(struct crom_chunk *, int, int);
extern int crom_add_chunk(struct crom_src *src, struct crom_chunk *,
struct crom_chunk *, int);
extern int crom_add_simple_text(struct crom_src *src, struct crom_chunk *,
struct crom_chunk *, char *);
extern int crom_load(struct crom_src *, uint32_t *, int);
#endif

View File

@ -0,0 +1,127 @@
/*-
* Copyright (c) 2003 Hidetoshi Shimokawa
* Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
* All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the acknowledgement as bellow:
*
* This product includes software developed by K. Kobayashi and H. Shimokawa
*
* 4. 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.
*
* $FreeBSD: src/sys/dev/firewire/iec68113.h,v 1.9 2005/01/06 01:42:41 imp Exp $
*
*/
#define DV_BROADCAST_ON (1<<30)
#define oMPR 0x900
#define oPCR 0x904
#define iMPR 0x980
#define iPCR 0x984
struct ciphdr {
#if BYTE_ORDER == BIG_ENDIAN
uint8_t eoh0:1, /* 0 */
form0:1, /* 0 */
src:6;
#else
uint8_t src:6,
form0:1, /* 0 */
eoh0:1; /* 0 */
#endif
uint8_t len;
#if BYTE_ORDER == BIG_ENDIAN
uint8_t fn:2,
qpc:3,
sph:1,
:2;
#else
uint8_t :2,
sph:1,
qpc:3,
fn:2;
#endif
uint8_t dbc;
#if BYTE_ORDER == BIG_ENDIAN
uint8_t eoh1:1, /* 1 */
form1:1, /* 0 */
fmt:6;
#else
uint8_t fmt:6,
form1:1, /* 0 */
eoh1:1; /* 1 */
#endif
#define CIP_FMT_DVCR 0
#define CIP_FMT_MPEG (1<<5)
union {
struct {
#if BYTE_ORDER == BIG_ENDIAN
uint8_t fs:1, /* 50/60 field system
NTSC/PAL */
stype:5,
:2;
#else
uint8_t :2,
stype:5,
fs:1; /* 50/60 field system
NTSC/PAL */
#endif
#define CIP_STYPE_SD 0
#define CIP_STYPE_SDL 1
#define CIP_STYPE_HD 2
uint16_t cyc:16; /* take care of byte order! */
} __attribute__ ((packed)) dv;
uint8_t bytes[3];
} fdf;
};
struct dvdbc{
#if BYTE_ORDER == BIG_ENDIAN
uint8_t sct:3, /* Section type */
:1, /* Reserved */
arb:4; /* Arbitrary bit */
#else
uint8_t arb:4, /* Arbitrary bit */
:1, /* Reserved */
sct:3; /* Section type */
#endif
#define DV_SCT_HEADER 0
#define DV_SCT_SUBCODE 1
#define DV_SCT_VAUX 2
#define DV_SCT_AUDIO 3
#define DV_SCT_VIDEO 4
#if BYTE_ORDER == BIG_ENDIAN
uint8_t dseq:4, /* DIF sequence number */
fsc:1, /* ID of a DIF block in each channel */
:3;
#else
uint8_t :3,
fsc:1, /* ID of a DIF block in each channel */
dseq:4; /* DIF sequence number */
#endif
uint8_t dbn; /* DIF block number */
uint8_t payload[77];
#define DV_DSF_12 0x80 /* PAL: payload[0] in Header DIF */
};

View File

@ -0,0 +1,618 @@
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* 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.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD: src/sys/sys/queue.h,v 1.68 2006/10/24 11:20:29 ru Exp $
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
#include <sys/cdefs.h>
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* For details on the use of these macros, see the queue(3) manual page.
*
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - - - +
* _LAST - - + +
* _FOREACH + + + +
* _FOREACH_SAFE + + + +
* _FOREACH_REVERSE - - - +
* _FOREACH_REVERSE_SAFE - - - +
* _INSERT_HEAD + + + +
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT - - + +
* _REMOVE_HEAD + - + -
* _REMOVE + + + +
*
*/
#ifdef QUEUE_MACRO_DEBUG
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
char * lastfile;
int lastline;
char * prevfile;
int prevline;
};
#define TRACEBUF struct qm_trace trace;
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \
(head)->trace.prevfile = (head)->trace.lastfile; \
(head)->trace.lastline = __LINE__; \
(head)->trace.lastfile = __FILE__; \
} while (0)
#define QMD_TRACE_ELEM(elem) do { \
(elem)->trace.prevline = (elem)->trace.lastline; \
(elem)->trace.prevfile = (elem)->trace.lastfile; \
(elem)->trace.lastline = __LINE__; \
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define TRACEBUF
#define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != NULL; \
(varp) = &SLIST_NEXT((var), field))
#define SLIST_INIT(head) do { \
SLIST_FIRST((head)) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) do { \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = SLIST_FIRST((head)); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_NEXT(curelm, field) = \
SLIST_NEXT(SLIST_NEXT(curelm, field), field); \
} \
TRASHIT((elm)->field.sle_next); \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first;/* first element */ \
struct type **stqh_last;/* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \
for((var) = STAILQ_FIRST((head)); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((tqelm), field) = (elm); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? \
NULL : \
((struct type *)(void *) \
((char *)((head)->stqh_last) - __offsetof(struct type, field))))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) do { \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = STAILQ_FIRST((head)); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
if ((STAILQ_NEXT(curelm, field) = \
STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((curelm), field);\
} \
TRASHIT((elm)->field.stqe_next); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
/*
* List declarations.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_LIST_CHECK_HEAD(head, field) do { \
if (LIST_FIRST((head)) != NULL && \
LIST_FIRST((head))->field.le_prev != \
&LIST_FIRST((head))) \
panic("Bad list head %p first->prev != head", (head)); \
} while (0)
#define QMD_LIST_CHECK_NEXT(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL && \
LIST_NEXT((elm), field)->field.le_prev != \
&((elm)->field.le_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_LIST_CHECK_PREV(elm, field) do { \
if (*(elm)->field.le_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_LIST_CHECK_HEAD(head, field)
#define QMD_LIST_CHECK_NEXT(elm, field)
#define QMD_LIST_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_INIT(head) do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
QMD_LIST_CHECK_NEXT(listelm, field); \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
QMD_LIST_CHECK_PREV(listelm, field); \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
QMD_LIST_CHECK_HEAD((head), field); \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_REMOVE(elm, field) do { \
QMD_LIST_CHECK_NEXT(elm, field); \
QMD_LIST_CHECK_PREV(elm, field); \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
TRASHIT((elm)->field.le_next); \
TRASHIT((elm)->field.le_prev); \
} while (0)
/*
* Tail queue declarations.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
if (!TAILQ_EMPTY(head) && \
TAILQ_FIRST((head))->field.tqe_prev != \
&TAILQ_FIRST((head))) \
panic("Bad tailq head %p first->prev != head", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
if (*(head)->tqh_last != NULL) \
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
if (TAILQ_NEXT((elm), field) != NULL && \
TAILQ_NEXT((elm), field)->field.tqe_prev != \
&((elm)->field.tqe_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
if (*(elm)->field.tqe_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_TAILQ_CHECK_HEAD(head, field)
#define QMD_TAILQ_CHECK_TAIL(head, headname)
#define QMD_TAILQ_CHECK_NEXT(elm, field)
#define QMD_TAILQ_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
QMD_TRACE_HEAD(head1); \
QMD_TRACE_HEAD(head2); \
} \
} while (0)
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
QMD_TAILQ_CHECK_NEXT(listelm, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
QMD_TAILQ_CHECK_PREV(listelm, field); \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
QMD_TAILQ_CHECK_HEAD(head, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
QMD_TAILQ_CHECK_TAIL(head, field); \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) do { \
QMD_TAILQ_CHECK_NEXT(elm, field); \
QMD_TAILQ_CHECK_PREV(elm, field); \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT((elm)->field.tqe_next); \
TRASHIT((elm)->field.tqe_prev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#ifdef _KERNEL
/*
* XXX insque() and remque() are an old way of handling certain queues.
* They bogusly assumes that all queue heads look alike.
*/
struct quehead {
struct quehead *qh_link;
struct quehead *qh_rlink;
};
#ifdef __CC_SUPPORTS___INLINE
static __inline void
insque(void *a, void *b)
{
struct quehead *element = (struct quehead *)a,
*head = (struct quehead *)b;
element->qh_link = head->qh_link;
element->qh_rlink = head;
head->qh_link = element;
element->qh_link->qh_rlink = element;
}
static __inline void
remque(void *a)
{
struct quehead *element = (struct quehead *)a;
element->qh_link->qh_rlink = element->qh_rlink;
element->qh_rlink->qh_link = element->qh_link;
element->qh_rlink = 0;
}
#else /* !__CC_SUPPORTS___INLINE */
void insque(void *a, void *b);
void remque(void *a);
#endif /* __CC_SUPPORTS___INLINE */
#endif /* _KERNEL */
#endif /* !_SYS_QUEUE_H_ */

13
src/bin/fwcontrol/Jamfile Normal file
View File

@ -0,0 +1,13 @@
SubDir HAIKU_TOP src bin fwcontrol ;
UseHeaders [ FDirName $(HAIKU_TOP) headers compatibility bsd ] : true ;
UsePrivateHeaders firewire ;
BinCommand fwcontrol :
eui64.c
fwcrom.c
fwdv.c
fwmpegts.c
fwcontrol.c
: libbsd.so
;

323
src/bin/fwcontrol/eui64.c Normal file
View File

@ -0,0 +1,323 @@
/*
* Copyright 2004 The Aerospace Corporation. All rights reserved.
*
* 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 Aerospace Corporation may not be used to endorse or
* promote products derived from this software.
*
* THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION "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 AEROSPACE CORPORATION 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.
*
* Copyright (c) 1995
* Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* EUI-64 conversion and lookup routines
*
*
* Converted from ether_addr.c rev
* FreeBSD: src/lib/libc/net/eui64.c,v 1.15 2002/04/08 07:51:10 ru Exp
* by Brooks Davis
*
* Written by Bill Paul <wpaul@ctr.columbia.edu>
* Center for Telecommunications Research
* Columbia University, New York City
*/
#ifndef __HAIKU__
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/lib/libc/net/eui64.c,v 1.2 2004/06/01 19:30:13 brooks Exp $");
#endif
#include <stdio.h>
#ifndef __HAIKU__
#include <paths.h>
#endif
#include <sys/types.h>
#ifdef __HAIKU__
#include "eui64.h"
#else
#include <sys/eui64.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <sys/param.h>
#ifndef __HAIKU__
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#ifndef _PATH_EUI64
#define _PATH_EUI64 "/etc/eui64"
#endif
static int eui64_line(const char *l, struct eui64 *e, char *hostname,
size_t len);
/*
* Parse a string of text containing an EUI-64 and hostname
* and separate it into its component parts.
*/
static int
eui64_line(const char *l, struct eui64 *e, char *hostname, size_t len)
{
char *line, *linehead, *cur;
linehead = strdup(l);
if (linehead == NULL)
return (-1);
line = linehead;
/* Find and parse the EUI64 */
while ((cur = strsep(&line, " \t\r\n")) != NULL) {
if (*cur != '\0') {
if (eui64_aton(cur, e) == 0)
break;
else
goto bad;
}
}
/* Find the hostname */
while ((cur = strsep(&line, " \t\r\n")) != NULL) {
if (*cur != '\0') {
if (strlcpy(hostname, cur, len) <= len)
break;
else
goto bad;
}
}
/* Make sure what remains is either whitespace or a comment */
while ((cur = strsep(&line, " \t\r\n")) != NULL) {
if (*cur == '#')
break;
if (*cur != '\0')
goto bad;
}
return (0);
bad:
free(linehead);
return (-1);
}
#endif
/*
* Convert an ASCII representation of an EUI-64 to binary form.
*/
int
eui64_aton(const char *a, struct eui64 *e)
{
int i;
unsigned int o0, o1, o2, o3, o4, o5, o6, o7;
/* canonical form */
i = sscanf(a, "%x-%x-%x-%x-%x-%x-%x-%x",
&o0, &o1, &o2, &o3, &o4, &o5, &o6, &o7);
if (i == EUI64_LEN)
goto good;
/* ethernet form */
i = sscanf(a, "%x:%x:%x:%x:%x:%x:%x:%x",
&o0, &o1, &o2, &o3, &o4, &o5, &o6, &o7);
if (i == EUI64_LEN)
goto good;
/* classic fwcontrol/dconschat form */
i = sscanf(a, "0x%2x%2x%2x%2x%2x%2x%2x%2x",
&o0, &o1, &o2, &o3, &o4, &o5, &o6, &o7);
if (i == EUI64_LEN)
goto good;
/* MAC format (-) */
i = sscanf(a, "%x-%x-%x-%x-%x-%x",
&o0, &o1, &o2, &o5, &o6, &o7);
if (i == 6) {
o3 = 0xff;
o4 = 0xfe;
goto good;
}
/* MAC format (:) */
i = sscanf(a, "%x:%x:%x:%x:%x:%x",
&o0, &o1, &o2, &o5, &o6, &o7);
if (i == 6) {
o3 = 0xff;
o4 = 0xfe;
goto good;
}
return (-1);
good:
e->octet[0]=o0;
e->octet[1]=o1;
e->octet[2]=o2;
e->octet[3]=o3;
e->octet[4]=o4;
e->octet[5]=o5;
e->octet[6]=o6;
e->octet[7]=o7;
return (0);
}
/*
* Convert a binary representation of an EUI-64 to an ASCII string.
*/
int
eui64_ntoa(const struct eui64 *id, char *a, size_t len)
{
int i;
i = snprintf(a, len, "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
id->octet[0], id->octet[1], id->octet[2], id->octet[3],
id->octet[4], id->octet[5], id->octet[6], id->octet[7]);
if (i < 23 || i >= len)
return (-1);
return (0);
}
#ifndef __HAIKU__
/*
* Map an EUI-64 to a hostname. Use either /etc/eui64 or NIS/YP.
*/
int
eui64_ntohost(char *hostname, size_t len, const struct eui64 *id)
{
FILE *fp;
char buf[BUFSIZ + 2];
struct eui64 local_eui64;
char local_host[MAXHOSTNAMELEN];
#ifdef YP
char *result;
int resultlen;
char eui64_a[24];
char *yp_domain;
#endif
if ((fp = fopen(_PATH_EUI64, "r")) == NULL)
return (1);
while (fgets(buf,BUFSIZ,fp)) {
if (buf[0] == '#')
continue;
#ifdef YP
if (buf[0] == '+') {
if (yp_get_default_domain(&yp_domain))
continue;
eui64_ntoa(id, eui64_a, sizeof(eui64_a));
if (yp_match(yp_domain, "eui64.byid", eui64_a,
strlen(eui64_a), &result, &resultlen)) {
continue;
}
strncpy(buf, result, resultlen);
buf[resultlen] = '\0';
free(result);
}
#endif
if (eui64_line(buf, &local_eui64, local_host,
sizeof(local_host)) == 0) {
if (bcmp(&local_eui64.octet[0],
&id->octet[0], EUI64_LEN) == 0) {
/* We have a match */
strcpy(hostname, local_host);
fclose(fp);
return(0);
}
}
}
fclose(fp);
return (1);
}
/*
* Map a hostname to an EUI-64 using /etc/eui64 or NIS/YP.
*/
int
eui64_hostton(const char *hostname, struct eui64 *id)
{
FILE *fp;
char buf[BUFSIZ + 2];
struct eui64 local_eui64;
char local_host[MAXHOSTNAMELEN];
#ifdef YP
char *result;
int resultlen;
char *yp_domain;
#endif
if ((fp = fopen(_PATH_EUI64, "r")) == NULL)
return (1);
while (fgets(buf,BUFSIZ,fp)) {
if (buf[0] == '#')
continue;
#ifdef YP
if (buf[0] == '+') {
if (yp_get_default_domain(&yp_domain))
continue;
if (yp_match(yp_domain, "eui64.byname", hostname,
strlen(hostname), &result, &resultlen)) {
continue;
}
strncpy(buf, result, resultlen);
buf[resultlen] = '\0';
free(result);
}
#endif
if (eui64_line(buf, &local_eui64, local_host,
sizeof(local_host)) == 0) {
if (strcmp(hostname, local_host) == 0) {
/* We have a match */
bcopy(&local_eui64, id, sizeof(struct eui64));
fclose(fp);
return(0);
}
}
}
fclose(fp);
return (1);
}
#endif

View File

@ -0,0 +1,204 @@
.\" Copyright (c) 2002 Hidetoshi Shimokawa
.\" All rights reserved.
.\"
.\" 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.
.\"
.\" 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.
.\"
.\" $FreeBSD: src/usr.sbin/fwcontrol/fwcontrol.8,v 1.18 2006/12/29 13:08:46 yar Exp $
.\"
.Dd October 24, 2006
.Dt FWCONTROL 8
.Os
.Sh NAME
.Nm fwcontrol
.Nd FireWire control utility
.Sh SYNOPSIS
.Nm
.Op Fl u Ar bus_num
.Op Fl prt
.Op Fl c Ar node
.Op Fl d Ar node
.Op Fl o Ar node
.Op Fl s Ar node
.Op Fl l Ar file
.Op Fl g Ar gap_count
.Op Fl b Ar pri_req
.Op Fl M Ar mode
.Op Fl R Ar filename
.Op Fl S Ar filename
.Op Fl m Ar EUI64 | hostname
.Sh DESCRIPTION
The
.Nm
utility is designed to provide a way for users to access and control the
.Fx
FireWire subsystem.
Without options,
.Nm
will output a list of devices that are/were connected to the bus.
.Pp
The following options are available:
.Bl -tag -width indent
.It Fl u Ar bus_num
Specify the FireWire bus number to be operated on.
.It Fl r
Initiate bus reset.
.It Fl t
Show the topology map.
.It Fl p
Dump PHY registers.
.It Fl c Ar node
Show the configuration ROM on the node.
.It Fl d Ar node
Hex dump of the configuration ROM.
.It Fl o Ar node
Send a link-on PHY packet to the node.
.It Fl s Ar node
Write to the
.Dv RESET_START
register on the node.
.It Fl l Ar file
Load hex dump file of the configuration ROM and parse it.
.It Fl g Ar gap_count
Broadcast
.Ar gap_count
by phy_config packet.
.It Fl i Ar pri_req
Set the
.Dv PRIORITY_BUDGET
register on all supported nodes.
.It Fl M Ar mode
Explicitly specify either
.Ar dv
or
.Ar mpeg
mode for the incoming stream.
Only meaningful in case of and must precede the
.Fl R
option. If not specified, the program will try to guess. If you get
an error complaining about "format 0x20", try to force the "mpeg" mode.
.It Fl R Ar filename
Receive DV or MPEG TS stream and dump it to a file.
Use Ctrl-C to stop the receiving.
Some DV cameras seem not to send the stream if a bus manager exits.
If you cannot get the stream, try the following commands:
.Bd -literal -offset indent
sysctl hw.firewire.try_bmr=0
fwcontrol -r
.Ed
.Pp
The resulting file contains raw DV data excluding isochronous header
and CIP header.
It can be handled by
.Nm libdv
in the
.Fx
Ports Collection. Resulting MPEG TS stream can be played and sent over a
network using the VideoLAN
.Nm vlc
tool in the
.Fx
Ports Collection. The stream can be piped directly to
.Nm vlc,
see EXAMPLES.
.It Fl S Ar filename
Send a DV file as isochronous stream.
.It Fl m Ar EUI64 | hostname
Set default fwmem target.
Hostname will be converted to EUI64 using
.Xr eui64 5 .
.El
.Sh FILES
.Bl -tag
.It Pa /dev/fw0.0
.El
.Sh EXAMPLES
Each DV frame has a fixed size and it is easy to edit the frame order.
.Pp
.Dl "fwcontrol -R original.dv"
.Pp
Receive a DV stream with DV camera attached.
.Pp
.Dl "dd if=original.dv of=first.dv bs=120000 count=30"
.Pp
Get first 30 frames(NTSC).
.Pp
.Dl "dd if=original.dv of=second.dv bs=120000 skip=30 count=30"
.Pp
Get second 30 frames(NTSC).
.Pp
.Dl "cat second.dv first.dv | fwcontrol -S /dev/stdin"
.Pp
Swap first and second 30 frames and send them to DV recorder.
.Pp
For PAL, replace
.Dq Li bs=120000
with
.Dq Li bs=144000 .
.Pp
.Dl "fwcontrol -R file.m2t
.Pp
Receive an MPEG TS stream from a camera producing MPEG transport stream. This
has been tested with SONY HDR-FX1E camera that produces HD MPEG-2 stream at
25 Mbps bandwidth.
.Pp
To send the stream from the camera over the network using TCP (which supprisingly works better with vlc), you can use
.Dl "fwcontrol -R - | nc 192.168.10.11 9000
with
.Nm netcat
from ports and to receive the stream, use
.Dl nc -l -p 9000 | vlc -
.Pp
To netcast via UDP, you need to use
.Nm buffer
program from ports, since vlc is not fast enough to read UDP packets from
buffers and thus it experiences dropouts when run directly. The sending side
can use
.Dl "fwcontrol -R - | nc 192.168.10.11 9000
and to receive the stream, use
.Dl nc -l -u -p 9000 | buffer -s 10k -b 1000 -m 20m -p 5 | vlc -
.Pp
.Pp
For more information on how to work with
.Nm vlc
see its docs.
.Sh SEE ALSO
.Xr firewire 4 ,
.Xr fwe 4 ,
.Xr fwip 4 ,
.Xr fwohci 4 ,
.Xr sbp 4 ,
.Xr mplayer 1 ,
.Xr vlc 1
.Sh HISTORY
The
.Nm
utility first appeared in
.Fx 5.0 .
.Sh AUTHORS
.An Hidetoshi Shimokawa Aq simokawa@FreeBSD.org
.An Petr Holub Aq hopet@ics.muni.cz
- MPEG TS mode.
.Sh BUGS
This utility is still under development and provided for debugging purposes.
Especially MPEG TS reception support is very rudimental and supports only
high-bandwidth MPEG-2 streams (fn field in CIP header equals 3).

View File

@ -0,0 +1,833 @@
/*
* Copyright (C) 2002
* Hidetoshi Shimokawa. All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by Hidetoshi Shimokawa.
*
* 4. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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 __HAIKU__
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/usr.sbin/fwcontrol/fwcontrol.c,v 1.23 2006/10/26 22:33:38 imp Exp $");
#endif
#ifdef __HAIKU__
#include <sys/param.h>
#include <sys/types.h>
#include "eui64.h"
#include "firewire.h"
#include "iec13213.h"
#include "fwphyreg.h"
#include "iec68113.h"
#include <stdint.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#else
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/errno.h>
#include <sys/eui64.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec13213.h>
#include <dev/firewire/fwphyreg.h>
#include <dev/firewire/iec68113.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <err.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#endif
#include <unistd.h>
#include "fwmethods.h"
#ifndef __HAIKU__
static void sysctl_set_int(const char *, int);
#endif
static void
usage(void)
{
fprintf(stderr,
"fwcontrol [-u bus_num] [-rt] [-g gap_count] [-o node] "
"[-b pri_req] [-c node] [-d node] [-l file] "
#ifdef __HAIKU__
"[-R file] [-S file] \n"
#else
"[-R file] [-S file] [-m target]\n"
#endif
"\t-u: specify bus number\n"
"\t-g: broadcast gap_count by phy_config packet\n"
"\t-o: send link-on packet to the node\n"
"\t-s: write RESET_START register on the node\n"
"\t-b: set PRIORITY_BUDGET register on all supported nodes\n"
"\t-c: read configuration ROM\n"
"\t-r: bus reset\n"
"\t-t: read topology map\n"
"\t-d: hex dump of configuration ROM\n"
"\t-l: load and parse hex dump file of configuration ROM\n"
"\t-R: Receive DV or MPEG TS stream\n"
#ifdef __HAIKU__
"\t-S: Send DV stream\n");
#else
"\t-S: Send DV stream\n"
"\t-m: set fwmem target\n");
#endif
exit(EX_USAGE);
}
static void
fweui2eui64(const struct fw_eui64 *fweui, struct eui64 *eui)
{
*(u_int32_t*)&(eui->octet[0]) = htonl(fweui->hi);
*(u_int32_t*)&(eui->octet[4]) = htonl(fweui->lo);
}
static struct fw_devlstreq *
get_dev(int fd)
{
struct fw_devlstreq *data;
data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq));
if (data == NULL)
err(1, "malloc");
if( ioctl(fd, FW_GDEVLST, data) < 0) {
err(1, "ioctl");
}
return data;
}
static int
str2node(int fd, const char *nodestr)
{
struct eui64 eui, tmpeui;
struct fw_devlstreq *data;
char *endptr;
int i, node;
if (nodestr == '\0')
return (-1);
/*
* Deal with classic node specifications.
*/
node = strtol(nodestr, &endptr, 0);
if (*endptr == '\0')
goto gotnode;
/*
* Try to get an eui and match it against available nodes.
*/
#ifdef __HAIKU__
if (eui64_aton(nodestr, &eui) != 0)
#else
if (eui64_hostton(nodestr, &eui) != 0 && eui64_aton(nodestr, &eui) != 0)
#endif
return (-1);
data = get_dev(fd);
for (i = 0; i < data->info_len; i++) {
fweui2eui64(&data->dev[i].eui, &tmpeui);
if (memcmp(&eui, &tmpeui, sizeof(struct eui64)) == 0) {
node = data->dev[i].dst;
goto gotnode;
}
}
if (i >= data->info_len)
return (-1);
gotnode:
if (node < 0 || node > 63)
return (-1);
else
return (node);
}
static void
list_dev(int fd)
{
struct fw_devlstreq *data;
struct fw_devinfo *devinfo;
struct eui64 eui;
char addr[EUI64_SIZ];
int i;
data = get_dev(fd);
printf("%d devices (info_len=%d)\n", data->n, data->info_len);
printf("node EUI64 status\n");
for (i = 0; i < data->info_len; i++) {
devinfo = &data->dev[i];
fweui2eui64(&devinfo->eui, &eui);
eui64_ntoa(&eui, addr, sizeof(addr));
printf("%4d %s %6d\n",
(devinfo->status || i == 0) ? devinfo->dst : -1,
addr,
devinfo->status
);
}
free((void *)data);
}
static u_int32_t
read_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int readmode, u_int32_t data)
{
struct fw_asyreq *asyreq;
u_int32_t *qld, res;
asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16);
asyreq->req.len = 16;
#if 0
asyreq->req.type = FWASREQNODE;
asyreq->pkt.mode.rreqq.dst = FWLOCALBUS | node;
#else
asyreq->req.type = FWASREQEUI;
asyreq->req.dst.eui = eui;
#endif
asyreq->pkt.mode.rreqq.tlrt = 0;
if (readmode)
asyreq->pkt.mode.rreqq.tcode = FWTCODE_RREQQ;
else
asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ;
asyreq->pkt.mode.rreqq.dest_hi = 0xffff;
asyreq->pkt.mode.rreqq.dest_lo = addr_lo;
qld = (u_int32_t *)&asyreq->pkt;
if (!readmode)
asyreq->pkt.mode.wreqq.data = data;
if (ioctl(fd, FW_ASYREQ, asyreq) < 0) {
err(1, "ioctl");
}
res = qld[3];
free(asyreq);
if (readmode)
return ntohl(res);
else
return 0;
}
static void
send_phy_config(int fd, int root_node, int gap_count)
{
struct fw_asyreq *asyreq;
asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12);
asyreq->req.len = 12;
asyreq->req.type = FWASREQNODE;
asyreq->pkt.mode.ld[0] = 0;
asyreq->pkt.mode.ld[1] = 0;
asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
if (root_node >= 0)
asyreq->pkt.mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23;
if (gap_count >= 0)
asyreq->pkt.mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16;
asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
printf("send phy_config root_node=%d gap_count=%d\n",
root_node, gap_count);
if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
err(1, "ioctl");
free(asyreq);
}
static void
send_link_on(int fd, int node)
{
struct fw_asyreq *asyreq;
asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12);
asyreq->req.len = 12;
asyreq->req.type = FWASREQNODE;
asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
asyreq->pkt.mode.ld[1] |= (1 << 30) | ((node & 0x3f) << 24);
asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
err(1, "ioctl");
free(asyreq);
}
static void
reset_start(int fd, int node)
{
struct fw_asyreq *asyreq;
asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16);
asyreq->req.len = 16;
asyreq->req.type = FWASREQNODE;
asyreq->pkt.mode.wreqq.dst = FWLOCALBUS | (node & 0x3f);
asyreq->pkt.mode.wreqq.tlrt = 0;
asyreq->pkt.mode.wreqq.tcode = FWTCODE_WREQQ;
asyreq->pkt.mode.wreqq.dest_hi = 0xffff;
asyreq->pkt.mode.wreqq.dest_lo = 0xf0000000 | RESET_START;
asyreq->pkt.mode.wreqq.data = htonl(0x1);
if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
err(1, "ioctl");
free(asyreq);
}
static void
set_pri_req(int fd, u_int32_t pri_req)
{
struct fw_devlstreq *data;
struct fw_devinfo *devinfo;
struct eui64 eui;
char addr[EUI64_SIZ];
u_int32_t max, reg, old;
int i;
data = get_dev(fd);
#define BUGET_REG 0xf0000218
for (i = 0; i < data->info_len; i++) {
devinfo = &data->dev[i];
if (!devinfo->status)
continue;
reg = read_write_quad(fd, devinfo->eui, BUGET_REG, 1, 0);
fweui2eui64(&devinfo->eui, &eui);
eui64_ntoa(&eui, addr, sizeof(addr));
printf("%d %s, %08x",
devinfo->dst, addr, reg);
if (reg > 0) {
old = (reg & 0x3f);
max = (reg & 0x3f00) >> 8;
if (pri_req > max)
pri_req = max;
printf(" 0x%x -> 0x%x\n", old, pri_req);
read_write_quad(fd, devinfo->eui, BUGET_REG, 0, pri_req);
} else {
printf("\n");
}
}
free((void *)data);
}
static void
parse_bus_info_block(u_int32_t *p)
{
char addr[EUI64_SIZ];
struct bus_info *bi;
struct eui64 eui;
bi = (struct bus_info *)p;
fweui2eui64(&bi->eui64, &eui);
eui64_ntoa(&eui, addr, sizeof(addr));
printf("bus_name: 0x%04x\n"
"irmc:%d cmc:%d isc:%d bmc:%d pmc:%d\n"
"cyc_clk_acc:%d max_rec:%d max_rom:%d\n"
"generation:%d link_spd:%d\n"
"EUI64: %s\n",
bi->bus_name,
bi->irmc, bi->cmc, bi->isc, bi->bmc, bi->pmc,
bi->cyc_clk_acc, bi->max_rec, bi->max_rom,
bi->generation, bi->link_spd,
addr);
}
static int
get_crom(int fd, int node, void *crom_buf, int len)
{
struct fw_crom_buf buf;
int i, error;
struct fw_devlstreq *data;
data = get_dev(fd);
for (i = 0; i < data->info_len; i++) {
if (data->dev[i].dst == node && data->dev[i].eui.lo != 0)
break;
}
if (i == data->info_len)
errx(1, "no such node %d.", node);
else
buf.eui = data->dev[i].eui;
free((void *)data);
buf.len = len;
buf.ptr = crom_buf;
bzero(crom_buf, len);
if ((error = ioctl(fd, FW_GCROM, &buf)) < 0) {
err(1, "ioctl");
}
return error;
}
static void
show_crom(u_int32_t *crom_buf)
{
int i;
struct crom_context cc;
char *desc, info[256];
static const char *key_types = "ICLD";
struct csrreg *reg;
struct csrdirectory *dir;
struct csrhdr *hdr;
u_int16_t crc;
printf("first quad: 0x%08x ", *crom_buf);
if (crom_buf[0] == 0) {
printf("(Invalid Configuration ROM)\n");
return;
}
hdr = (struct csrhdr *)crom_buf;
if (hdr->info_len == 1) {
/* minimum ROM */
reg = (struct csrreg *)hdr;
printf("verndor ID: 0x%06x\n", reg->val);
return;
}
printf("info_len=%d crc_len=%d crc=0x%04x",
hdr->info_len, hdr->crc_len, hdr->crc);
crc = crom_crc(crom_buf+1, hdr->crc_len);
if (crc == hdr->crc)
printf("(OK)\n");
else
printf("(NG)\n");
parse_bus_info_block(crom_buf+1);
crom_init_context(&cc, crom_buf);
dir = cc.stack[0].dir;
if (!dir) {
printf("no root directory - giving up\n");
return;
}
printf("root_directory: len=0x%04x(%d) crc=0x%04x",
dir->crc_len, dir->crc_len, dir->crc);
crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
if (crc == dir->crc)
printf("(OK)\n");
else
printf("(NG)\n");
if (dir->crc_len < 1)
return;
while (cc.depth >= 0) {
desc = crom_desc(&cc, info, sizeof(info));
reg = crom_get(&cc);
for (i = 0; i < cc.depth; i++)
printf("\t");
printf("%02x(%c:%02x) %06x %s: %s\n",
reg->key,
key_types[(reg->key & CSRTYPE_MASK)>>6],
reg->key & CSRKEY_MASK, reg->val,
desc, info);
crom_next(&cc);
}
}
#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
static void
dump_crom(u_int32_t *p)
{
int len=1024, i;
for (i = 0; i < len/(4*8); i ++) {
printf(DUMP_FORMAT,
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
p += 8;
}
}
static void
load_crom(char *filename, u_int32_t *p)
{
FILE *file;
int len=1024, i;
if ((file = fopen(filename, "r")) == NULL)
err(1, "load_crom");
for (i = 0; i < len/(4*8); i ++) {
fscanf(file, DUMP_FORMAT,
p, p+1, p+2, p+3, p+4, p+5, p+6, p+7);
p += 8;
}
}
static void
show_topology_map(int fd)
{
struct fw_topology_map *tmap;
union fw_self_id sid;
int i;
static const char *port_status[] = {" ", "-", "P", "C"};
static const char *pwr_class[] = {" 0W", "15W", "30W", "45W",
"-1W", "-2W", "-5W", "-9W"};
static const char *speed[] = {"S100", "S200", "S400", "S800"};
tmap = malloc(sizeof(struct fw_topology_map));
if (tmap == NULL)
return;
if (ioctl(fd, FW_GTPMAP, tmap) < 0) {
err(1, "ioctl");
}
printf("crc_len: %d generation:%d node_count:%d sid_count:%d\n",
tmap->crc_len, tmap->generation,
tmap->node_count, tmap->self_id_count);
printf("id link gap_cnt speed delay cIRM power port0 port1 port2"
" ini more\n");
for (i = 0; i < tmap->crc_len - 2; i++) {
sid = tmap->self_id[i];
if (sid.p0.sequel) {
printf("%02d sequel packet\n", sid.p0.phy_id);
continue;
}
printf("%02d %2d %2d %4s %d %d %3s"
" %s %s %s %d %d\n",
sid.p0.phy_id,
sid.p0.link_active,
sid.p0.gap_count,
speed[sid.p0.phy_speed],
sid.p0.phy_delay,
sid.p0.contender,
pwr_class[sid.p0.power_class],
port_status[sid.p0.port0],
port_status[sid.p0.port1],
port_status[sid.p0.port2],
sid.p0.initiated_reset,
sid.p0.more_packets
);
}
free(tmap);
}
static void
read_phy_registers(int fd, u_int8_t *buf, int offset, int len)
{
struct fw_reg_req_t reg;
int i;
for (i = 0; i < len; i++) {
reg.addr = offset + i;
if (ioctl(fd, FWOHCI_RDPHYREG, &reg) < 0)
err(1, "ioctl");
buf[i] = (u_int8_t) reg.data;
printf("0x%02x ", reg.data);
}
printf("\n");
}
static void
read_phy_page(int fd, u_int8_t *buf, int page, int port)
{
struct fw_reg_req_t reg;
reg.addr = 0x7;
reg.data = ((page & 7) << 5) | (port & 0xf);
if (ioctl(fd, FWOHCI_WRPHYREG, &reg) < 0)
err(1, "ioctl");
read_phy_registers(fd, buf, 8, 8);
}
static void
dump_phy_registers(int fd)
{
struct phyreg_base b;
struct phyreg_page0 p;
struct phyreg_page1 v;
int i;
printf("=== base register ===\n");
read_phy_registers(fd, (u_int8_t *)&b, 0, 8);
printf(
"Physical_ID:%d R:%d CPS:%d\n"
"RHB:%d IBR:%d Gap_Count:%d\n"
"Extended:%d Num_Ports:%d\n"
"PHY_Speed:%d Delay:%d\n"
"LCtrl:%d C:%d Jitter:%d Pwr_Class:%d\n"
"WDIE:%d ISBR:%d CTOI:%d CPSI:%d STOI:%d PEI:%d EAA:%d EMC:%d\n"
"Max_Legacy_SPD:%d BLINK:%d Bridge:%d\n"
"Page_Select:%d Port_Select%d\n",
b.phy_id, b.r, b.cps,
b.rhb, b.ibr, b.gap_count,
b.extended, b.num_ports,
b.phy_speed, b.delay,
b.lctrl, b.c, b.jitter, b.pwr_class,
b.wdie, b.isbr, b.ctoi, b.cpsi, b.stoi, b.pei, b.eaa, b.emc,
b.legacy_spd, b.blink, b.bridge,
b.page_select, b.port_select
);
for (i = 0; i < b.num_ports; i ++) {
printf("\n=== page 0 port %d ===\n", i);
read_phy_page(fd, (u_int8_t *)&p, 0, i);
printf(
"Astat:%d BStat:%d Ch:%d Con:%d RXOK:%d Dis:%d\n"
"Negotiated_speed:%d PIE:%d Fault:%d Stanby_fault:%d Disscrm:%d B_Only:%d\n"
"DC_connected:%d Max_port_speed:%d LPP:%d Cable_speed:%d\n"
"Connection_unreliable:%d Beta_mode:%d\n"
"Port_error:0x%x\n"
"Loop_disable:%d In_standby:%d Hard_disable:%d\n",
p.astat, p.bstat, p.ch, p.con, p.rxok, p.dis,
p.negotiated_speed, p.pie, p.fault, p.stanby_fault, p.disscrm, p.b_only,
p.dc_connected, p.max_port_speed, p.lpp, p.cable_speed,
p.connection_unreliable, p.beta_mode,
p.port_error,
p.loop_disable, p.in_standby, p.hard_disable
);
}
printf("\n=== page 1 ===\n");
read_phy_page(fd, (u_int8_t *)&v, 1, 0);
printf(
"Compliance:%d\n"
"Vendor_ID:0x%06x\n"
"Product_ID:0x%06x\n",
v.compliance,
(v.vendor_id[0] << 16) | (v.vendor_id[1] << 8) | v.vendor_id[2],
(v.product_id[0] << 16) | (v.product_id[1] << 8) | v.product_id[2]
);
}
static void
open_dev(int *fd, char *devbase)
{
char name[256];
int i;
if (*fd < 0) {
for (i = 0; i < 4; i++) {
snprintf(name, sizeof(name), "%s.%d", devbase, i);
if ((*fd = open(name, O_RDWR)) >= 0)
break;
}
if (*fd < 0)
err(1, "open");
}
}
#ifndef __HAIKU__
static void
sysctl_set_int(const char *name, int val)
{
if (sysctlbyname(name, NULL, NULL, &val, sizeof(int)) < 0)
err(1, "sysctl %s failed.", name);
}
#endif
static fwmethod *
detect_recv_fn(int fd, char ich)
{
char *buf;
struct fw_isochreq isoreq;
struct fw_isobufreq bufreq;
int len;
u_int32_t *ptr;
struct ciphdr *ciph;
fwmethod *retfn;
bufreq.rx.nchunk = 8;
bufreq.rx.npacket = 16;
bufreq.rx.psize = 1024;
bufreq.tx.nchunk = 0;
bufreq.tx.npacket = 0;
bufreq.tx.psize = 0;
if (ioctl(fd, FW_SSTBUF, &bufreq) < 0)
err(1, "ioctl FW_SSTBUF");
isoreq.ch = ich & 0x3f;
isoreq.tag = (ich >> 6) & 3;
if (ioctl(fd, FW_SRSTREAM, &isoreq) < 0)
err(1, "ioctl FW_SRSTREAM");
buf = (char *)malloc(1024*16);
len = read(fd, buf, 1024*16);
ptr = (u_int32_t *) buf;
ciph = (struct ciphdr *)(ptr + 1);
switch(ciph->fmt) {
case CIP_FMT_DVCR:
fprintf(stderr, "Detected DV format on input.\n");
retfn = dvrecv;
break;
case CIP_FMT_MPEG:
fprintf(stderr, "Detected MPEG TS format on input.\n");
retfn = mpegtsrecv;
break;
default:
errx(1, "Unsupported format for receiving: fmt=0x%x", ciph->fmt);
}
free(buf);
return retfn;
}
int
main(int argc, char **argv)
{
u_int32_t crom_buf[1024/4];
#ifdef __HAIKU__
char devbase[1024] = "/dev/fw";
#else
char devbase[1024] = "/dev/fw0";
#endif
int fd, ch, len=1024;
long tmp;
struct fw_eui64 eui;
struct eui64 target;
fwmethod *recvfn = NULL;
fd = -1;
if (argc < 2) {
open_dev(&fd, devbase);
list_dev(fd);
}
#ifdef __HAIKU__
while ((ch = getopt(argc, argv, "M:g:o:s:b:prtc:d:l:u:R:S:")) != -1)
#else
while ((ch = getopt(argc, argv, "M:g:m:o:s:b:prtc:d:l:u:R:S:")) != -1)
#endif
switch(ch) {
case 'b':
tmp = strtol(optarg, NULL, 0);
if (tmp < 0 || tmp > (long)0xffffffff)
errx(EX_USAGE, "invalid number: %s", optarg);
open_dev(&fd, devbase);
set_pri_req(fd, tmp);
break;
case 'c':
open_dev(&fd, devbase);
tmp = str2node(fd, optarg);
get_crom(fd, tmp, crom_buf, len);
show_crom(crom_buf);
break;
case 'd':
open_dev(&fd, devbase);
tmp = str2node(fd, optarg);
get_crom(fd, tmp, crom_buf, len);
dump_crom(crom_buf);
break;
case 'g':
tmp = strtol(optarg, NULL, 0);
open_dev(&fd, devbase);
send_phy_config(fd, -1, tmp);
break;
case 'l':
load_crom(optarg, crom_buf);
show_crom(crom_buf);
break;
#ifndef __HAIKU__
case 'm':
if (eui64_hostton(optarg, &target) != 0 &&
eui64_aton(optarg, &target) != 0)
errx(EX_USAGE, "invalid target: %s", optarg);
eui.hi = ntohl(*(u_int32_t*)&(target.octet[0]));
eui.lo = ntohl(*(u_int32_t*)&(target.octet[4]));
sysctl_set_int("hw.firewire.fwmem.eui64_hi", eui.hi);
sysctl_set_int("hw.firewire.fwmem.eui64_lo", eui.lo);
break;
#endif
case 'o':
open_dev(&fd, devbase);
tmp = str2node(fd, optarg);
send_link_on(fd, tmp);
break;
case 'p':
open_dev(&fd, devbase);
dump_phy_registers(fd);
break;
case 'r':
open_dev(&fd, devbase);
if(ioctl(fd, FW_IBUSRST, &tmp) < 0)
err(1, "ioctl");
break;
case 's':
open_dev(&fd, devbase);
tmp = str2node(fd, optarg);
reset_start(fd, tmp);
break;
case 't':
open_dev(&fd, devbase);
show_topology_map(fd);
break;
case 'u':
tmp = strtol(optarg, NULL, 0);
snprintf(devbase, sizeof(devbase), "/dev/fw%ld", tmp);
if (fd > 0) {
close(fd);
fd = -1;
}
if (argc == optind) {
open_dev(&fd, devbase);
list_dev(fd);
}
break;
#define TAG (1<<6)
#define CHANNEL 63
case 'M':
switch (optarg[0]) {
case 'm':
recvfn = mpegtsrecv;
break;
case 'd':
recvfn = dvrecv;
break;
default:
errx(EX_USAGE, "unrecognized method: %s",
optarg);
}
break;
case 'R':
open_dev(&fd, devbase);
if (recvfn == NULL) /* guess... */
recvfn = detect_recv_fn(fd, TAG | CHANNEL);
close(fd);
fd = -1;
open_dev(&fd, devbase);
(*recvfn)(fd, optarg, TAG | CHANNEL, -1);
break;
case 'S':
open_dev(&fd, devbase);
dvsend(fd, optarg, TAG | CHANNEL, -1);
break;
default:
usage();
}
return 0;
}

652
src/bin/fwcontrol/fwcrom.c Normal file
View File

@ -0,0 +1,652 @@
/*-
* Copyright (c) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by Hidetoshi Shimokawa.
*
* 4. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*/
#ifdef __FreeBSD__
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/dev/firewire/fwcrom.c,v 1.14 2006/02/04 21:37:39 imp Exp $");
#endif
#include <sys/param.h>
#ifdef _BOOT
#include <stand.h>
#include <bootstrap.h>
#else
#if defined(_KERNEL) || defined(TEST)
#ifdef __HAIKU__
#include "queue.h"
#else
#include <sys/queue.h>
#endif
#endif
#ifdef _KERNEL
#ifndef __HAIKU__
#include <sys/systm.h>
#include <sys/kernel.h>
#endif
#else
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <err.h>
#include <stdlib.h>
#include <string.h>
#endif
#endif
#ifdef __HAIKU__
#include <stdint.h>
#endif
#if defined( __DragonFly__) || defined(__HAIKU__)
#include "firewire.h"
#include "iec13213.h"
#define vm_offset_t uint32_t
#else
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec13213.h>
#endif
#define MAX_ROM (1024 - sizeof(uint32_t) * 5)
#define CROM_END(cc) ((vm_offset_t)(cc)->stack[0].dir + MAX_ROM - 1)
void
crom_init_context(struct crom_context *cc, uint32_t *p)
{
struct csrhdr *hdr;
hdr = (struct csrhdr *)p;
if (hdr->info_len <= 1) {
/* minimum or invalid ROM */
cc->depth = -1;
return;
}
p += 1 + hdr->info_len;
/* check size of root directory */
if (((struct csrdirectory *)p)->crc_len == 0) {
cc->depth = -1;
return;
}
cc->depth = 0;
cc->stack[0].dir = (struct csrdirectory *)p;
cc->stack[0].index = 0;
}
struct csrreg *
crom_get(struct crom_context *cc)
{
struct crom_ptr *ptr;
ptr = &cc->stack[cc->depth];
return (&ptr->dir->entry[ptr->index]);
}
void
crom_next(struct crom_context *cc)
{
struct crom_ptr *ptr;
struct csrreg *reg;
if (cc->depth < 0)
return;
reg = crom_get(cc);
if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) {
if (cc->depth >= CROM_MAX_DEPTH) {
printf("crom_next: too deep\n");
goto again;
}
cc->depth ++;
ptr = &cc->stack[cc->depth];
ptr->dir = (struct csrdirectory *) (reg + reg->val);
ptr->index = 0;
goto check;
}
again:
ptr = &cc->stack[cc->depth];
ptr->index ++;
check:
if (ptr->index < ptr->dir->crc_len &&
(vm_offset_t)crom_get(cc) <= CROM_END(cc))
return;
if (ptr->index < ptr->dir->crc_len)
printf("crom_next: bound check failed\n");
if (cc->depth > 0) {
cc->depth--;
goto again;
}
/* no more data */
cc->depth = -1;
}
struct csrreg *
crom_search_key(struct crom_context *cc, uint8_t key)
{
struct csrreg *reg;
while(cc->depth >= 0) {
reg = crom_get(cc);
if (reg->key == key)
return reg;
crom_next(cc);
}
return NULL;
}
int
crom_has_specver(uint32_t *p, uint32_t spec, uint32_t ver)
{
struct csrreg *reg;
struct crom_context c, *cc;
int state = 0;
cc = &c;
crom_init_context(cc, p);
while(cc->depth >= 0) {
reg = crom_get(cc);
if (state == 0) {
if (reg->key == CSRKEY_SPEC && reg->val == spec)
state = 1;
else
state = 0;
} else {
if (reg->key == CSRKEY_VER && reg->val == ver)
return 1;
else
state = 0;
}
crom_next(cc);
}
return 0;
}
void
crom_parse_text(struct crom_context *cc, char *buf, int len)
{
struct csrreg *reg;
struct csrtext *textleaf;
uint32_t *bp;
int i, qlen;
static char *nullstr = "(null)";
if (cc->depth < 0)
return;
reg = crom_get(cc);
if (reg->key != CROM_TEXTLEAF ||
(vm_offset_t)(reg + reg->val) > CROM_END(cc)) {
strncpy(buf, nullstr, len);
return;
}
textleaf = (struct csrtext *)(reg + reg->val);
if ((vm_offset_t)textleaf + textleaf->crc_len > CROM_END(cc)) {
strncpy(buf, nullstr, len);
return;
}
/* XXX should check spec and type */
bp = (uint32_t *)&buf[0];
qlen = textleaf->crc_len - 2;
if (len < qlen * 4)
qlen = len/4;
for (i = 0; i < qlen; i ++)
*bp++ = ntohl(textleaf->text[i]);
/* make sure to terminate the string */
if (len <= qlen * 4)
buf[len - 1] = 0;
else
buf[qlen * 4] = 0;
}
uint16_t
crom_crc(uint32_t *ptr, int len)
{
int i, shift;
uint32_t data, sum, crc = 0;
for (i = 0; i < len; i++) {
data = ptr[i];
for (shift = 28; shift >= 0; shift -= 4) {
sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;
}
crc &= 0xffff;
}
return((uint16_t) crc);
}
#if !defined(_KERNEL) && !defined(_BOOT)
static void
crom_desc_specver(uint32_t spec, uint32_t ver, char *buf, int len)
{
char *s = NULL;
if (spec == CSRVAL_ANSIT10 || spec == 0) {
switch (ver) {
case CSRVAL_T10SBP2:
s = "SBP-2";
break;
default:
if (spec != 0)
s = "unknown ANSIT10";
}
}
if (spec == CSRVAL_1394TA || spec == 0) {
switch (ver) {
case CSR_PROTAVC:
s = "AV/C";
break;
case CSR_PROTCAL:
s = "CAL";
break;
case CSR_PROTEHS:
s = "EHS";
break;
case CSR_PROTHAVI:
s = "HAVi";
break;
case CSR_PROTCAM104:
s = "1394 Cam 1.04";
break;
case CSR_PROTCAM120:
s = "1394 Cam 1.20";
break;
case CSR_PROTCAM130:
s = "1394 Cam 1.30";
break;
case CSR_PROTDPP:
s = "1394 Direct print";
break;
case CSR_PROTIICP:
s = "Industrial & Instrument";
break;
default:
if (spec != 0)
s = "unknown 1394TA";
}
}
if (s != NULL)
snprintf(buf, len, "%s", s);
}
char *
crom_desc(struct crom_context *cc, char *buf, int len)
{
struct csrreg *reg;
struct csrdirectory *dir;
char *desc;
uint16_t crc;
reg = crom_get(cc);
switch (reg->key & CSRTYPE_MASK) {
case CSRTYPE_I:
#if 0
len -= snprintf(buf, len, "%d", reg->val);
buf += strlen(buf);
#else
*buf = '\0';
#endif
break;
case CSRTYPE_C:
len -= snprintf(buf, len, "offset=0x%04x(%d)",
reg->val, reg->val);
buf += strlen(buf);
break;
case CSRTYPE_L:
/* XXX fall through */
case CSRTYPE_D:
dir = (struct csrdirectory *) (reg + reg->val);
crc = crom_crc((uint32_t *)&dir->entry[0], dir->crc_len);
len -= snprintf(buf, len, "len=%d crc=0x%04x(%s) ",
dir->crc_len, dir->crc,
(crc == dir->crc) ? "OK" : "NG");
buf += strlen(buf);
}
switch (reg->key) {
case 0x03:
desc = "module_vendor_ID";
break;
case 0x04:
desc = "hardware_version";
break;
case 0x0c:
desc = "node_capabilities";
break;
case 0x12:
desc = "unit_spec_ID";
break;
case 0x13:
desc = "unit_sw_version";
crom_desc_specver(0, reg->val, buf, len);
break;
case 0x14:
desc = "logical_unit_number";
break;
case 0x17:
desc = "model_ID";
break;
case 0x38:
desc = "command_set_spec_ID";
break;
case 0x39:
desc = "command_set";
break;
case 0x3a:
desc = "unit_characteristics";
break;
case 0x3b:
desc = "command_set_revision";
break;
case 0x3c:
desc = "firmware_revision";
break;
case 0x3d:
desc = "reconnect_timeout";
break;
case 0x54:
desc = "management_agent";
break;
case 0x81:
desc = "text_leaf";
crom_parse_text(cc, buf + strlen(buf), len);
break;
case 0xd1:
desc = "unit_directory";
break;
case 0xd4:
desc = "logical_unit_directory";
break;
default:
desc = "unknown";
}
return desc;
}
#endif
#if defined(_KERNEL) || defined(_BOOT) || defined(TEST)
int
crom_add_quad(struct crom_chunk *chunk, uint32_t entry)
{
int index;
index = chunk->data.crc_len;
if (index >= CROM_MAX_CHUNK_LEN - 1) {
printf("too large chunk %d\n", index);
return(-1);
}
chunk->data.buf[index] = entry;
chunk->data.crc_len++;
return(index);
}
int
crom_add_entry(struct crom_chunk *chunk, int key, int val)
{
union
{
struct csrreg reg;
uint32_t i;
} foo;
foo.reg.key = key;
foo.reg.val = val;
return (crom_add_quad(chunk, foo.i));
}
int
crom_add_chunk(struct crom_src *src, struct crom_chunk *parent,
struct crom_chunk *child, int key)
{
int index;
if (parent == NULL) {
STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
return(0);
}
index = crom_add_entry(parent, key, 0);
if (index < 0) {
return(-1);
}
child->ref_chunk = parent;
child->ref_index = index;
STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
return(index);
}
#define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
int
crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent,
struct crom_chunk *chunk, char *buf)
{
struct csrtext *tl;
uint32_t *p;
int len, i;
char t[MAX_TEXT];
len = strlen(buf);
if (len > MAX_TEXT) {
#if defined(__DragonFly__) || __FreeBSD_version < 500000
printf("text(%d) trancated to %d.\n", len, MAX_TEXT);
#else
printf("text(%d) trancated to %td.\n", len, MAX_TEXT);
#endif
len = MAX_TEXT;
}
tl = (struct csrtext *) &chunk->data;
tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(uint32_t));
tl->spec_id = 0;
tl->spec_type = 0;
tl->lang_id = 0;
bzero(&t[0], roundup2(len, sizeof(uint32_t)));
bcopy(buf, &t[0], len);
p = (uint32_t *)&t[0];
for (i = 0; i < howmany(len, sizeof(uint32_t)); i ++)
tl->text[i] = ntohl(*p++);
return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF));
}
static int
crom_copy(uint32_t *src, uint32_t *dst, int *offset, int len, int maxlen)
{
if (*offset + len > maxlen) {
printf("Config. ROM is too large for the buffer\n");
return(-1);
}
bcopy(src, (char *)(dst + *offset), len * sizeof(uint32_t));
*offset += len;
return(0);
}
int
crom_load(struct crom_src *src, uint32_t *buf, int maxlen)
{
struct crom_chunk *chunk, *parent;
struct csrhdr *hdr;
#if defined(_KERNEL) || defined(_BOOT)
uint32_t *ptr;
int i;
#endif
int count, offset;
int len;
offset = 0;
/* Determine offset */
STAILQ_FOREACH(chunk, &src->chunk_list, link) {
chunk->offset = offset;
/* Assume the offset of the parent is already known */
parent = chunk->ref_chunk;
if (parent != NULL) {
struct csrreg *reg;
reg = (struct csrreg *)
&parent->data.buf[chunk->ref_index];
reg->val = offset -
(parent->offset + 1 + chunk->ref_index);
}
offset += 1 + chunk->data.crc_len;
}
/* Calculate CRC and dump to the buffer */
len = 1 + src->hdr.info_len;
count = 0;
if (crom_copy((uint32_t *)&src->hdr, buf, &count, len, maxlen) < 0)
return(-1);
STAILQ_FOREACH(chunk, &src->chunk_list, link) {
chunk->data.crc =
crom_crc(&chunk->data.buf[0], chunk->data.crc_len);
len = 1 + chunk->data.crc_len;
if (crom_copy((uint32_t *)&chunk->data, buf,
&count, len, maxlen) < 0)
return(-1);
}
hdr = (struct csrhdr *)buf;
hdr->crc_len = count - 1;
hdr->crc = crom_crc(&buf[1], hdr->crc_len);
#if defined(_KERNEL) || defined(_BOOT)
/* byte swap */
ptr = buf;
for (i = 0; i < count; i ++) {
*ptr = htonl(*ptr);
ptr++;
}
#endif
return(count);
}
#endif
#ifdef TEST
int
main () {
struct crom_src src;
struct crom_chunk root,unit1,unit2,unit3;
struct crom_chunk text1,text2,text3,text4,text5,text6,text7;
uint32_t buf[256], *p;
int i;
bzero(&src, sizeof(src));
bzero(&root, sizeof(root));
bzero(&unit1, sizeof(unit1));
bzero(&unit2, sizeof(unit2));
bzero(&unit3, sizeof(unit3));
bzero(&text1, sizeof(text1));
bzero(&text2, sizeof(text2));
bzero(&text3, sizeof(text3));
bzero(&text3, sizeof(text4));
bzero(&text3, sizeof(text5));
bzero(&text3, sizeof(text6));
bzero(&text3, sizeof(text7));
bzero(buf, sizeof(buf));
/* BUS info sample */
src.hdr.info_len = 4;
src.businfo.bus_name = CSR_BUS_NAME_IEEE1394;
src.businfo.eui64.hi = 0x11223344;
src.businfo.eui64.lo = 0x55667788;
src.businfo.link_spd = FWSPD_S400;
src.businfo.generation = 0;
src.businfo.max_rom = MAXROM_4;
src.businfo.max_rec = 10;
src.businfo.cyc_clk_acc = 100;
src.businfo.pmc = 0;
src.businfo.bmc = 1;
src.businfo.isc = 1;
src.businfo.cmc = 1;
src.businfo.irmc = 1;
STAILQ_INIT(&src.chunk_list);
/* Root directory */
crom_add_chunk(&src, NULL, &root, 0);
crom_add_entry(&root, CSRKEY_NCAP, 0x123456);
/* private company_id */
crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48);
#ifdef __DragonFly__
crom_add_simple_text(&src, &root, &text1, "DragonFly");
crom_add_entry(&root, CSRKEY_HW, __DragonFly_cc_version);
crom_add_simple_text(&src, &root, &text2, "DragonFly-1");
#else
crom_add_simple_text(&src, &root, &text1, "FreeBSD");
crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version);
crom_add_simple_text(&src, &root, &text2, "FreeBSD-5");
#endif
/* SBP unit directory */
crom_add_chunk(&src, &root, &unit1, CROM_UDIR);
crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10);
crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2);
crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI);
/* management_agent */
crom_add_entry(&unit1, CROM_MGM, 0x1000);
crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8);
/* Device type and LUN */
crom_add_entry(&unit1, CROM_LUN, 0);
crom_add_entry(&unit1, CSRKEY_MODEL, 1);
crom_add_simple_text(&src, &unit1, &text3, "scsi_target");
/* RFC2734 IPv4 over IEEE1394 */
crom_add_chunk(&src, &root, &unit2, CROM_UDIR);
crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF);
crom_add_simple_text(&src, &unit2, &text4, "IANA");
crom_add_entry(&unit2, CSRKEY_VER, 1);
crom_add_simple_text(&src, &unit2, &text5, "IPv4");
/* RFC3146 IPv6 over IEEE1394 */
crom_add_chunk(&src, &root, &unit3, CROM_UDIR);
crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF);
crom_add_simple_text(&src, &unit3, &text6, "IANA");
crom_add_entry(&unit3, CSRKEY_VER, 2);
crom_add_simple_text(&src, &unit3, &text7, "IPv6");
crom_load(&src, buf, 256);
p = buf;
#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
for (i = 0; i < 256/8; i ++) {
printf(DUMP_FORMAT,
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
p += 8;
}
return(0);
}
#endif

426
src/bin/fwcontrol/fwdv.c Normal file
View File

@ -0,0 +1,426 @@
/*
* Copyright (C) 2003
* Hidetoshi Shimokawa. All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by Hidetoshi Shimokawa.
*
* 4. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* $FreeBSD: src/usr.sbin/fwcontrol/fwdv.c,v 1.7 2007/06/17 10:20:55 simokawa Exp $
*/
#include <sys/param.h>
#ifndef __HAIKU__
#include <sys/ioctl.h>
#endif
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#if __FreeBSD_version >= 500000 || defined(__HAIKU__)
#include <arpa/inet.h>
#endif
#include <err.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __HAIKU__
#include <stdint.h>
#include "firewire.h"
#include "iec68113.h"
#else
#include <sysexits.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec68113.h>
#endif
#include "fwmethods.h"
#define DEBUG 0
#define FIX_FRAME 1
struct frac {
int n,d;
};
struct frac frame_cycle[2] = {
{8000*100, 2997}, /* NTSC 8000 cycle / 29.97 Hz */
{320, 1}, /* PAL 8000 cycle / 25 Hz */
};
int npackets[] = {
250 /* NTSC */,
300 /* PAL */
};
struct frac pad_rate[2] = {
{203, 2997}, /* = (8000 - 29.97 * 250)/(29.97 * 250) */
{1, 15}, /* = (8000 - 25 * 300)/(25 * 300) */
};
char *system_name[] = {"NTSC", "PAL"};
int frame_rate[] = {30, 25};
#define PSIZE 512
#define DSIZE 480
#define NCHUNK 64
#define NPACKET_R 256
#define NPACKET_T 255
#define TNBUF 100 /* XXX too large value causes block noise */
#define NEMPTY 10 /* depends on TNBUF */
#define RBUFSIZE (PSIZE * NPACKET_R)
#define MAXBLOCKS (300)
#define CYCLE_FRAC 0xc00
void
dvrecv(int d, const char *filename, char ich, int count)
{
struct fw_isochreq isoreq;
struct fw_isobufreq bufreq;
struct dvdbc *dv;
struct ciphdr *ciph;
struct fw_pkt *pkt;
char *pad, *buf;
u_int32_t *ptr;
int len, tlen, npad, fd, k, m, vec, system = -1, nb;
int nblocks[] = {250 /* NTSC */, 300 /* PAL */};
struct iovec wbuf[NPACKET_R];
if(strcmp(filename, "-") == 0) {
fd = STDOUT_FILENO;
} else {
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0660);
if (fd == -1)
err(EX_NOINPUT, filename);
}
buf = malloc(RBUFSIZE);
pad = malloc(DSIZE*MAXBLOCKS);
memset(pad, 0xff, DSIZE*MAXBLOCKS);
bzero(wbuf, sizeof(wbuf));
bufreq.rx.nchunk = NCHUNK;
bufreq.rx.npacket = NPACKET_R;
bufreq.rx.psize = PSIZE;
bufreq.tx.nchunk = 0;
bufreq.tx.npacket = 0;
bufreq.tx.psize = 0;
if (ioctl(d, FW_SSTBUF, &bufreq) < 0)
err(1, "ioctl FW_SSTBUF");
isoreq.ch = ich & 0x3f;
isoreq.tag = (ich >> 6) & 3;
if (ioctl(d, FW_SRSTREAM, &isoreq) < 0)
err(1, "ioctl");
k = m = 0;
while (count <= 0 || k <= count) {
#if 0
tlen = 0;
while ((len = read(d, buf + tlen, PSIZE
/* RBUFSIZE - tlen */)) > 0) {
if (len < 0) {
if (errno == EAGAIN) {
fprintf(stderr, "(EAGAIN)\n");
fflush(stderr);
if (len <= 0)
continue;
} else
err(1, "read failed");
}
tlen += len;
if ((RBUFSIZE - tlen) < PSIZE)
break;
};
#else
tlen = len = read(d, buf, RBUFSIZE);
if (len < 0) {
if (errno == EAGAIN) {
fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
fflush(stderr);
if (len <= 0)
continue;
} else
err(1, "read failed");
}
#endif
vec = 0;
ptr = (u_int32_t *) buf;
again:
pkt = (struct fw_pkt *) ptr;
#if DEBUG
fprintf(stderr, "%08x %08x %08x %08x\n",
htonl(ptr[0]), htonl(ptr[1]),
htonl(ptr[2]), htonl(ptr[3]));
#endif
ciph = (struct ciphdr *)(ptr + 1); /* skip iso header */
if (ciph->fmt != CIP_FMT_DVCR)
errx(1, "unknown format 0x%x", ciph->fmt);
ptr = (u_int32_t *) (ciph + 1); /* skip cip header */
#if DEBUG
if (ciph->fdf.dv.cyc != 0xffff && k == 0) {
fprintf(stderr, "0x%04x\n", ntohs(ciph->fdf.dv.cyc));
}
#endif
if (pkt->mode.stream.len <= sizeof(struct ciphdr))
/* no payload */
goto next;
for (dv = (struct dvdbc *)ptr;
(char *)dv < (char *)(ptr + ciph->len);
dv+=6) {
#if DEBUG
fprintf(stderr, "(%d,%d) ", dv->sct, dv->dseq);
#endif
if (dv->sct == DV_SCT_HEADER && dv->dseq == 0) {
if (system < 0) {
system = ciph->fdf.dv.fs;
fprintf(stderr, "%s\n", system_name[system]);
}
/* Fix DSF bit */
if (system == 1 &&
(dv->payload[0] & DV_DSF_12) == 0)
dv->payload[0] |= DV_DSF_12;
nb = nblocks[system];
fprintf(stderr, "%d", k%10);
#if FIX_FRAME
if (m > 0 && m != nb) {
/* padding bad frame */
npad = ((nb - m) % nb);
if (npad < 0)
npad += nb;
fprintf(stderr, "(%d blocks padded)",
npad);
npad *= DSIZE;
wbuf[vec].iov_base = pad;
wbuf[vec++].iov_len = npad;
if (vec >= NPACKET_R) {
writev(fd, wbuf, vec);
vec = 0;
}
}
#endif
k++;
if (k % frame_rate[system] == 0) {
/* every second */
fprintf(stderr, "\n");
}
fflush(stderr);
m = 0;
}
if (k == 0 || (count > 0 && k > count))
continue;
m++;
wbuf[vec].iov_base = (char *) dv;
wbuf[vec++].iov_len = DSIZE;
if (vec >= NPACKET_R) {
writev(fd, wbuf, vec);
vec = 0;
}
}
ptr = (u_int32_t *)dv;
next:
if ((char *)ptr < buf + tlen)
goto again;
if (vec > 0)
writev(fd, wbuf, vec);
}
if(fd != STDOUT_FILENO) {
close(fd);
}
fprintf(stderr, "\n");
}
void
dvsend(int d, const char *filename, char ich, int count)
{
struct fw_isochreq isoreq;
struct fw_isobufreq bufreq;
struct dvdbc *dv;
struct fw_pkt *pkt;
int len, tlen, header, fd, frames, packets, vec, offset, nhdr, i;
int system=-1, pad_acc, cycle_acc, cycle, f_cycle, f_frac;
struct iovec wbuf[TNBUF*2 + NEMPTY];
char *pbuf;
u_int32_t iso_data, iso_empty, hdr[TNBUF + NEMPTY][3];
struct ciphdr *ciph;
struct timeval start, end;
double rtime;
fd = open(filename, O_RDONLY);
if (fd == -1)
err(EX_NOINPUT, filename);
pbuf = malloc(DSIZE * TNBUF);
bzero(wbuf, sizeof(wbuf));
bufreq.rx.nchunk = 0;
bufreq.rx.npacket = 0;
bufreq.rx.psize = 0;
bufreq.tx.nchunk = NCHUNK;
bufreq.tx.npacket = NPACKET_T;
bufreq.tx.psize = PSIZE;
if (ioctl(d, FW_SSTBUF, &bufreq) < 0)
err(1, "ioctl FW_SSTBUF");
isoreq.ch = ich & 0x3f;
isoreq.tag = (ich >> 6) & 3;
if (ioctl(d, FW_STSTREAM, &isoreq) < 0)
err(1, "ioctl FW_STSTREAM");
iso_data = 0;
pkt = (struct fw_pkt *) &iso_data;
pkt->mode.stream.len = DSIZE + sizeof(struct ciphdr);
pkt->mode.stream.sy = 0;
pkt->mode.stream.tcode = FWTCODE_STREAM;
pkt->mode.stream.chtag = ich;
iso_empty = iso_data;
pkt = (struct fw_pkt *) &iso_empty;
pkt->mode.stream.len = sizeof(struct ciphdr);
bzero(hdr[0], sizeof(hdr[0]));
hdr[0][0] = iso_data;
ciph = (struct ciphdr *)&hdr[0][1];
ciph->src = 0; /* XXX */
ciph->len = 120;
ciph->dbc = 0;
ciph->eoh1 = 1;
ciph->fdf.dv.cyc = 0xffff;
for (i = 1; i < TNBUF; i++)
bcopy(hdr[0], hdr[i], sizeof(hdr[0]));
gettimeofday(&start, NULL);
#if DEBUG
fprintf(stderr, "%08x %08x %08x\n",
htonl(hdr[0]), htonl(hdr[1]), htonl(hdr[2]));
#endif
frames = 0;
packets = 0;
pad_acc = 0;
while (1) {
tlen = 0;
while (tlen < DSIZE * TNBUF) {
len = read(fd, pbuf + tlen, DSIZE * TNBUF - tlen);
if (len <= 0) {
if (tlen > 0)
break;
if (len < 0)
warn("read");
else
fprintf(stderr, "\nend of file\n");
goto send_end;
}
tlen += len;
}
vec = 0;
offset = 0;
nhdr = 0;
next:
dv = (struct dvdbc *)(pbuf + offset * DSIZE);
#if 0
header = (dv->sct == 0 && dv->dseq == 0);
#else
header = (packets == 0 || packets % npackets[system] == 0);
#endif
ciph = (struct ciphdr *)&hdr[nhdr][1];
if (header) {
if (system < 0) {
system = ((dv->payload[0] & DV_DSF_12) != 0);
printf("%s\n", system_name[system]);
cycle = 1;
cycle_acc = frame_cycle[system].d * cycle;
}
fprintf(stderr, "%d", frames % 10);
frames ++;
if (count > 0 && frames > count)
break;
if (frames % frame_rate[system] == 0)
fprintf(stderr, "\n");
fflush(stderr);
f_cycle = (cycle_acc / frame_cycle[system].d) & 0xf;
f_frac = (cycle_acc % frame_cycle[system].d
* CYCLE_FRAC) / frame_cycle[system].d;
#if 0
ciph->fdf.dv.cyc = htons(f_cycle << 12 | f_frac);
#else
ciph->fdf.dv.cyc = htons(cycle << 12 | f_frac);
#endif
cycle_acc += frame_cycle[system].n;
cycle_acc %= frame_cycle[system].d * 0x10;
} else {
ciph->fdf.dv.cyc = 0xffff;
}
ciph->dbc = packets++ % 256;
pad_acc += pad_rate[system].n;
if (pad_acc >= pad_rate[system].d) {
pad_acc -= pad_rate[system].d;
bcopy(hdr[nhdr], hdr[nhdr+1], sizeof(hdr[0]));
hdr[nhdr][0] = iso_empty;
wbuf[vec].iov_base = (char *)hdr[nhdr];
wbuf[vec++].iov_len = sizeof(hdr[0]);
nhdr ++;
cycle ++;
}
hdr[nhdr][0] = iso_data;
wbuf[vec].iov_base = (char *)hdr[nhdr];
wbuf[vec++].iov_len = sizeof(hdr[0]);
wbuf[vec].iov_base = (char *)dv;
wbuf[vec++].iov_len = DSIZE;
nhdr ++;
cycle ++;
offset ++;
if (offset * DSIZE < tlen)
goto next;
again:
len = writev(d, wbuf, vec);
if (len < 0) {
if (errno == EAGAIN) {
fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
goto again;
}
err(1, "write failed");
}
}
close(fd);
fprintf(stderr, "\n");
send_end:
gettimeofday(&end, NULL);
rtime = end.tv_sec - start.tv_sec
+ (end.tv_usec - start.tv_usec) * 1e-6;
fprintf(stderr, "%d frames, %.2f secs, %.2f frames/sec\n",
frames, rtime, frames/rtime);
}

View File

@ -0,0 +1,10 @@
/*-
* This file is in the public domain.
*
* $FreeBSD: src/usr.sbin/fwcontrol/fwmethods.h,v 1.1 2006/10/26 22:33:38 imp Exp $
*/
typedef void (fwmethod)(int dev_fd, const char *filename, char ich, int count);
extern fwmethod dvrecv;
extern fwmethod dvsend;
extern fwmethod mpegtsrecv;

View File

@ -0,0 +1,275 @@
/*
* Copyright (C) 2005
* Petr Holub, Hidetoshi Shimokawa. All rights reserved.
*
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by Hidetoshi Shimokawa.
*
* 4. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* $FreeBSD: src/usr.sbin/fwcontrol/fwmpegts.c,v 1.1 2006/10/26 22:33:38 imp Exp $
*/
#include <sys/param.h>
#ifndef __HAIKU__
#include <sys/ioctl.h>
#endif
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#if __FreeBSD_version >= 500000 || defined(__HAIKU__)
#include <arpa/inet.h>
#endif
#include <err.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __HAIKU__
#include <stdint.h>
#include "firewire.h"
#include "iec68113.h"
#else
#include <sysexits.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec68113.h>
#endif
#include "fwmethods.h"
#define DEBUG 0
/*****************************************************************************
MPEG-2 Transport Stream (MPEG TS) packet format according to IEC 61883:
31 15 0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ --------
| len |tag| channel | tcode | sy |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1394
| header_CRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ --------
|0|0| sid | dbs |fn | qpc |S|RSV| dbc |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ CIP
|1|0| fmt | fdf | fdf/syt |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ --------
| reserved | cycle_count | cycle_offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | N x
. . MPEG
. MPEG TS payload 188 bytes .
. .
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ --------
| data_CRC |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
N.b. that CRCs are removed by firewire layer!
The following fiels are fixed for IEEE-1394:
tag = 01b
tcode = 1010b
The length is payload length, i.e. includes CIP header and data size.
The following fields are constant for MPEG TS:
sph = 1 (denoted as S in CIP header above)
dbs = 6
fmt = (1<<5)
fdf = reserved
In the supported streams we also require
qpc = 0
fn = 3
and thus the payload is divided in 8 blocks as follows:
+-----+-----+-----+-----+-----+-----+-----+-----+
| db0 | db1 | db2 | db3 | db4 | db5 | db6 | db7 |
+-----+-----+-----+-----+-----+-----+-----+-----+
We have several cases of payload distribution based on stream
bandwidth (R):
1) R < 1.5 Mbps: any of db0..db7 may be payload,
2) 1.5 < R < 3 Mbps: db0/db1 or db2/db3 or db4/db5 or db6/db7 is payload,
3) 3 < R < 6 Mbps: db0/db1/db2/db3 or db4/db5/db6/db7 is payload,
4) R > 6 Mbps: all db0..db7 contain the payload.
Curently, only case (4) is supported in fwmpegts.c
Each packet may contain N MPEG TS data blocks with timestamp header,
which are (4+188)B long. Experimentally, the N ranges from 0 through 3.
*****************************************************************************/
typedef uint8_t mpeg_ts_pld[188];
struct mpeg_pldt {
#if BYTE_ORDER == BIG_ENDIAN
uint32_t :7,
c_count:13,
c_offset:12;
#else /* BYTE_ORDER != BIG_ENDIAN */
uint32_t c_offset:12,
c_count:13,
:7;
#endif /* BYTE_ORDER == BIG_ENDIAN */
mpeg_ts_pld payload;
};
#define NCHUNK 8
#define PSIZE 596
#define NPACKET_R 4096
#define RBUFSIZE (PSIZE * NPACKET_R)
void
mpegtsrecv(int d, const char *filename, char ich, int count)
{
struct ciphdr *ciph;
struct fw_isochreq isoreq;
struct fw_isobufreq bufreq;
struct fw_pkt *pkt;
struct mpeg_pldt *pld;
uint32_t *ptr;
int fd, k, len, m, pkt_size, startwr, tlen;
char *buf;
startwr = 0;
if (strcmp(filename, "-") == 0)
fd = STDOUT_FILENO;
else {
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0660);
if (fd == -1)
err(EX_NOINPUT, filename);
}
buf = malloc(RBUFSIZE);
bufreq.rx.nchunk = NCHUNK;
bufreq.rx.npacket = NPACKET_R;
bufreq.rx.psize = PSIZE;
bufreq.tx.nchunk = 0;
bufreq.tx.npacket = 0;
bufreq.tx.psize = 0;
if (ioctl(d, FW_SSTBUF, &bufreq) < 0)
err(1, "ioctl");
isoreq.ch = ich & 0x3f;
isoreq.tag = (ich >> 6) & 3;
if (ioctl(d, FW_SRSTREAM, &isoreq) < 0)
err(1, "ioctl");
k = m = 0;
while (count <= 0 || k <= count) {
len = tlen = read(d, buf, RBUFSIZE);
#if DEBUG
fprintf(stderr, "Read %d bytes.\n", len);
#endif /* DEBUG */
if (len < 0) {
if (errno == EAGAIN) {
fprintf(stderr, "(EAGAIN) - push 'Play'?\n");
if (len <= 0)
continue;
} else
err(1, "read failed");
}
ptr = (uint32_t *) buf;
do {
pkt = (struct fw_pkt *) ptr;
#if DEBUG
fprintf(stderr, "\nReading new packet.\n");
fprintf(stderr, "%08x %08x %08x %08x\n",
htonl(ptr[0]), htonl(ptr[1]),
htonl(ptr[2]), htonl(ptr[3]));
#endif /* DEBUG */
/* there is no CRC in the 1394 header */
ciph = (struct ciphdr *)(ptr + 1); /* skip iso header */
if (ciph->fmt != CIP_FMT_MPEG)
errx(1, "unknown format 0x%x", ciph->fmt);
if (ciph->fn != 3) {
errx(1,
"unsupported MPEG TS stream, fn=%d (only fn=3 is supported)",
ciph->fn);
}
ptr = (uint32_t *) (ciph + 1); /* skip cip header */
if (pkt->mode.stream.len <= sizeof(struct ciphdr)) {
/* no payload */
/* tlen needs to be decremented before end of the loop */
goto next;
}
#if DEBUG
else {
fprintf(stderr,
"Packet net payload length (IEEE1394 header): %d\n",
pkt->mode.stream.len - sizeof(struct ciphdr));
fprintf(stderr, "Data block size (CIP header): %d [q], %d [B]\n",
ciph->len, ciph->len * 4);
fprintf(stderr,
"Data fraction number (CIP header): %d => DBC increments with %d\n",
ciph->fn, (1<<ciph->fn) );
fprintf(stderr, "QCP (CIP header): %d\n", ciph->qpc );
fprintf(stderr, "DBC counter (CIP header): %d\n", ciph->dbc );
fprintf(stderr, "MPEG payload type size: %d\n",
sizeof(struct mpeg_pldt));
}
#endif /* DEBUG */
/* This is a condition that needs to be satisfied to start
writing the data */
if (ciph->dbc % (1<<ciph->fn) == 0)
startwr = 1;
/* Read out all the MPEG TS data blocks from current packet */
for (pld = (struct mpeg_pldt *)ptr;
(intptr_t)pld < (intptr_t)((char *)ptr +
pkt->mode.stream.len - sizeof(struct ciphdr));
pld++) {
if (startwr == 1)
write(fd, pld->payload,
sizeof(pld->payload));
}
next:
/* CRCs are removed from both header and trailer
so that only 4 bytes of 1394 header remains */
pkt_size = pkt->mode.stream.len + 4;
ptr = (uint32_t *)((intptr_t)pkt + pkt_size);
tlen -= pkt_size;
} while (tlen > 0);
#if DEBUG
fprintf(stderr, "\nReading a data from firewire.\n");
#endif /* DEBUG */
}
if (fd != STDOUT_FILENO)
close(fd);
fprintf(stderr, "\n");
}