1108441Ssimokawa/* 2108441Ssimokawa * Copyright (C) 2002 3108441Ssimokawa * Hidetoshi Shimokawa. All rights reserved. 4108441Ssimokawa * 5108441Ssimokawa * Redistribution and use in source and binary forms, with or without 6108441Ssimokawa * modification, are permitted provided that the following conditions 7108441Ssimokawa * are met: 8108441Ssimokawa * 1. Redistributions of source code must retain the above copyright 9108441Ssimokawa * notice, this list of conditions and the following disclaimer. 10108441Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright 11108441Ssimokawa * notice, this list of conditions and the following disclaimer in the 12108441Ssimokawa * documentation and/or other materials provided with the distribution. 13108441Ssimokawa * 3. All advertising materials mentioning features or use of this software 14108441Ssimokawa * must display the following acknowledgement: 15108441Ssimokawa * 16108441Ssimokawa * This product includes software developed by Hidetoshi Shimokawa. 17108441Ssimokawa * 18108441Ssimokawa * 4. Neither the name of the author nor the names of its contributors 19108441Ssimokawa * may be used to endorse or promote products derived from this software 20108441Ssimokawa * without specific prior written permission. 21108441Ssimokawa * 22108441Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23108441Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24108441Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25108441Ssimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26108441Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27108441Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28108441Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29108441Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30108441Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31108441Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32108441Ssimokawa * SUCH DAMAGE. 33108441Ssimokawa */ 34108441Ssimokawa 35185996Ssbruno#if defined(__FreeBSD__) 36146442Scharnier#include <sys/cdefs.h> 37146442Scharnier__FBSDID("$FreeBSD$"); 38185996Ssbruno#endif 39146442Scharnier 40108441Ssimokawa#include <sys/param.h> 41108441Ssimokawa#include <sys/malloc.h> 42146442Scharnier#include <sys/types.h> 43146442Scharnier#include <sys/sysctl.h> 44108441Ssimokawa#include <sys/socket.h> 45108441Ssimokawa#include <sys/ioctl.h> 46108441Ssimokawa#include <sys/errno.h> 47185996Ssbruno#if defined(__FreeBSD__) 48129760Sbrooks#include <sys/eui64.h> 49108441Ssimokawa#include <dev/firewire/firewire.h> 50108441Ssimokawa#include <dev/firewire/iec13213.h> 51120432Ssimokawa#include <dev/firewire/fwphyreg.h> 52163712Simp#include <dev/firewire/iec68113.h> 53185996Ssbruno#elif defined(__NetBSD__) 54185996Ssbruno#include "eui64.h" 55185996Ssbruno#include <dev/ieee1394/firewire.h> 56185996Ssbruno#include <dev/ieee1394/iec13213.h> 57185996Ssbruno#include <dev/ieee1394/fwphyreg.h> 58185996Ssbruno#include <dev/ieee1394/iec68113.h> 59185996Ssbruno#else 60185996Ssbruno#warning "You need to add support for your OS" 61185996Ssbruno#endif 62108441Ssimokawa 63185996Ssbruno 64108441Ssimokawa#include <netinet/in.h> 65108441Ssimokawa#include <fcntl.h> 66108441Ssimokawa#include <stdio.h> 67108441Ssimokawa#include <err.h> 68108441Ssimokawa#include <stdlib.h> 69108441Ssimokawa#include <string.h> 70163712Simp#include <sysexits.h> 71108441Ssimokawa#include <unistd.h> 72182911Ssbruno#include <stdint.h> 73182911Ssbruno#include <stdbool.h> 74163712Simp#include "fwmethods.h" 75108441Ssimokawa 76163712Simpstatic void sysctl_set_int(const char *, int); 77109737Ssimokawa 78108657Ssimokawastatic void 79108441Ssimokawausage(void) 80108441Ssimokawa{ 81109787Ssimokawa fprintf(stderr, 82185996Ssbruno "%s [-u bus_num] [-prt] [-c node] [-d node] [-o node] [-s node]\n" 83182911Ssbruno "\t [-l file] [-g gap_count] [-f force_root ] [-b pri_req]\n" 84182911Ssbruno "\t [-M mode] [-R filename] [-S filename] [-m EUI64 | hostname]\n" 85118457Ssimokawa "\t-u: specify bus number\n" 86182911Ssbruno "\t-p: Display current PHY register settings\n" 87114217Ssimokawa "\t-r: bus reset\n" 88114217Ssimokawa "\t-t: read topology map\n" 89182911Ssbruno "\t-c: read configuration ROM\n" 90114217Ssimokawa "\t-d: hex dump of configuration ROM\n" 91182911Ssbruno "\t-o: send link-on packet to the node\n" 92182911Ssbruno "\t-s: write RESET_START register on the node\n" 93114217Ssimokawa "\t-l: load and parse hex dump file of configuration ROM\n" 94185996Ssbruno "\t-g: set gap count\n" 95185996Ssbruno "\t-f: force root node\n" 96182911Ssbruno "\t-b: set PRIORITY_BUDGET register on all supported nodes\n" 97182911Ssbruno "\t-M: specify dv or mpeg\n" 98163712Simp "\t-R: Receive DV or MPEG TS stream\n" 99137028Ssimokawa "\t-S: Send DV stream\n" 100185996Ssbruno "\t-m: set fwmem target\n" 101185996Ssbruno , getprogname() ); 102185996Ssbruno fprintf(stderr, "\n"); 103108441Ssimokawa} 104108441Ssimokawa 105129760Sbrooksstatic void 106129760Sbrooksfweui2eui64(const struct fw_eui64 *fweui, struct eui64 *eui) 107129760Sbrooks{ 108129760Sbrooks *(u_int32_t*)&(eui->octet[0]) = htonl(fweui->hi); 109129760Sbrooks *(u_int32_t*)&(eui->octet[4]) = htonl(fweui->lo); 110129760Sbrooks} 111129760Sbrooks 112182911Ssbrunostatic void 113182911Ssbrunoget_dev(int fd, struct fw_devlstreq *data) 114108441Ssimokawa{ 115109814Ssimokawa if (data == NULL) 116182911Ssbruno err(EX_SOFTWARE, "%s: data malloc", __func__); 117108441Ssimokawa if( ioctl(fd, FW_GDEVLST, data) < 0) { 118182911Ssbruno err(EX_IOERR, "%s: ioctl", __func__); 119108441Ssimokawa } 120108441Ssimokawa} 121108441Ssimokawa 122129760Sbrooksstatic int 123129760Sbrooksstr2node(int fd, const char *nodestr) 124129760Sbrooks{ 125129760Sbrooks struct eui64 eui, tmpeui; 126129760Sbrooks struct fw_devlstreq *data; 127129760Sbrooks char *endptr; 128129760Sbrooks int i, node; 129129760Sbrooks 130129760Sbrooks if (nodestr == '\0') 131129760Sbrooks return (-1); 132129760Sbrooks 133129760Sbrooks /* 134129760Sbrooks * Deal with classic node specifications. 135129760Sbrooks */ 136129760Sbrooks node = strtol(nodestr, &endptr, 0); 137129760Sbrooks if (*endptr == '\0') 138129760Sbrooks goto gotnode; 139129760Sbrooks 140129760Sbrooks /* 141129760Sbrooks * Try to get an eui and match it against available nodes. 142129760Sbrooks */ 143129760Sbrooks if (eui64_hostton(nodestr, &eui) != 0 && eui64_aton(nodestr, &eui) != 0) 144129760Sbrooks return (-1); 145129760Sbrooks 146182911Ssbruno data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq)); 147182911Ssbruno if (data == NULL) 148182911Ssbruno err(EX_SOFTWARE, "%s: data malloc", __func__); 149182911Ssbruno get_dev(fd,data); 150129760Sbrooks 151129760Sbrooks for (i = 0; i < data->info_len; i++) { 152129760Sbrooks fweui2eui64(&data->dev[i].eui, &tmpeui); 153129760Sbrooks if (memcmp(&eui, &tmpeui, sizeof(struct eui64)) == 0) { 154129760Sbrooks node = data->dev[i].dst; 155228790Seadler free(data); 156129760Sbrooks goto gotnode; 157129760Sbrooks } 158129760Sbrooks } 159182911Ssbruno if (i >= data->info_len) { 160182911Ssbruno if (data != NULL) 161182911Ssbruno free(data); 162129760Sbrooks return (-1); 163182911Ssbruno } 164129760Sbrooks 165129760Sbrooksgotnode: 166129760Sbrooks if (node < 0 || node > 63) 167129760Sbrooks return (-1); 168129760Sbrooks else 169129760Sbrooks return (node); 170129760Sbrooks} 171129760Sbrooks 172108657Ssimokawastatic void 173108441Ssimokawalist_dev(int fd) 174108441Ssimokawa{ 175109814Ssimokawa struct fw_devlstreq *data; 176109814Ssimokawa struct fw_devinfo *devinfo; 177129760Sbrooks struct eui64 eui; 178176810Ssimokawa char addr[EUI64_SIZ], hostname[40]; 179108441Ssimokawa int i; 180108441Ssimokawa 181182911Ssbruno data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq)); 182182911Ssbruno if (data == NULL) 183182911Ssbruno err(EX_SOFTWARE, "%s:data malloc", __func__); 184182911Ssbruno get_dev(fd, data); 185109814Ssimokawa printf("%d devices (info_len=%d)\n", data->n, data->info_len); 186176810Ssimokawa printf("node EUI64 status hostname\n"); 187109814Ssimokawa for (i = 0; i < data->info_len; i++) { 188109814Ssimokawa devinfo = &data->dev[i]; 189129760Sbrooks fweui2eui64(&devinfo->eui, &eui); 190129760Sbrooks eui64_ntoa(&eui, addr, sizeof(addr)); 191176810Ssimokawa if (eui64_ntohost(hostname, sizeof(hostname), &eui)) 192176810Ssimokawa hostname[0] = 0; 193176810Ssimokawa printf("%4d %s %6d %s\n", 194110578Ssimokawa (devinfo->status || i == 0) ? devinfo->dst : -1, 195129760Sbrooks addr, 196176810Ssimokawa devinfo->status, 197176810Ssimokawa hostname 198108441Ssimokawa ); 199108441Ssimokawa } 200109814Ssimokawa free((void *)data); 201108441Ssimokawa} 202108441Ssimokawa 203108657Ssimokawastatic u_int32_t 204146442Scharnierread_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int readmode, u_int32_t data) 205108441Ssimokawa{ 206108441Ssimokawa struct fw_asyreq *asyreq; 207108441Ssimokawa u_int32_t *qld, res; 208108441Ssimokawa 209108441Ssimokawa asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16); 210182911Ssbruno if (asyreq == NULL) 211182911Ssbruno err(EX_SOFTWARE, "%s:asyreq malloc", __func__); 212108441Ssimokawa asyreq->req.len = 16; 213114217Ssimokawa#if 0 214114217Ssimokawa asyreq->req.type = FWASREQNODE; 215114217Ssimokawa asyreq->pkt.mode.rreqq.dst = FWLOCALBUS | node; 216114217Ssimokawa#else 217108441Ssimokawa asyreq->req.type = FWASREQEUI; 218108441Ssimokawa asyreq->req.dst.eui = eui; 219108441Ssimokawa#endif 220108441Ssimokawa asyreq->pkt.mode.rreqq.tlrt = 0; 221146442Scharnier if (readmode) 222108441Ssimokawa asyreq->pkt.mode.rreqq.tcode = FWTCODE_RREQQ; 223108441Ssimokawa else 224108441Ssimokawa asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ; 225108441Ssimokawa 226113584Ssimokawa asyreq->pkt.mode.rreqq.dest_hi = 0xffff; 227113584Ssimokawa asyreq->pkt.mode.rreqq.dest_lo = addr_lo; 228108441Ssimokawa 229108441Ssimokawa qld = (u_int32_t *)&asyreq->pkt; 230146442Scharnier if (!readmode) 231176810Ssimokawa asyreq->pkt.mode.wreqq.data = htonl(data); 232108441Ssimokawa 233108441Ssimokawa if (ioctl(fd, FW_ASYREQ, asyreq) < 0) { 234182911Ssbruno err(EX_IOERR, "%s: ioctl", __func__); 235108441Ssimokawa } 236108441Ssimokawa res = qld[3]; 237108441Ssimokawa free(asyreq); 238146442Scharnier if (readmode) 239108441Ssimokawa return ntohl(res); 240108441Ssimokawa else 241108441Ssimokawa return 0; 242108441Ssimokawa} 243108657Ssimokawa 244182911Ssbruno/* 245182911Ssbruno * Send a PHY Config Packet 246182911Ssbruno * ieee 1394a-2005 4.3.4.3 247182911Ssbruno * 248182911Ssbruno * Message ID Root ID R T Gap Count 249182911Ssbruno * 00(2 bits) (6 bits) 1 1 (6 bits) 250182911Ssbruno * 251182911Ssbruno * if "R" is set, then Root ID will be the next 252182911Ssbruno * root node upon the next bus reset. 253182911Ssbruno * if "T" is set, then Gap Count will be the 254182911Ssbruno * value that all nodes use for their Gap Count 255182911Ssbruno * if "R" and "T" are not set, then this message 256182911Ssbruno * is either ignored or interpreted as an extended 257182911Ssbruno * PHY config Packet as per 1394a-2005 4.3.4.4 258182911Ssbruno */ 259108657Ssimokawastatic void 260108441Ssimokawasend_phy_config(int fd, int root_node, int gap_count) 261108441Ssimokawa{ 262108441Ssimokawa struct fw_asyreq *asyreq; 263108441Ssimokawa 264108441Ssimokawa asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12); 265182911Ssbruno if (asyreq == NULL) 266182911Ssbruno err(EX_SOFTWARE, "%s:asyreq malloc", __func__); 267108441Ssimokawa asyreq->req.len = 12; 268108441Ssimokawa asyreq->req.type = FWASREQNODE; 269108441Ssimokawa asyreq->pkt.mode.ld[0] = 0; 270108441Ssimokawa asyreq->pkt.mode.ld[1] = 0; 271108441Ssimokawa asyreq->pkt.mode.common.tcode = FWTCODE_PHY; 272108441Ssimokawa if (root_node >= 0) 273182911Ssbruno asyreq->pkt.mode.ld[1] |= ((root_node << 24) | (1 << 23)); 274108441Ssimokawa if (gap_count >= 0) 275182911Ssbruno asyreq->pkt.mode.ld[1] |= ((1 << 22) | (gap_count << 16)); 276108441Ssimokawa asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1]; 277108441Ssimokawa 278108441Ssimokawa printf("send phy_config root_node=%d gap_count=%d\n", 279108441Ssimokawa root_node, gap_count); 280108441Ssimokawa 281114274Ssimokawa if (ioctl(fd, FW_ASYREQ, asyreq) < 0) 282182911Ssbruno err(EX_IOERR, "%s: ioctl", __func__); 283114274Ssimokawa free(asyreq); 284108441Ssimokawa} 285108441Ssimokawa 286108657Ssimokawastatic void 287182911Ssbrunolink_on(int fd, int node) 288114217Ssimokawa{ 289114217Ssimokawa struct fw_asyreq *asyreq; 290114217Ssimokawa 291114217Ssimokawa asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12); 292182911Ssbruno if (asyreq == NULL) 293182911Ssbruno err(EX_SOFTWARE, "%s:asyreq malloc", __func__); 294114217Ssimokawa asyreq->req.len = 12; 295114217Ssimokawa asyreq->req.type = FWASREQNODE; 296114217Ssimokawa asyreq->pkt.mode.common.tcode = FWTCODE_PHY; 297114217Ssimokawa asyreq->pkt.mode.ld[1] |= (1 << 30) | ((node & 0x3f) << 24); 298114217Ssimokawa asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1]; 299114217Ssimokawa 300114274Ssimokawa if (ioctl(fd, FW_ASYREQ, asyreq) < 0) 301182911Ssbruno err(EX_IOERR, "%s: ioctl", __func__); 302114274Ssimokawa free(asyreq); 303114217Ssimokawa} 304114217Ssimokawa 305114217Ssimokawastatic void 306114217Ssimokawareset_start(int fd, int node) 307114217Ssimokawa{ 308114217Ssimokawa struct fw_asyreq *asyreq; 309114217Ssimokawa 310114217Ssimokawa asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16); 311182911Ssbruno if (asyreq == NULL) 312182911Ssbruno err(EX_SOFTWARE, "%s:asyreq malloc", __func__); 313114217Ssimokawa asyreq->req.len = 16; 314114217Ssimokawa asyreq->req.type = FWASREQNODE; 315114217Ssimokawa asyreq->pkt.mode.wreqq.dst = FWLOCALBUS | (node & 0x3f); 316114217Ssimokawa asyreq->pkt.mode.wreqq.tlrt = 0; 317114217Ssimokawa asyreq->pkt.mode.wreqq.tcode = FWTCODE_WREQQ; 318114217Ssimokawa 319114217Ssimokawa asyreq->pkt.mode.wreqq.dest_hi = 0xffff; 320114217Ssimokawa asyreq->pkt.mode.wreqq.dest_lo = 0xf0000000 | RESET_START; 321114217Ssimokawa 322114217Ssimokawa asyreq->pkt.mode.wreqq.data = htonl(0x1); 323114217Ssimokawa 324114274Ssimokawa if (ioctl(fd, FW_ASYREQ, asyreq) < 0) 325182911Ssbruno err(EX_IOERR, "%s: ioctl", __func__); 326114274Ssimokawa free(asyreq); 327114217Ssimokawa} 328114217Ssimokawa 329114217Ssimokawastatic void 330163712Simpset_pri_req(int fd, u_int32_t pri_req) 331108441Ssimokawa{ 332109814Ssimokawa struct fw_devlstreq *data; 333109814Ssimokawa struct fw_devinfo *devinfo; 334129760Sbrooks struct eui64 eui; 335129760Sbrooks char addr[EUI64_SIZ]; 336108441Ssimokawa u_int32_t max, reg, old; 337108441Ssimokawa int i; 338108441Ssimokawa 339182911Ssbruno data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq)); 340182911Ssbruno if (data == NULL) 341182911Ssbruno err(EX_SOFTWARE, "%s:data malloc", __func__); 342182911Ssbruno get_dev(fd, data); 343108441Ssimokawa#define BUGET_REG 0xf0000218 344109814Ssimokawa for (i = 0; i < data->info_len; i++) { 345109814Ssimokawa devinfo = &data->dev[i]; 346109814Ssimokawa if (!devinfo->status) 347108441Ssimokawa continue; 348109814Ssimokawa reg = read_write_quad(fd, devinfo->eui, BUGET_REG, 1, 0); 349129760Sbrooks fweui2eui64(&devinfo->eui, &eui); 350129760Sbrooks eui64_ntoa(&eui, addr, sizeof(addr)); 351129760Sbrooks printf("%d %s, %08x", 352129760Sbrooks devinfo->dst, addr, reg); 353163712Simp if (reg > 0) { 354108441Ssimokawa old = (reg & 0x3f); 355108441Ssimokawa max = (reg & 0x3f00) >> 8; 356108441Ssimokawa if (pri_req > max) 357108441Ssimokawa pri_req = max; 358108441Ssimokawa printf(" 0x%x -> 0x%x\n", old, pri_req); 359109814Ssimokawa read_write_quad(fd, devinfo->eui, BUGET_REG, 0, pri_req); 360108441Ssimokawa } else { 361108441Ssimokawa printf("\n"); 362108441Ssimokawa } 363108441Ssimokawa } 364109814Ssimokawa free((void *)data); 365108441Ssimokawa} 366108441Ssimokawa 367108657Ssimokawastatic void 368163712Simpparse_bus_info_block(u_int32_t *p) 369108441Ssimokawa{ 370129760Sbrooks char addr[EUI64_SIZ]; 371116141Ssimokawa struct bus_info *bi; 372129760Sbrooks struct eui64 eui; 373108441Ssimokawa 374116141Ssimokawa bi = (struct bus_info *)p; 375129760Sbrooks fweui2eui64(&bi->eui64, &eui); 376129760Sbrooks eui64_ntoa(&eui, addr, sizeof(addr)); 377116141Ssimokawa printf("bus_name: 0x%04x\n" 378116141Ssimokawa "irmc:%d cmc:%d isc:%d bmc:%d pmc:%d\n" 379116141Ssimokawa "cyc_clk_acc:%d max_rec:%d max_rom:%d\n" 380116141Ssimokawa "generation:%d link_spd:%d\n" 381129760Sbrooks "EUI64: %s\n", 382116141Ssimokawa bi->bus_name, 383116141Ssimokawa bi->irmc, bi->cmc, bi->isc, bi->bmc, bi->pmc, 384116141Ssimokawa bi->cyc_clk_acc, bi->max_rec, bi->max_rom, 385116141Ssimokawa bi->generation, bi->link_spd, 386129760Sbrooks addr); 387108441Ssimokawa} 388108441Ssimokawa 389108657Ssimokawastatic int 390108441Ssimokawaget_crom(int fd, int node, void *crom_buf, int len) 391108441Ssimokawa{ 392108441Ssimokawa struct fw_crom_buf buf; 393109991Ssimokawa int i, error; 394109814Ssimokawa struct fw_devlstreq *data; 395108441Ssimokawa 396182911Ssbruno data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq)); 397182911Ssbruno if (data == NULL) 398182911Ssbruno err(EX_SOFTWARE, "%s:data malloc", __func__); 399182911Ssbruno get_dev(fd, data); 400108441Ssimokawa 401109814Ssimokawa for (i = 0; i < data->info_len; i++) { 402109814Ssimokawa if (data->dev[i].dst == node && data->dev[i].eui.lo != 0) 403108441Ssimokawa break; 404108441Ssimokawa } 405109814Ssimokawa if (i == data->info_len) 406109814Ssimokawa errx(1, "no such node %d.", node); 407109814Ssimokawa else 408109814Ssimokawa buf.eui = data->dev[i].eui; 409109814Ssimokawa free((void *)data); 410108441Ssimokawa 411108441Ssimokawa buf.len = len; 412108441Ssimokawa buf.ptr = crom_buf; 413117474Ssimokawa bzero(crom_buf, len); 414108441Ssimokawa if ((error = ioctl(fd, FW_GCROM, &buf)) < 0) { 415182911Ssbruno err(EX_IOERR, "%s: ioctl", __func__); 416108441Ssimokawa } 417109814Ssimokawa 418108441Ssimokawa return error; 419108441Ssimokawa} 420108441Ssimokawa 421108657Ssimokawastatic void 422108441Ssimokawashow_crom(u_int32_t *crom_buf) 423108441Ssimokawa{ 424108441Ssimokawa int i; 425108441Ssimokawa struct crom_context cc; 426108441Ssimokawa char *desc, info[256]; 427146442Scharnier static const char *key_types = "ICLD"; 428108441Ssimokawa struct csrreg *reg; 429108441Ssimokawa struct csrdirectory *dir; 430108441Ssimokawa struct csrhdr *hdr; 431113584Ssimokawa u_int16_t crc; 432108441Ssimokawa 433113584Ssimokawa printf("first quad: 0x%08x ", *crom_buf); 434136845Ssimokawa if (crom_buf[0] == 0) { 435136845Ssimokawa printf("(Invalid Configuration ROM)\n"); 436136845Ssimokawa return; 437136845Ssimokawa } 438108441Ssimokawa hdr = (struct csrhdr *)crom_buf; 439108441Ssimokawa if (hdr->info_len == 1) { 440108441Ssimokawa /* minimum ROM */ 441108441Ssimokawa reg = (struct csrreg *)hdr; 442108441Ssimokawa printf("verndor ID: 0x%06x\n", reg->val); 443108441Ssimokawa return; 444108441Ssimokawa } 445113584Ssimokawa printf("info_len=%d crc_len=%d crc=0x%04x", 446113584Ssimokawa hdr->info_len, hdr->crc_len, hdr->crc); 447113584Ssimokawa crc = crom_crc(crom_buf+1, hdr->crc_len); 448113584Ssimokawa if (crc == hdr->crc) 449113584Ssimokawa printf("(OK)\n"); 450113584Ssimokawa else 451113584Ssimokawa printf("(NG)\n"); 452163712Simp parse_bus_info_block(crom_buf+1); 453108441Ssimokawa 454108441Ssimokawa crom_init_context(&cc, crom_buf); 455108441Ssimokawa dir = cc.stack[0].dir; 456129604Sdfr if (!dir) { 457129604Sdfr printf("no root directory - giving up\n"); 458129604Sdfr return; 459129604Sdfr } 460113584Ssimokawa printf("root_directory: len=0x%04x(%d) crc=0x%04x", 461108441Ssimokawa dir->crc_len, dir->crc_len, dir->crc); 462113584Ssimokawa crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len); 463113584Ssimokawa if (crc == dir->crc) 464113584Ssimokawa printf("(OK)\n"); 465113584Ssimokawa else 466113584Ssimokawa printf("(NG)\n"); 467108657Ssimokawa if (dir->crc_len < 1) 468108657Ssimokawa return; 469108441Ssimokawa while (cc.depth >= 0) { 470108441Ssimokawa desc = crom_desc(&cc, info, sizeof(info)); 471108441Ssimokawa reg = crom_get(&cc); 472108441Ssimokawa for (i = 0; i < cc.depth; i++) 473108441Ssimokawa printf("\t"); 474108441Ssimokawa printf("%02x(%c:%02x) %06x %s: %s\n", 475108441Ssimokawa reg->key, 476108441Ssimokawa key_types[(reg->key & CSRTYPE_MASK)>>6], 477108441Ssimokawa reg->key & CSRKEY_MASK, reg->val, 478108441Ssimokawa desc, info); 479108441Ssimokawa crom_next(&cc); 480108441Ssimokawa } 481108441Ssimokawa} 482108441Ssimokawa 483108441Ssimokawa#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" 484108441Ssimokawa 485108657Ssimokawastatic void 486108441Ssimokawadump_crom(u_int32_t *p) 487108441Ssimokawa{ 488108441Ssimokawa int len=1024, i; 489108441Ssimokawa 490108441Ssimokawa for (i = 0; i < len/(4*8); i ++) { 491108441Ssimokawa printf(DUMP_FORMAT, 492108441Ssimokawa p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 493108441Ssimokawa p += 8; 494108441Ssimokawa } 495108441Ssimokawa} 496108441Ssimokawa 497108657Ssimokawastatic void 498108441Ssimokawaload_crom(char *filename, u_int32_t *p) 499108441Ssimokawa{ 500108441Ssimokawa FILE *file; 501108441Ssimokawa int len=1024, i; 502108441Ssimokawa 503108441Ssimokawa if ((file = fopen(filename, "r")) == NULL) 504185996Ssbruno err(1, "load_crom %s", filename); 505108441Ssimokawa for (i = 0; i < len/(4*8); i ++) { 506108441Ssimokawa fscanf(file, DUMP_FORMAT, 507108441Ssimokawa p, p+1, p+2, p+3, p+4, p+5, p+6, p+7); 508108441Ssimokawa p += 8; 509108441Ssimokawa } 510216321Skevlo fclose(file); 511108441Ssimokawa} 512108441Ssimokawa 513108441Ssimokawastatic void 514108441Ssimokawashow_topology_map(int fd) 515108441Ssimokawa{ 516108441Ssimokawa struct fw_topology_map *tmap; 517108441Ssimokawa union fw_self_id sid; 518108441Ssimokawa int i; 519146442Scharnier static const char *port_status[] = {" ", "-", "P", "C"}; 520146442Scharnier static const char *pwr_class[] = {" 0W", "15W", "30W", "45W", 521108441Ssimokawa "-1W", "-2W", "-5W", "-9W"}; 522146442Scharnier static const char *speed[] = {"S100", "S200", "S400", "S800"}; 523108441Ssimokawa tmap = malloc(sizeof(struct fw_topology_map)); 524108441Ssimokawa if (tmap == NULL) 525182911Ssbruno err(EX_SOFTWARE, "%s:tmap malloc", __func__); 526108441Ssimokawa if (ioctl(fd, FW_GTPMAP, tmap) < 0) { 527182911Ssbruno err(EX_IOERR, "%s: ioctl", __func__); 528108441Ssimokawa } 529108441Ssimokawa printf("crc_len: %d generation:%d node_count:%d sid_count:%d\n", 530108441Ssimokawa tmap->crc_len, tmap->generation, 531108441Ssimokawa tmap->node_count, tmap->self_id_count); 532108441Ssimokawa printf("id link gap_cnt speed delay cIRM power port0 port1 port2" 533108441Ssimokawa " ini more\n"); 534108441Ssimokawa for (i = 0; i < tmap->crc_len - 2; i++) { 535108441Ssimokawa sid = tmap->self_id[i]; 536108441Ssimokawa if (sid.p0.sequel) { 537108441Ssimokawa printf("%02d sequel packet\n", sid.p0.phy_id); 538108441Ssimokawa continue; 539108441Ssimokawa } 540188742Ssbruno printf("%02d %2d %2d %4s %d %3s" 541108441Ssimokawa " %s %s %s %d %d\n", 542108441Ssimokawa sid.p0.phy_id, 543108441Ssimokawa sid.p0.link_active, 544108441Ssimokawa sid.p0.gap_count, 545108441Ssimokawa speed[sid.p0.phy_speed], 546108441Ssimokawa sid.p0.contender, 547108441Ssimokawa pwr_class[sid.p0.power_class], 548108441Ssimokawa port_status[sid.p0.port0], 549108441Ssimokawa port_status[sid.p0.port1], 550108441Ssimokawa port_status[sid.p0.port2], 551108441Ssimokawa sid.p0.initiated_reset, 552108441Ssimokawa sid.p0.more_packets 553108441Ssimokawa ); 554108441Ssimokawa } 555108441Ssimokawa free(tmap); 556108441Ssimokawa} 557108441Ssimokawa 558118457Ssimokawastatic void 559120432Ssimokawaread_phy_registers(int fd, u_int8_t *buf, int offset, int len) 560120432Ssimokawa{ 561120432Ssimokawa struct fw_reg_req_t reg; 562120432Ssimokawa int i; 563120432Ssimokawa 564120432Ssimokawa for (i = 0; i < len; i++) { 565120432Ssimokawa reg.addr = offset + i; 566120432Ssimokawa if (ioctl(fd, FWOHCI_RDPHYREG, ®) < 0) 567182911Ssbruno err(EX_IOERR, "%s: ioctl", __func__); 568120432Ssimokawa buf[i] = (u_int8_t) reg.data; 569120432Ssimokawa printf("0x%02x ", reg.data); 570120432Ssimokawa } 571120432Ssimokawa printf("\n"); 572120432Ssimokawa} 573120432Ssimokawa 574120432Ssimokawastatic void 575120432Ssimokawaread_phy_page(int fd, u_int8_t *buf, int page, int port) 576120432Ssimokawa{ 577120432Ssimokawa struct fw_reg_req_t reg; 578120432Ssimokawa 579120432Ssimokawa reg.addr = 0x7; 580120432Ssimokawa reg.data = ((page & 7) << 5) | (port & 0xf); 581120432Ssimokawa if (ioctl(fd, FWOHCI_WRPHYREG, ®) < 0) 582182911Ssbruno err(EX_IOERR, "%s: ioctl", __func__); 583120432Ssimokawa read_phy_registers(fd, buf, 8, 8); 584120432Ssimokawa} 585120432Ssimokawa 586120432Ssimokawastatic void 587120432Ssimokawadump_phy_registers(int fd) 588120432Ssimokawa{ 589120432Ssimokawa struct phyreg_base b; 590120432Ssimokawa struct phyreg_page0 p; 591120432Ssimokawa struct phyreg_page1 v; 592120432Ssimokawa int i; 593120432Ssimokawa 594120432Ssimokawa printf("=== base register ===\n"); 595120432Ssimokawa read_phy_registers(fd, (u_int8_t *)&b, 0, 8); 596120432Ssimokawa printf( 597120432Ssimokawa "Physical_ID:%d R:%d CPS:%d\n" 598120432Ssimokawa "RHB:%d IBR:%d Gap_Count:%d\n" 599120432Ssimokawa "Extended:%d Num_Ports:%d\n" 600120432Ssimokawa "PHY_Speed:%d Delay:%d\n" 601120432Ssimokawa "LCtrl:%d C:%d Jitter:%d Pwr_Class:%d\n" 602120432Ssimokawa "WDIE:%d ISBR:%d CTOI:%d CPSI:%d STOI:%d PEI:%d EAA:%d EMC:%d\n" 603120432Ssimokawa "Max_Legacy_SPD:%d BLINK:%d Bridge:%d\n" 604120432Ssimokawa "Page_Select:%d Port_Select%d\n", 605120432Ssimokawa b.phy_id, b.r, b.cps, 606120432Ssimokawa b.rhb, b.ibr, b.gap_count, 607120432Ssimokawa b.extended, b.num_ports, 608120432Ssimokawa b.phy_speed, b.delay, 609120432Ssimokawa b.lctrl, b.c, b.jitter, b.pwr_class, 610120432Ssimokawa b.wdie, b.isbr, b.ctoi, b.cpsi, b.stoi, b.pei, b.eaa, b.emc, 611120432Ssimokawa b.legacy_spd, b.blink, b.bridge, 612120432Ssimokawa b.page_select, b.port_select 613120432Ssimokawa ); 614120432Ssimokawa 615120432Ssimokawa for (i = 0; i < b.num_ports; i ++) { 616120432Ssimokawa printf("\n=== page 0 port %d ===\n", i); 617120432Ssimokawa read_phy_page(fd, (u_int8_t *)&p, 0, i); 618120432Ssimokawa printf( 619120432Ssimokawa "Astat:%d BStat:%d Ch:%d Con:%d RXOK:%d Dis:%d\n" 620120432Ssimokawa "Negotiated_speed:%d PIE:%d Fault:%d Stanby_fault:%d Disscrm:%d B_Only:%d\n" 621120432Ssimokawa "DC_connected:%d Max_port_speed:%d LPP:%d Cable_speed:%d\n" 622120432Ssimokawa "Connection_unreliable:%d Beta_mode:%d\n" 623120432Ssimokawa "Port_error:0x%x\n" 624120432Ssimokawa "Loop_disable:%d In_standby:%d Hard_disable:%d\n", 625120432Ssimokawa p.astat, p.bstat, p.ch, p.con, p.rxok, p.dis, 626120432Ssimokawa p.negotiated_speed, p.pie, p.fault, p.stanby_fault, p.disscrm, p.b_only, 627120432Ssimokawa p.dc_connected, p.max_port_speed, p.lpp, p.cable_speed, 628120432Ssimokawa p.connection_unreliable, p.beta_mode, 629120432Ssimokawa p.port_error, 630120432Ssimokawa p.loop_disable, p.in_standby, p.hard_disable 631120432Ssimokawa ); 632120432Ssimokawa } 633120432Ssimokawa printf("\n=== page 1 ===\n"); 634120432Ssimokawa read_phy_page(fd, (u_int8_t *)&v, 1, 0); 635120432Ssimokawa printf( 636120432Ssimokawa "Compliance:%d\n" 637120432Ssimokawa "Vendor_ID:0x%06x\n" 638120432Ssimokawa "Product_ID:0x%06x\n", 639120432Ssimokawa v.compliance, 640120432Ssimokawa (v.vendor_id[0] << 16) | (v.vendor_id[1] << 8) | v.vendor_id[2], 641120432Ssimokawa (v.product_id[0] << 16) | (v.product_id[1] << 8) | v.product_id[2] 642120432Ssimokawa ); 643120432Ssimokawa} 644120432Ssimokawa 645182911Ssbrunostatic int 646182911Ssbrunoopen_dev(int *fd, char *devname) 647118457Ssimokawa{ 648118457Ssimokawa if (*fd < 0) { 649182911Ssbruno *fd = open(devname, O_RDWR); 650118457Ssimokawa if (*fd < 0) 651182911Ssbruno return(-1); 652118457Ssimokawa 653118457Ssimokawa } 654182911Ssbruno return(0); 655118457Ssimokawa} 656118457Ssimokawa 657163712Simpstatic void 658146442Scharniersysctl_set_int(const char *name, int val) 659136845Ssimokawa{ 660136845Ssimokawa if (sysctlbyname(name, NULL, NULL, &val, sizeof(int)) < 0) 661136845Ssimokawa err(1, "sysctl %s failed.", name); 662136845Ssimokawa} 663136845Ssimokawa 664163712Simpstatic fwmethod * 665163712Simpdetect_recv_fn(int fd, char ich) 666163712Simp{ 667163712Simp char *buf; 668163712Simp struct fw_isochreq isoreq; 669163712Simp struct fw_isobufreq bufreq; 670163712Simp int len; 671163712Simp u_int32_t *ptr; 672163712Simp struct ciphdr *ciph; 673163712Simp fwmethod *retfn; 674182911Ssbruno#define RECV_NUM_PACKET 16 675182911Ssbruno#define RECV_PACKET_SZ 1024 676163712Simp 677163712Simp bufreq.rx.nchunk = 8; 678182911Ssbruno bufreq.rx.npacket = RECV_NUM_PACKET; 679182911Ssbruno bufreq.rx.psize = RECV_PACKET_SZ; 680163712Simp bufreq.tx.nchunk = 0; 681163712Simp bufreq.tx.npacket = 0; 682163712Simp bufreq.tx.psize = 0; 683163712Simp 684163712Simp if (ioctl(fd, FW_SSTBUF, &bufreq) < 0) 685182911Ssbruno err(EX_IOERR, "%s: ioctl FW_SSTBUF", __func__); 686163712Simp 687163712Simp isoreq.ch = ich & 0x3f; 688163712Simp isoreq.tag = (ich >> 6) & 3; 689163712Simp 690163712Simp if (ioctl(fd, FW_SRSTREAM, &isoreq) < 0) 691182911Ssbruno err(EX_IOERR, "%s: ioctl FW_SRSTREAM", __func__); 692163712Simp 693182911Ssbruno buf = (char *)malloc(RECV_NUM_PACKET * RECV_PACKET_SZ); 694182911Ssbruno if (buf == NULL) 695182911Ssbruno err(EX_SOFTWARE, "%s:buf malloc", __func__); 696182911Ssbruno /* 697182911Ssbruno * fwdev.c seems to return EIO on error and 698182911Ssbruno * the return value of the last uiomove 699182911Ssbruno * on success. For now, checking that the 700182911Ssbruno * return is not less than zero should be 701182911Ssbruno * sufficient. fwdev.c::fw_read() should 702182911Ssbruno * return the total length read, not the value 703182911Ssbruno * of the last uiomove(). 704182911Ssbruno */ 705182911Ssbruno len = read(fd, buf, RECV_NUM_PACKET * RECV_PACKET_SZ); 706182911Ssbruno if (len < 0) 707185996Ssbruno err(EX_IOERR, "%s: error reading from device", __func__); 708163712Simp ptr = (u_int32_t *) buf; 709163712Simp ciph = (struct ciphdr *)(ptr + 1); 710163712Simp 711163712Simp switch(ciph->fmt) { 712163712Simp case CIP_FMT_DVCR: 713163712Simp fprintf(stderr, "Detected DV format on input.\n"); 714163712Simp retfn = dvrecv; 715163712Simp break; 716163712Simp case CIP_FMT_MPEG: 717163712Simp fprintf(stderr, "Detected MPEG TS format on input.\n"); 718163712Simp retfn = mpegtsrecv; 719163712Simp break; 720163712Simp default: 721163712Simp errx(1, "Unsupported format for receiving: fmt=0x%x", ciph->fmt); 722163712Simp } 723163712Simp free(buf); 724163712Simp return retfn; 725163712Simp} 726163712Simp 727136845Ssimokawaint 728108441Ssimokawamain(int argc, char **argv) 729108441Ssimokawa{ 730182911Ssbruno#define MAX_BOARDS 10 731108441Ssimokawa u_int32_t crom_buf[1024/4]; 732182911Ssbruno u_int32_t crom_buf_hex[1024/4]; 733182911Ssbruno char devbase[64]; 734182911Ssbruno const char *device_string = "/dev/fw"; 735182911Ssbruno int fd = -1, ch, len=1024; 736182911Ssbruno int32_t current_board = 0; 737182911Ssbruno /* 738182911Ssbruno * If !command_set, then -u will display the nodes for the board. 739182911Ssbruno * This emulates the previous behavior when -u is passed by itself 740182911Ssbruno */ 741182911Ssbruno bool command_set = false; 742182911Ssbruno bool open_needed = false; 743163712Simp long tmp; 744136845Ssimokawa struct fw_eui64 eui; 745136845Ssimokawa struct eui64 target; 746163712Simp fwmethod *recvfn = NULL; 747182911Ssbruno/* 748182911Ssbruno * Holders for which functions 749182911Ssbruno * to iterate through 750182911Ssbruno */ 751182911Ssbruno bool display_board_only = false; 752182911Ssbruno bool display_crom = false; 753182911Ssbruno bool send_bus_reset = false; 754182911Ssbruno bool display_crom_hex = false; 755182911Ssbruno bool load_crom_from_file = false; 756182911Ssbruno bool set_fwmem_target = false; 757182911Ssbruno bool dump_topology = false; 758182911Ssbruno bool dump_phy_reg = false; 759108441Ssimokawa 760182911Ssbruno int32_t priority_budget = -1; 761182911Ssbruno int32_t set_root_node = -1; 762182911Ssbruno int32_t set_gap_count = -1; 763182911Ssbruno int32_t send_link_on = -1; 764182911Ssbruno int32_t send_reset_start = -1; 765108441Ssimokawa 766182911Ssbruno char *crom_string = NULL; 767182911Ssbruno char *crom_string_hex = NULL; 768182911Ssbruno char *recv_data = NULL; 769182911Ssbruno char *send_data = NULL; 770182911Ssbruno 771108441Ssimokawa if (argc < 2) { 772182911Ssbruno for (current_board = 0; current_board < MAX_BOARDS; current_board++) { 773185996Ssbruno snprintf(devbase, sizeof(devbase), "%s%d.0", device_string, current_board); 774182911Ssbruno if (open_dev(&fd, devbase) < 0) { 775182911Ssbruno if (current_board == 0) { 776182911Ssbruno usage(); 777185996Ssbruno err(EX_IOERR, "%s: Error opening firewire controller #%d %s", 778185996Ssbruno __func__, current_board, devbase); 779182911Ssbruno } 780182911Ssbruno return(EIO); 781182911Ssbruno } 782182911Ssbruno list_dev(fd); 783182911Ssbruno close(fd); 784182911Ssbruno fd = -1; 785182911Ssbruno } 786108441Ssimokawa } 787182911Ssbruno /* 788182911Ssbruno * Parse all command line options, then execute requested operations. 789182911Ssbruno */ 790182911Ssbruno while ((ch = getopt(argc, argv, "M:f:g:m:o:s:b:prtc:d:l:u:R:S:")) != -1) { 791108441Ssimokawa switch(ch) { 792108441Ssimokawa case 'b': 793182911Ssbruno priority_budget = strtol(optarg, NULL, 0); 794182911Ssbruno if (priority_budget < 0 || priority_budget > INT32_MAX) 795185996Ssbruno errx(EX_USAGE, "%s: priority_budget out of range: %s", __func__, optarg); 796182911Ssbruno command_set = true; 797182911Ssbruno open_needed = true; 798182911Ssbruno display_board_only = false; 799108441Ssimokawa break; 800108441Ssimokawa case 'c': 801182911Ssbruno crom_string = malloc(strlen(optarg)+1); 802182911Ssbruno if (crom_string == NULL) 803182911Ssbruno err(EX_SOFTWARE, "%s:crom_string malloc", __func__); 804182911Ssbruno if ( (strtol(crom_string, NULL, 0) < 0) || strtol(crom_string, NULL, 0) > MAX_BOARDS) 805185996Ssbruno errx(EX_USAGE, "%s:Invalid value for node", __func__); 806182911Ssbruno strcpy(crom_string, optarg); 807182911Ssbruno display_crom = 1; 808182911Ssbruno open_needed = true; 809182911Ssbruno command_set = true; 810182911Ssbruno display_board_only = false; 811108441Ssimokawa break; 812108441Ssimokawa case 'd': 813182911Ssbruno crom_string_hex = malloc(strlen(optarg)+1); 814182911Ssbruno if (crom_string_hex == NULL) 815182911Ssbruno err(EX_SOFTWARE, "%s:crom_string_hex malloc", __func__); 816182911Ssbruno strcpy(crom_string_hex, optarg); 817182911Ssbruno display_crom_hex = 1; 818182911Ssbruno open_needed = true; 819182911Ssbruno command_set = true; 820182911Ssbruno display_board_only = false; 821108441Ssimokawa break; 822176810Ssimokawa case 'f': 823182911Ssbruno#define MAX_PHY_CONFIG 0x3f 824182911Ssbruno set_root_node = strtol(optarg, NULL, 0); 825182911Ssbruno if ( (set_root_node < 0) || (set_root_node > MAX_PHY_CONFIG) ) 826185996Ssbruno errx(EX_USAGE, "%s:set_root_node out of range", __func__); 827182911Ssbruno open_needed = true; 828182911Ssbruno command_set = true; 829182911Ssbruno display_board_only = false; 830176810Ssimokawa break; 831118457Ssimokawa case 'g': 832182911Ssbruno set_gap_count = strtol(optarg, NULL, 0); 833182911Ssbruno if ( (set_gap_count < 0) || (set_gap_count > MAX_PHY_CONFIG) ) 834185996Ssbruno errx(EX_USAGE, "%s:set_gap_count out of range", __func__); 835182911Ssbruno open_needed = true; 836182911Ssbruno command_set = true; 837182911Ssbruno display_board_only = false; 838118457Ssimokawa break; 839108441Ssimokawa case 'l': 840182911Ssbruno load_crom_from_file = 1; 841108441Ssimokawa load_crom(optarg, crom_buf); 842182911Ssbruno command_set = true; 843182911Ssbruno display_board_only = false; 844108441Ssimokawa break; 845136845Ssimokawa case 'm': 846182911Ssbruno set_fwmem_target = 1; 847182911Ssbruno open_needed = 0; 848182911Ssbruno command_set = true; 849182911Ssbruno display_board_only = false; 850182911Ssbruno if (eui64_hostton(optarg, &target) != 0 && 851182911Ssbruno eui64_aton(optarg, &target) != 0) 852185996Ssbruno errx(EX_USAGE, "%s: invalid target: %s", __func__, optarg); 853136845Ssimokawa break; 854118457Ssimokawa case 'o': 855182911Ssbruno send_link_on = str2node(fd, optarg); 856185996Ssbruno if ( (send_link_on < 0) || (send_link_on > MAX_PHY_CONFIG) ) 857185996Ssbruno errx(EX_USAGE, "%s: node out of range: %s\n",__func__, optarg); 858182911Ssbruno open_needed = true; 859182911Ssbruno command_set = true; 860182911Ssbruno display_board_only = false; 861118457Ssimokawa break; 862120432Ssimokawa case 'p': 863182911Ssbruno dump_phy_reg = 1; 864182911Ssbruno open_needed = true; 865182911Ssbruno command_set = true; 866182911Ssbruno display_board_only = false; 867120432Ssimokawa break; 868118457Ssimokawa case 'r': 869182911Ssbruno send_bus_reset = 1; 870182911Ssbruno open_needed = true; 871182911Ssbruno command_set = true; 872182911Ssbruno display_board_only = false; 873118457Ssimokawa break; 874118457Ssimokawa case 's': 875182911Ssbruno send_reset_start = str2node(fd, optarg); 876185996Ssbruno if ( (send_reset_start < 0) || (send_reset_start > MAX_PHY_CONFIG) ) 877185996Ssbruno errx(EX_USAGE, "%s: node out of range: %s\n", __func__, optarg); 878182911Ssbruno open_needed = true; 879182911Ssbruno command_set = true; 880182911Ssbruno display_board_only = false; 881118457Ssimokawa break; 882118457Ssimokawa case 't': 883182911Ssbruno dump_topology = 1; 884182911Ssbruno open_needed = true; 885182911Ssbruno command_set = true; 886182911Ssbruno display_board_only = false; 887118457Ssimokawa break; 888118457Ssimokawa case 'u': 889182911Ssbruno if(!command_set) 890182911Ssbruno display_board_only = true; 891182911Ssbruno current_board = strtol(optarg, NULL, 0); 892182911Ssbruno open_needed = true; 893118457Ssimokawa break; 894163712Simp case 'M': 895163712Simp switch (optarg[0]) { 896163712Simp case 'm': 897163712Simp recvfn = mpegtsrecv; 898163712Simp break; 899163712Simp case 'd': 900163712Simp recvfn = dvrecv; 901163712Simp break; 902163712Simp default: 903163712Simp errx(EX_USAGE, "unrecognized method: %s", 904163712Simp optarg); 905163712Simp } 906182911Ssbruno command_set = true; 907182911Ssbruno display_board_only = false; 908163712Simp break; 909109737Ssimokawa case 'R': 910182911Ssbruno recv_data = malloc(strlen(optarg)+1); 911182911Ssbruno if (recv_data == NULL) 912182911Ssbruno err(EX_SOFTWARE, "%s:recv_data malloc", __func__); 913182911Ssbruno strcpy(recv_data, optarg); 914182911Ssbruno open_needed = false; 915182911Ssbruno command_set = true; 916182911Ssbruno display_board_only = false; 917109737Ssimokawa break; 918109737Ssimokawa case 'S': 919182911Ssbruno send_data = malloc(strlen(optarg)+1); 920182911Ssbruno if (send_data == NULL) 921182911Ssbruno err(EX_SOFTWARE, "%s:send_data malloc", __func__); 922182911Ssbruno strcpy(send_data, optarg); 923182911Ssbruno open_needed = true; 924182911Ssbruno command_set = true; 925182911Ssbruno display_board_only = false; 926109737Ssimokawa break; 927185996Ssbruno case '?': 928108441Ssimokawa default: 929108441Ssimokawa usage(); 930185996Ssbruno warnc(EINVAL, "%s: Unknown command line arguments", __func__); 931182911Ssbruno return 0; 932108441Ssimokawa } 933182911Ssbruno } /* end while */ 934182911Ssbruno 935182911Ssbruno /* 936185996Ssbruno * Catch the error case when the user 937185996Ssbruno * executes the command with non ''-'' 938185996Ssbruno * delimited arguments. 939185996Ssbruno * Generate the usage() display and exit. 940185996Ssbruno */ 941185996Ssbruno if (!command_set && !display_board_only) { 942185996Ssbruno usage(); 943185996Ssbruno warnc(EINVAL, "%s: Unknown command line arguments", __func__); 944185996Ssbruno return 0; 945185996Ssbruno } 946185996Ssbruno 947185996Ssbruno /* 948182911Ssbruno * If -u <bus_number> is passed, execute 949182911Ssbruno * command for that card only. 950182911Ssbruno * 951182911Ssbruno * If -u <bus_number> is not passed, execute 952182911Ssbruno * command for card 0 only. 953182911Ssbruno * 954182911Ssbruno */ 955182911Ssbruno if(open_needed){ 956185996Ssbruno snprintf(devbase, sizeof(devbase), "%s%d.0", device_string, current_board); 957182911Ssbruno if (open_dev(&fd, devbase) < 0) { 958185996Ssbruno err(EX_IOERR, "%s: Error opening firewire controller #%d %s", __func__, current_board, devbase); 959182911Ssbruno } 960182911Ssbruno } 961182911Ssbruno /* 962182911Ssbruno * display the nodes on this board "-u" 963182911Ssbruno * only 964182911Ssbruno */ 965182911Ssbruno if (display_board_only) 966182911Ssbruno list_dev(fd); 967182911Ssbruno 968182911Ssbruno /* 969182911Ssbruno * dump_phy_reg "-p" 970182911Ssbruno */ 971182911Ssbruno if (dump_phy_reg) 972182911Ssbruno dump_phy_registers(fd); 973182911Ssbruno 974182911Ssbruno /* 975182911Ssbruno * send a BUS_RESET Event "-r" 976182911Ssbruno */ 977182911Ssbruno if (send_bus_reset) { 978182911Ssbruno if(ioctl(fd, FW_IBUSRST, &tmp) < 0) 979185996Ssbruno err(EX_IOERR, "%s: Ioctl of bus reset failed for %s", __func__, devbase); 980182911Ssbruno } 981182911Ssbruno /* 982182911Ssbruno * Print out the CROM for this node "-c" 983182911Ssbruno */ 984182911Ssbruno if (display_crom) { 985182911Ssbruno tmp = str2node(fd, crom_string); 986182911Ssbruno get_crom(fd, tmp, crom_buf, len); 987182911Ssbruno show_crom(crom_buf); 988182911Ssbruno free(crom_string); 989182911Ssbruno } 990182911Ssbruno /* 991182911Ssbruno * Hex Dump the CROM for this node "-d" 992182911Ssbruno */ 993182911Ssbruno if (display_crom_hex) { 994182911Ssbruno tmp = str2node(fd, crom_string_hex); 995182911Ssbruno get_crom(fd, tmp, crom_buf_hex, len); 996182911Ssbruno dump_crom(crom_buf_hex); 997182911Ssbruno free(crom_string_hex); 998182911Ssbruno } 999182911Ssbruno /* 1000182911Ssbruno * Set Priority Budget to value for this node "-b" 1001182911Ssbruno */ 1002182911Ssbruno if (priority_budget >= 0) 1003182911Ssbruno set_pri_req(fd, priority_budget); 1004182911Ssbruno 1005182911Ssbruno /* 1006182911Ssbruno * Explicitly set the root node of this bus to value "-f" 1007182911Ssbruno */ 1008182911Ssbruno if (set_root_node >= 0) 1009182911Ssbruno send_phy_config(fd, set_root_node, -1); 1010182911Ssbruno 1011182911Ssbruno /* 1012182911Ssbruno * Set the gap count for this card/bus "-g" 1013182911Ssbruno */ 1014182911Ssbruno if (set_gap_count >= 0) 1015182911Ssbruno send_phy_config(fd, -1, set_gap_count); 1016182911Ssbruno 1017182911Ssbruno /* 1018182911Ssbruno * Load a CROM from a file "-l" 1019182911Ssbruno */ 1020182911Ssbruno if (load_crom_from_file) 1021182911Ssbruno show_crom(crom_buf); 1022182911Ssbruno /* 1023182911Ssbruno * Set the fwmem target for a node to argument "-m" 1024182911Ssbruno */ 1025182911Ssbruno if (set_fwmem_target) { 1026182911Ssbruno eui.hi = ntohl(*(u_int32_t*)&(target.octet[0])); 1027182911Ssbruno eui.lo = ntohl(*(u_int32_t*)&(target.octet[4])); 1028185996Ssbruno#if defined(__FreeBSD__) 1029182911Ssbruno sysctl_set_int("hw.firewire.fwmem.eui64_hi", eui.hi); 1030182911Ssbruno sysctl_set_int("hw.firewire.fwmem.eui64_lo", eui.lo); 1031185996Ssbruno#elif defined(__NetBSD__) 1032185996Ssbruno sysctl_set_int("hw.fwmem.eui64_hi", eui.hi); 1033185996Ssbruno sysctl_set_int("hw.fwmem.eui64_lo", eui.lo); 1034185996Ssbruno#else 1035185996Ssbruno#warning "You need to add support for your OS" 1036185996Ssbruno#endif 1037185996Ssbruno 1038182911Ssbruno } 1039182911Ssbruno 1040182911Ssbruno /* 1041182911Ssbruno * Send a link on to this board/bus "-o" 1042182911Ssbruno */ 1043182911Ssbruno if (send_link_on >= 0) 1044182911Ssbruno link_on(fd, send_link_on); 1045182911Ssbruno 1046182911Ssbruno /* 1047182911Ssbruno * Send a reset start to this board/bus "-s" 1048182911Ssbruno */ 1049182911Ssbruno if (send_reset_start >= 0) 1050182911Ssbruno reset_start(fd, send_reset_start); 1051182911Ssbruno 1052182911Ssbruno /* 1053182911Ssbruno * Dump the node topology for this board/bus "-t" 1054182911Ssbruno */ 1055182911Ssbruno if (dump_topology) 1056182911Ssbruno show_topology_map(fd); 1057182911Ssbruno 1058182911Ssbruno /* 1059228990Suqs * Receive data file from node "-R" 1060182911Ssbruno */ 1061182911Ssbruno#define TAG (1<<6) 1062182911Ssbruno#define CHANNEL 63 1063182911Ssbruno if (recv_data != NULL){ 1064182911Ssbruno if (recvfn == NULL) { /* guess... */ 1065182911Ssbruno recvfn = detect_recv_fn(fd, TAG | CHANNEL); 1066182911Ssbruno close(fd); 1067186696Simp fd = -1; 1068182911Ssbruno } 1069185996Ssbruno snprintf(devbase, sizeof(devbase), "%s%d.0", device_string, current_board); 1070182911Ssbruno if (open_dev(&fd, devbase) < 0) 1071185996Ssbruno err(EX_IOERR, "%s: Error opening firewire controller #%d %s in recv_data\n", __func__, current_board, devbase); 1072182911Ssbruno (*recvfn)(fd, recv_data, TAG | CHANNEL, -1); 1073182911Ssbruno free(recv_data); 1074182911Ssbruno } 1075182911Ssbruno 1076182911Ssbruno /* 1077182911Ssbruno * Send data file to node "-S" 1078182911Ssbruno */ 1079182911Ssbruno if (send_data != NULL){ 1080182911Ssbruno dvsend(fd, send_data, TAG | CHANNEL, -1); 1081182911Ssbruno free(send_data); 1082182911Ssbruno } 1083182911Ssbruno 1084182911Ssbruno if (fd > 0) { 1085182911Ssbruno close(fd); 1086182911Ssbruno fd = -1; 1087182911Ssbruno } 1088108441Ssimokawa return 0; 1089108441Ssimokawa} 1090