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:
parent
84f03dd594
commit
2ff0a95e11
57
headers/private/firewire/eui64.h
Normal file
57
headers/private/firewire/eui64.h
Normal 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 */
|
437
headers/private/firewire/firewire.h
Normal file
437
headers/private/firewire/firewire.h
Normal 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
|
168
headers/private/firewire/fwphyreg.h
Normal file
168
headers/private/firewire/fwphyreg.h
Normal 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];
|
||||
};
|
251
headers/private/firewire/iec13213.h
Normal file
251
headers/private/firewire/iec13213.h
Normal 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
|
127
headers/private/firewire/iec68113.h
Normal file
127
headers/private/firewire/iec68113.h
Normal 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 */
|
||||
};
|
618
headers/private/firewire/queue.h
Normal file
618
headers/private/firewire/queue.h
Normal 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
13
src/bin/fwcontrol/Jamfile
Normal 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
323
src/bin/fwcontrol/eui64.c
Normal 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
|
204
src/bin/fwcontrol/fwcontrol.8
Normal file
204
src/bin/fwcontrol/fwcontrol.8
Normal 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).
|
833
src/bin/fwcontrol/fwcontrol.c
Normal file
833
src/bin/fwcontrol/fwcontrol.c
Normal 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, ®) < 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, ®) < 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
652
src/bin/fwcontrol/fwcrom.c
Normal 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
426
src/bin/fwcontrol/fwdv.c
Normal 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);
|
||||
}
|
10
src/bin/fwcontrol/fwmethods.h
Normal file
10
src/bin/fwcontrol/fwmethods.h
Normal 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;
|
275
src/bin/fwcontrol/fwmpegts.c
Normal file
275
src/bin/fwcontrol/fwmpegts.c
Normal 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");
|
||||
}
|
Loading…
Reference in New Issue
Block a user