From 2ff0a95e11057b43698cc20894d39a62f0499d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sun, 15 Jul 2007 17:43:02 +0000 Subject: [PATCH] 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 --- headers/private/firewire/eui64.h | 57 ++ headers/private/firewire/firewire.h | 437 +++++++++++++++ headers/private/firewire/fwphyreg.h | 168 ++++++ headers/private/firewire/iec13213.h | 251 +++++++++ headers/private/firewire/iec68113.h | 127 +++++ headers/private/firewire/queue.h | 618 +++++++++++++++++++++ src/bin/fwcontrol/Jamfile | 13 + src/bin/fwcontrol/eui64.c | 323 +++++++++++ src/bin/fwcontrol/fwcontrol.8 | 204 +++++++ src/bin/fwcontrol/fwcontrol.c | 833 ++++++++++++++++++++++++++++ src/bin/fwcontrol/fwcrom.c | 652 ++++++++++++++++++++++ src/bin/fwcontrol/fwdv.c | 426 ++++++++++++++ src/bin/fwcontrol/fwmethods.h | 10 + src/bin/fwcontrol/fwmpegts.c | 275 +++++++++ 14 files changed, 4394 insertions(+) create mode 100644 headers/private/firewire/eui64.h create mode 100644 headers/private/firewire/firewire.h create mode 100644 headers/private/firewire/fwphyreg.h create mode 100644 headers/private/firewire/iec13213.h create mode 100644 headers/private/firewire/iec68113.h create mode 100644 headers/private/firewire/queue.h create mode 100644 src/bin/fwcontrol/Jamfile create mode 100644 src/bin/fwcontrol/eui64.c create mode 100644 src/bin/fwcontrol/fwcontrol.8 create mode 100644 src/bin/fwcontrol/fwcontrol.c create mode 100644 src/bin/fwcontrol/fwcrom.c create mode 100644 src/bin/fwcontrol/fwdv.c create mode 100644 src/bin/fwcontrol/fwmethods.h create mode 100644 src/bin/fwcontrol/fwmpegts.c diff --git a/headers/private/firewire/eui64.h b/headers/private/firewire/eui64.h new file mode 100644 index 0000000000..129215028f --- /dev/null +++ b/headers/private/firewire/eui64.h @@ -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 */ diff --git a/headers/private/firewire/firewire.h b/headers/private/firewire/firewire.h new file mode 100644 index 0000000000..5f84e66fad --- /dev/null +++ b/headers/private/firewire/firewire.h @@ -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 +#include +#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 diff --git a/headers/private/firewire/fwphyreg.h b/headers/private/firewire/fwphyreg.h new file mode 100644 index 0000000000..825a21f520 --- /dev/null +++ b/headers/private/firewire/fwphyreg.h @@ -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]; +}; diff --git a/headers/private/firewire/iec13213.h b/headers/private/firewire/iec13213.h new file mode 100644 index 0000000000..f018518cb1 --- /dev/null +++ b/headers/private/firewire/iec13213.h @@ -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 diff --git a/headers/private/firewire/iec68113.h b/headers/private/firewire/iec68113.h new file mode 100644 index 0000000000..9dc8326664 --- /dev/null +++ b/headers/private/firewire/iec68113.h @@ -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 */ +}; diff --git a/headers/private/firewire/queue.h b/headers/private/firewire/queue.h new file mode 100644 index 0000000000..d62afcc847 --- /dev/null +++ b/headers/private/firewire/queue.h @@ -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 + +/* + * 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_ */ diff --git a/src/bin/fwcontrol/Jamfile b/src/bin/fwcontrol/Jamfile new file mode 100644 index 0000000000..3c133212ab --- /dev/null +++ b/src/bin/fwcontrol/Jamfile @@ -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 +; diff --git a/src/bin/fwcontrol/eui64.c b/src/bin/fwcontrol/eui64.c new file mode 100644 index 0000000000..564e7f4919 --- /dev/null +++ b/src/bin/fwcontrol/eui64.c @@ -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 . 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 + * Center for Telecommunications Research + * Columbia University, New York City + */ + +#ifndef __HAIKU__ +#include +__FBSDID("$FreeBSD: src/lib/libc/net/eui64.c,v 1.2 2004/06/01 19:30:13 brooks Exp $"); +#endif + +#include +#ifndef __HAIKU__ +#include +#endif +#include +#ifdef __HAIKU__ +#include "eui64.h" +#else +#include +#endif +#include +#include +#include +#ifndef __HAIKU__ +#ifdef YP +#include +#include +#include +#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 diff --git a/src/bin/fwcontrol/fwcontrol.8 b/src/bin/fwcontrol/fwcontrol.8 new file mode 100644 index 0000000000..6c40f05a58 --- /dev/null +++ b/src/bin/fwcontrol/fwcontrol.8 @@ -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). diff --git a/src/bin/fwcontrol/fwcontrol.c b/src/bin/fwcontrol/fwcontrol.c new file mode 100644 index 0000000000..cf668d6523 --- /dev/null +++ b/src/bin/fwcontrol/fwcontrol.c @@ -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 +__FBSDID("$FreeBSD: src/usr.sbin/fwcontrol/fwcontrol.c,v 1.23 2006/10/26 22:33:38 imp Exp $"); +#endif + +#ifdef __HAIKU__ +#include +#include +#include "eui64.h" +#include "firewire.h" +#include "iec13213.h" +#include "fwphyreg.h" +#include "iec68113.h" +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#endif +#include +#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; +} diff --git a/src/bin/fwcontrol/fwcrom.c b/src/bin/fwcontrol/fwcrom.c new file mode 100644 index 0000000000..c6205d3478 --- /dev/null +++ b/src/bin/fwcontrol/fwcrom.c @@ -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 +__FBSDID("$FreeBSD: src/sys/dev/firewire/fwcrom.c,v 1.14 2006/02/04 21:37:39 imp Exp $"); +#endif + +#include + +#ifdef _BOOT +#include +#include +#else +#if defined(_KERNEL) || defined(TEST) +#ifdef __HAIKU__ +#include "queue.h" +#else +#include +#endif +#endif +#ifdef _KERNEL +#ifndef __HAIKU__ +#include +#include +#endif +#else +#include +#include +#include +#include +#include +#include +#endif +#endif +#ifdef __HAIKU__ +#include +#endif + +#if defined( __DragonFly__) || defined(__HAIKU__) +#include "firewire.h" +#include "iec13213.h" +#define vm_offset_t uint32_t +#else +#include +#include +#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 diff --git a/src/bin/fwcontrol/fwdv.c b/src/bin/fwcontrol/fwdv.c new file mode 100644 index 0000000000..e8ecbb74c1 --- /dev/null +++ b/src/bin/fwcontrol/fwdv.c @@ -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 +#ifndef __HAIKU__ +#include +#endif +#include +#include +#include + +#if __FreeBSD_version >= 500000 || defined(__HAIKU__) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef __HAIKU__ +#include +#include "firewire.h" +#include "iec68113.h" +#else +#include + +#include +#include +#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); +} diff --git a/src/bin/fwcontrol/fwmethods.h b/src/bin/fwcontrol/fwmethods.h new file mode 100644 index 0000000000..9cb23f30c5 --- /dev/null +++ b/src/bin/fwcontrol/fwmethods.h @@ -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; diff --git a/src/bin/fwcontrol/fwmpegts.c b/src/bin/fwcontrol/fwmpegts.c new file mode 100644 index 0000000000..75cfbd8882 --- /dev/null +++ b/src/bin/fwcontrol/fwmpegts.c @@ -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 +#ifndef __HAIKU__ +#include +#endif +#include +#include +#include + +#if __FreeBSD_version >= 500000 || defined(__HAIKU__) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#ifdef __HAIKU__ +#include +#include "firewire.h" +#include "iec68113.h" +#else +#include + +#include +#include +#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<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<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"); +}