1 /* $NetBSD: fwcontrol.c,v 1.10 2010/08/26 07:04:04 cegger Exp $ */ 2 /* 3 * Copyright (C) 2002 4 * Hidetoshi Shimokawa. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * 17 * This product includes software developed by Hidetoshi Shimokawa. 18 * 19 * 4. Neither the name of the author nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 #include <sys/cdefs.h> 36 //__FBSDID("$FreeBSD: src/usr.sbin/fwcontrol/fwcontrol.c,v 1.23 2006/10/26 22:33:38 imp Exp $"); 37 __RCSID("$NetBSD: fwcontrol.c,v 1.10 2010/08/26 07:04:04 cegger Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/malloc.h> 41 #include <sys/types.h> 42 #include <sys/sysctl.h> 43 #include <sys/socket.h> 44 #include <sys/ioctl.h> 45 #include <sys/errno.h> 46 #include "eui64.h" 47 #include <dev/ieee1394/firewire.h> 48 #include <dev/ieee1394/iec13213.h> 49 #include <dev/ieee1394/fwphyreg.h> 50 #include <dev/ieee1394/iec68113.h> 51 52 #include <netinet/in.h> 53 #include <fcntl.h> 54 #include <stdio.h> 55 #include <err.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <sysexits.h> 59 #include <unistd.h> 60 #include "fwmethods.h" 61 62 static void sysctl_set_int(const char *, int); 63 64 static void 65 usage(void) 66 { 67 fprintf(stderr, 68 "%s [-prt] [-b pri_req] [-c node] [-d node] [-f force_root ]\n" 69 "\t[-g gap_count] [-l file] [-M mode] [-m EUI64 | hostname]\n" 70 "\t[-o node] [-R filename] [-S filename] [-s node] [-u bus_num]\n" 71 "\n" 72 "\t-b: set PRIORITY_BUDGET register on all supported nodes\n" 73 "\t-c: read configuration ROM\n" 74 "\t-d: hex dump of configuration ROM\n" 75 "\t-f: force root node\n" 76 "\t-g: broadcast gap_count by phy_config packet\n" 77 "\t-l: load and parse hex dump file of configuration ROM\n" 78 "\t-M: specify dv or mpeg\n" 79 "\t-m: set fwmem target\n" 80 "\t-o: send link-on packet to the node\n" 81 "\t-p: dump PHY registers\n" 82 "\t-R: receive DV or MPEG TS stream\n" 83 "\t-r: bus reset\n" 84 "\t-S: send DV stream\n" 85 "\t-s: write RESET_START register on the node\n" 86 "\t-t: read topology map\n" 87 "\t-u: specify bus number\n", getprogname()); 88 exit(EX_USAGE); 89 } 90 91 static void 92 fweui2eui64(const struct fw_eui64 *fweui, struct eui64 *eui) 93 { 94 *(uint32_t*)&(eui->octet[0]) = htonl(fweui->hi); 95 *(uint32_t*)&(eui->octet[4]) = htonl(fweui->lo); 96 } 97 98 static void 99 get_dev(int fd, struct fw_devlstreq *data) 100 { 101 102 if (data == NULL) 103 err(EX_SOFTWARE, "%s: data malloc", __func__); 104 if (ioctl(fd, FW_GDEVLST, data) < 0) 105 err(EX_IOERR, "%s: ioctl", __func__); 106 } 107 108 static int 109 str2node(int fd, const char *nodestr) 110 { 111 struct eui64 eui, tmpeui; 112 struct fw_devlstreq *data; 113 char *endptr; 114 int i, node; 115 116 if (nodestr == '\0') 117 return -1; 118 119 /* 120 * Deal with classic node specifications. 121 */ 122 node = strtol(nodestr, &endptr, 0); 123 if (*endptr == '\0') 124 goto gotnode; 125 126 /* 127 * Try to get an eui and match it against available nodes. 128 */ 129 if (eui64_hostton(nodestr, &eui) != 0 && eui64_aton(nodestr, &eui) != 0) 130 return -1; 131 132 data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq)); 133 if (data == NULL) 134 err(EX_SOFTWARE, "%s: data malloc", __func__); 135 get_dev(fd,data); 136 137 for (i = 0; i < data->info_len; i++) { 138 fweui2eui64(&data->dev[i].eui, &tmpeui); 139 if (memcmp(&eui, &tmpeui, sizeof(struct eui64)) == 0) { 140 node = data->dev[i].dst; 141 if (data != NULL) 142 free(data); 143 goto gotnode; 144 } 145 } 146 if (i >= data->info_len) { 147 if (data != NULL) 148 free(data); 149 return -1; 150 } 151 152 gotnode: 153 if (node < 0 || node > 63) 154 return -1; 155 else 156 return node; 157 } 158 159 static void 160 list_dev(int fd) 161 { 162 struct fw_devlstreq *data; 163 struct fw_devinfo *devinfo; 164 struct eui64 eui; 165 char addr[EUI64_SIZ], hostname[40]; 166 int i; 167 168 data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq)); 169 if (data == NULL) 170 err(EX_SOFTWARE, "%s:data malloc", __func__); 171 get_dev(fd, data); 172 printf("%d devices (info_len=%d)\n", data->n, data->info_len); 173 printf("node EUI64 status hostname\n"); 174 for (i = 0; i < data->info_len; i++) { 175 devinfo = &data->dev[i]; 176 fweui2eui64(&devinfo->eui, &eui); 177 eui64_ntoa(&eui, addr, sizeof(addr)); 178 if (eui64_ntohost(hostname, sizeof(hostname), &eui)) 179 hostname[0] = 0; 180 printf("%4d %s %6d %s\n", 181 (devinfo->status || i == 0) ? devinfo->dst : -1, 182 addr, devinfo->status, hostname); 183 } 184 free((void *)data); 185 } 186 187 static uint32_t 188 read_write_quad(int fd, struct fw_eui64 eui, uint32_t addr_lo, int readmode, 189 uint32_t data) 190 { 191 struct fw_asyreq *asyreq; 192 uint32_t *qld, res; 193 194 asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16); 195 if (asyreq == NULL) 196 err(EX_SOFTWARE, "%s:asyreq malloc", __func__); 197 asyreq->req.len = 16; 198 #if 0 199 asyreq->req.type = FWASREQNODE; 200 asyreq->pkt.mode.rreqq.dst = FWLOCALBUS | node; 201 #else 202 asyreq->req.type = FWASREQEUI; 203 asyreq->req.dst.eui = eui; 204 #endif 205 asyreq->pkt.mode.rreqq.tlrt = 0; 206 if (readmode) 207 asyreq->pkt.mode.rreqq.tcode = FWTCODE_RREQQ; 208 else 209 asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ; 210 211 asyreq->pkt.mode.rreqq.dest_hi = 0xffff; 212 asyreq->pkt.mode.rreqq.dest_lo = addr_lo; 213 214 qld = (uint32_t *)&asyreq->pkt; 215 if (!readmode) 216 asyreq->pkt.mode.wreqq.data = htonl(data); 217 218 if (ioctl(fd, FW_ASYREQ, asyreq) < 0) 219 err(EX_IOERR, "%s: ioctl", __func__); 220 res = qld[3]; 221 free(asyreq); 222 if (readmode) 223 return ntohl(res); 224 else 225 return 0; 226 } 227 228 /* 229 * Send a PHY Config Packet 230 * ieee 1394a-2005 4.3.4.3 231 * 232 * Message ID Root ID R T Gap Count 233 * 00(2 bits) (6 bits) 1 1 (6 bits) 234 * 235 * if "R" is set, then Root ID will be the next 236 * root node upon the next bus reset. 237 * if "T" is set, then Gap Count will be the 238 * value that all nodes use for their Gap Count 239 * if "R" and "T" are not set, then this message 240 * is either ignored or interpreted as an extended 241 * PHY config Packet as per 1394a-2005 4.3.4.4 242 */ 243 static void 244 send_phy_config(int fd, int root_node, int gap_count) 245 { 246 struct fw_asyreq *asyreq; 247 248 asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12); 249 if (asyreq == NULL) 250 err(EX_SOFTWARE, "%s:asyreq malloc", __func__); 251 asyreq->req.len = 12; 252 asyreq->req.type = FWASREQNODE; 253 asyreq->pkt.mode.ld[0] = 0; 254 asyreq->pkt.mode.ld[1] = 0; 255 asyreq->pkt.mode.common.tcode = FWTCODE_PHY; 256 if (root_node >= 0) 257 asyreq->pkt.mode.ld[1] |= ((root_node << 24) | (1 << 23)); 258 if (gap_count >= 0) 259 asyreq->pkt.mode.ld[1] |= ((1 << 22) | (gap_count << 16)); 260 asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1]; 261 262 printf("send phy_config root_node=%d gap_count=%d\n", 263 root_node, gap_count); 264 265 if (ioctl(fd, FW_ASYREQ, asyreq) < 0) 266 err(EX_IOERR, "%s: ioctl", __func__); 267 free(asyreq); 268 } 269 270 static void 271 link_on(int fd, int node) 272 { 273 struct fw_asyreq *asyreq; 274 275 asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12); 276 if (asyreq == NULL) 277 err(EX_SOFTWARE, "%s:asyreq malloc", __func__); 278 asyreq->req.len = 12; 279 asyreq->req.type = FWASREQNODE; 280 asyreq->pkt.mode.common.tcode = FWTCODE_PHY; 281 asyreq->pkt.mode.ld[1] |= (1 << 30) | ((node & 0x3f) << 24); 282 asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1]; 283 284 if (ioctl(fd, FW_ASYREQ, asyreq) < 0) 285 err(EX_IOERR, "%s: ioctl", __func__); 286 free(asyreq); 287 } 288 289 static void 290 reset_start(int fd, int node) 291 { 292 struct fw_asyreq *asyreq; 293 294 asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16); 295 if (asyreq == NULL) 296 err(EX_SOFTWARE, "%s:asyreq malloc", __func__); 297 asyreq->req.len = 16; 298 asyreq->req.type = FWASREQNODE; 299 asyreq->pkt.mode.wreqq.dst = FWLOCALBUS | (node & 0x3f); 300 asyreq->pkt.mode.wreqq.tlrt = 0; 301 asyreq->pkt.mode.wreqq.tcode = FWTCODE_WREQQ; 302 303 asyreq->pkt.mode.wreqq.dest_hi = 0xffff; 304 asyreq->pkt.mode.wreqq.dest_lo = 0xf0000000 | RESET_START; 305 306 asyreq->pkt.mode.wreqq.data = htonl(0x1); 307 308 if (ioctl(fd, FW_ASYREQ, asyreq) < 0) 309 err(EX_IOERR, "%s: ioctl", __func__); 310 free(asyreq); 311 } 312 313 static void 314 set_pri_req(int fd, uint32_t pri_req) 315 { 316 struct fw_devlstreq *data; 317 struct fw_devinfo *devinfo; 318 struct eui64 eui; 319 char addr[EUI64_SIZ]; 320 uint32_t max, reg, old; 321 int i; 322 323 data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq)); 324 if (data == NULL) 325 err(EX_SOFTWARE, "%s:data malloc", __func__); 326 get_dev(fd, data); 327 #define BUGET_REG 0xf0000218 328 for (i = 0; i < data->info_len; i++) { 329 devinfo = &data->dev[i]; 330 if (!devinfo->status) 331 continue; 332 reg = read_write_quad(fd, devinfo->eui, BUGET_REG, 1, 0); 333 fweui2eui64(&devinfo->eui, &eui); 334 eui64_ntoa(&eui, addr, sizeof(addr)); 335 printf("%d %s, %08x", 336 devinfo->dst, addr, reg); 337 if (reg > 0) { 338 old = (reg & 0x3f); 339 max = (reg & 0x3f00) >> 8; 340 if (pri_req > max) 341 pri_req = max; 342 printf(" 0x%x -> 0x%x\n", old, pri_req); 343 read_write_quad(fd, devinfo->eui, BUGET_REG, 0, pri_req); 344 } else { 345 printf("\n"); 346 } 347 } 348 free((void *)data); 349 } 350 351 static void 352 parse_bus_info_block(uint32_t *p) 353 { 354 char addr[EUI64_SIZ]; 355 struct bus_info *bi; 356 struct eui64 eui; 357 358 bi = (struct bus_info *)p; 359 fweui2eui64(&bi->eui64, &eui); 360 eui64_ntoa(&eui, addr, sizeof(addr)); 361 printf("bus_name: 0x%04x\n" 362 "irmc:%d cmc:%d isc:%d bmc:%d pmc:%d\n" 363 "cyc_clk_acc:%d max_rec:%d max_rom:%d\n" 364 "generation:%d link_spd:%d\n" 365 "EUI64: %s\n", 366 bi->bus_name, 367 bi->irmc, bi->cmc, bi->isc, bi->bmc, bi->pmc, 368 bi->cyc_clk_acc, bi->max_rec, bi->max_rom, 369 bi->generation, bi->link_spd, 370 addr); 371 } 372 373 static int 374 get_crom(int fd, int node, void *crom_buf, int len) 375 { 376 struct fw_crom_buf buf; 377 int i, error; 378 struct fw_devlstreq *data; 379 380 data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq)); 381 if (data == NULL) 382 err(EX_SOFTWARE, "%s:data malloc", __func__); 383 get_dev(fd, data); 384 385 for (i = 0; i < data->info_len; i++) 386 if (data->dev[i].dst == node && data->dev[i].eui.lo != 0) 387 break; 388 if (i == data->info_len) 389 errx(1, "no such node %d.", node); 390 else 391 buf.eui = data->dev[i].eui; 392 free(data); 393 394 buf.len = len; 395 buf.ptr = crom_buf; 396 memset(crom_buf, 0, len); 397 if ((error = ioctl(fd, FW_GCROM, &buf)) < 0) 398 err(EX_IOERR, "%s: ioctl", __func__); 399 400 return error; 401 } 402 403 static void 404 show_crc(uint16_t crc, uint16_t good_crc) 405 { 406 if (crc == good_crc) 407 printf("(OK)\n"); 408 else 409 printf("(NG, 0x%x)\n", good_crc); 410 } 411 412 static void 413 show_crom(uint32_t *crom_buf) 414 { 415 int i; 416 struct crom_context cc; 417 const char *desc; 418 char info[256]; 419 static const char *key_types = "ICLD"; 420 struct csrreg *reg; 421 struct csrdirectory *dir; 422 struct csrhdr *hdr; 423 uint16_t crc; 424 425 printf("first quad: 0x%08x ", *crom_buf); 426 if (crom_buf[0] == 0) { 427 printf("(Invalid Configuration ROM)\n"); 428 return; 429 } 430 hdr = (struct csrhdr *)crom_buf; 431 if (hdr->info_len == 1) { 432 /* minimum ROM */ 433 reg = (struct csrreg *)hdr; 434 printf("vendor ID: 0x%06x\n", reg->val); 435 return; 436 } 437 crc = crom_crc(crom_buf+1, hdr->crc_len); 438 printf("info_len=%d crc_len=%d crc=0x%04x ", 439 hdr->info_len, hdr->crc_len, crc); 440 show_crc(crc, hdr->crc); 441 parse_bus_info_block(crom_buf+1); 442 443 crom_init_context(&cc, crom_buf); 444 dir = cc.stack[0].dir; 445 if (!dir) { 446 printf("no root directory - giving up\n"); 447 return; 448 } 449 crc = crom_crc((uint32_t *)&dir->entry[0], dir->crc_len); 450 printf("root_directory: len=0x%04x(%d) crc=0x%04x ", 451 dir->crc_len, dir->crc_len, crc); 452 show_crc(crc, dir->crc); 453 if (dir->crc_len < 1) 454 return; 455 while (cc.depth >= 0) { 456 desc = crom_desc(&cc, info, sizeof(info)); 457 reg = crom_get(&cc); 458 for (i = 0; i < cc.depth; i++) 459 printf("\t"); 460 printf("%02x(%c:%02x) %06x %s: %s\n", 461 reg->key, 462 key_types[(reg->key & CSRTYPE_MASK)>>6], 463 reg->key & CSRKEY_MASK, reg->val, 464 desc, info); 465 crom_next(&cc); 466 } 467 } 468 469 #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" 470 471 static void 472 dump_crom(uint32_t *p) 473 { 474 int len=1024, i; 475 476 for (i = 0; i < len/(4*8); i ++) { 477 printf(DUMP_FORMAT, 478 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 479 p += 8; 480 } 481 } 482 483 static void 484 load_crom(const char *filename, uint32_t *p) 485 { 486 FILE *file; 487 int len=1024, i; 488 489 if ((file = fopen(filename, "r")) == NULL) 490 err(EX_IOERR, "load_crom %s", filename); 491 for (i = 0; i < len/(4*8); i ++) { 492 fscanf(file, DUMP_FORMAT, p, p+1, p+2, p+3, p+4, p+5, p+6, p+7); 493 p += 8; 494 } 495 } 496 497 static void 498 show_topology_map(int fd) 499 { 500 struct fw_topology_map *tmap; 501 union fw_self_id sid; 502 int i; 503 static const char *port_status[] = {" ", "-", "P", "C"}; 504 static const char *pwr_class[] = {" 0W", "15W", "30W", "45W", 505 "-1W", "-2W", "-5W", "-9W"}; 506 static const char *speed[] = {"S100", "S200", "S400", "S800"}; 507 508 tmap = malloc(sizeof(struct fw_topology_map)); 509 if (tmap == NULL) 510 err(EX_SOFTWARE, "%s:tmap malloc", __func__); 511 if (ioctl(fd, FW_GTPMAP, tmap) < 0) 512 err(EX_IOERR, "%s: ioctl", __func__); 513 printf("crc_len: %d generation:%d node_count:%d sid_count:%d\n", 514 tmap->crc_len, tmap->generation, 515 tmap->node_count, tmap->self_id_count); 516 printf("id link gap_cnt speed delay cIRM power port0 port1 port2" 517 " ini more\n"); 518 for (i = 0; i < tmap->crc_len - 2; i++) { 519 sid = tmap->self_id[i]; 520 if (sid.p0.sequel) { 521 printf("%02d sequel packet\n", sid.p0.phy_id); 522 continue; 523 } 524 printf("%02d %2d %2d %4s %d %3s" 525 " %s %s %s %d %d\n", 526 sid.p0.phy_id, 527 sid.p0.link_active, 528 sid.p0.gap_count, 529 speed[sid.p0.phy_speed], 530 sid.p0.contender, 531 pwr_class[sid.p0.power_class], 532 port_status[sid.p0.port0], 533 port_status[sid.p0.port1], 534 port_status[sid.p0.port2], 535 sid.p0.initiated_reset, 536 sid.p0.more_packets 537 ); 538 } 539 free(tmap); 540 } 541 542 static void 543 read_phy_registers(int fd, uint8_t *buf, int offset, int len) 544 { 545 struct fw_reg_req_t reg; 546 int i; 547 548 for (i = 0; i < len; i++) { 549 reg.addr = offset + i; 550 if (ioctl(fd, FWOHCI_RDPHYREG, ®) < 0) 551 err(EX_IOERR, "%s: ioctl", __func__); 552 buf[i] = (uint8_t) reg.data; 553 printf("0x%02x ", reg.data); 554 } 555 printf("\n"); 556 } 557 558 static void 559 read_phy_page(int fd, uint8_t *buf, int page, int port) 560 { 561 struct fw_reg_req_t reg; 562 563 reg.addr = 0x7; 564 reg.data = ((page & 7) << 5) | (port & 0xf); 565 if (ioctl(fd, FWOHCI_WRPHYREG, ®) < 0) 566 err(EX_IOERR, "%s: ioctl", __func__); 567 read_phy_registers(fd, buf, 8, 8); 568 } 569 570 static void 571 dump_phy_registers(int fd) 572 { 573 struct phyreg_base b; 574 struct phyreg_page0 p; 575 struct phyreg_page1 v; 576 int i; 577 578 printf("=== base register ===\n"); 579 read_phy_registers(fd, (uint8_t *)&b, 0, 8); 580 printf( 581 "Physical_ID:%d R:%d CPS:%d\n" 582 "RHB:%d IBR:%d Gap_Count:%d\n" 583 "Extended:%d Num_Ports:%d\n" 584 "PHY_Speed:%d Delay:%d\n" 585 "LCtrl:%d C:%d Jitter:%d Pwr_Class:%d\n" 586 "WDIE:%d ISBR:%d CTOI:%d CPSI:%d STOI:%d PEI:%d EAA:%d EMC:%d\n" 587 "Max_Legacy_SPD:%d BLINK:%d Bridge:%d\n" 588 "Page_Select:%d Port_Select%d\n", 589 b.phy_id, b.r, b.cps, 590 b.rhb, b.ibr, b.gap_count, 591 b.extended, b.num_ports, 592 b.phy_speed, b.delay, 593 b.lctrl, b.c, b.jitter, b.pwr_class, 594 b.wdie, b.isbr, b.ctoi, b.cpsi, b.stoi, b.pei, b.eaa, b.emc, 595 b.legacy_spd, b.blink, b.bridge, 596 b.page_select, b.port_select 597 ); 598 599 for (i = 0; i < b.num_ports; i ++) { 600 printf("\n=== page 0 port %d ===\n", i); 601 read_phy_page(fd, (uint8_t *)&p, 0, i); 602 printf( 603 "Astat:%d BStat:%d Ch:%d Con:%d RXOK:%d Dis:%d\n" 604 "Negotiated_speed:%d PIE:%d Fault:%d Stanby_fault:%d Disscrm:%d B_Only:%d\n" 605 "DC_connected:%d Max_port_speed:%d LPP:%d Cable_speed:%d\n" 606 "Connection_unreliable:%d Beta_mode:%d\n" 607 "Port_error:0x%x\n" 608 "Loop_disable:%d In_standby:%d Hard_disable:%d\n", 609 p.astat, p.bstat, p.ch, p.con, p.rxok, p.dis, 610 p.negotiated_speed, p.pie, p.fault, p.stanby_fault, p.disscrm, p.b_only, 611 p.dc_connected, p.max_port_speed, p.lpp, p.cable_speed, 612 p.connection_unreliable, p.beta_mode, 613 p.port_error, 614 p.loop_disable, p.in_standby, p.hard_disable 615 ); 616 } 617 printf("\n=== page 1 ===\n"); 618 read_phy_page(fd, (uint8_t *)&v, 1, 0); 619 printf( 620 "Compliance:%d\n" 621 "Vendor_ID:0x%06x\n" 622 "Product_ID:0x%06x\n", 623 v.compliance, 624 (v.vendor_id[0] << 16) | (v.vendor_id[1] << 8) | v.vendor_id[2], 625 (v.product_id[0] << 16) | (v.product_id[1] << 8) | v.product_id[2] 626 ); 627 } 628 629 static int 630 open_dev(int *fd, const char *_devname) 631 { 632 633 if (*fd < 0) { 634 *fd = open(_devname, O_RDWR); 635 if (*fd < 0) 636 return -1; 637 } 638 return 0; 639 } 640 641 static void 642 sysctl_set_int(const char *name, int val) 643 { 644 if (sysctlbyname(name, NULL, NULL, &val, sizeof(int)) < 0) 645 err(1, "sysctl %s failed.", name); 646 } 647 648 static fwmethod * 649 detect_recv_fn(int fd, char ich) 650 { 651 char *buf; 652 struct fw_isochreq isoreq; 653 struct fw_isobufreq bufreq; 654 int len; 655 uint32_t *ptr; 656 struct ciphdr *ciph; 657 fwmethod *retfn; 658 #define RECV_NUM_PACKET 16 659 #define RECV_PACKET_SZ 1024 660 661 bufreq.rx.nchunk = 8; 662 bufreq.rx.npacket = RECV_NUM_PACKET; 663 bufreq.rx.psize = RECV_PACKET_SZ; 664 bufreq.tx.nchunk = 0; 665 bufreq.tx.npacket = 0; 666 bufreq.tx.psize = 0; 667 668 if (ioctl(fd, FW_SSTBUF, &bufreq) < 0) 669 err(EX_IOERR, "%s: ioctl FW_SSTBUF", __func__); 670 671 isoreq.ch = ich & 0x3f; 672 isoreq.tag = (ich >> 6) & 3; 673 674 if (ioctl(fd, FW_SRSTREAM, &isoreq) < 0) 675 err(EX_IOERR, "%s: ioctl FW_SRSTREAM", __func__); 676 677 buf = (char *)malloc(RECV_NUM_PACKET * RECV_PACKET_SZ); 678 if (buf == NULL) 679 err(EX_SOFTWARE, "%s:buf malloc", __func__); 680 /* 681 * fwdev.c seems to return EIO on error and 682 * the return value of the last uiomove 683 * on success. For now, checking that the 684 * return is not less than zero should be 685 * sufficient. fwdev.c::fw_read() should 686 * return the total length read, not the value 687 * of the last uiomove(). 688 */ 689 len = read(fd, buf, RECV_NUM_PACKET * RECV_PACKET_SZ); 690 if (len < 0) 691 err(EX_IOERR, "%s: error reading from device", __func__); 692 ptr = (uint32_t *) buf; 693 ciph = (struct ciphdr *)(ptr + 1); 694 695 switch (ciph->fmt) { 696 case CIP_FMT_DVCR: 697 fprintf(stderr, "Detected DV format on input.\n"); 698 retfn = dvrecv; 699 break; 700 case CIP_FMT_MPEG: 701 fprintf(stderr, "Detected MPEG TS format on input.\n"); 702 retfn = mpegtsrecv; 703 break; 704 default: 705 errx(EXIT_FAILURE, "Unsupported format for receiving: fmt=0x%x", 706 ciph->fmt); 707 } 708 free(buf); 709 return retfn; 710 } 711 712 int 713 main(int argc, char **argv) 714 { 715 #define MAX_BOARDS 10 716 uint32_t crom_buf[1024/4]; 717 uint32_t crom_buf_hex[1024/4]; 718 char devbase[64]; 719 const char *device_string = "/dev/fw"; 720 int fd = -1, ch, len=1024; 721 int32_t current_board = 0; 722 /* 723 * If !command_set, then -u will display the nodes for the board. 724 * This emulates the previous behavior when -u is passed by itself 725 */ 726 bool command_set = false; 727 bool open_needed = false; 728 long tmp; 729 struct fw_eui64 eui; 730 struct eui64 target; 731 fwmethod *recvfn = NULL; 732 733 /* 734 * Holders for which functions 735 * to iterate through 736 */ 737 bool display_board_only = false; 738 bool display_crom = false; 739 bool send_bus_reset = false; 740 bool display_crom_hex = false; 741 bool load_crom_from_file = false; 742 bool set_fwmem_target = false; 743 bool dump_topology = false; 744 bool dump_phy_reg = false; 745 746 int32_t priority_budget = -1; 747 int32_t set_root_node = -1; 748 int32_t set_gap_count = -1; 749 int32_t send_link_on = -1; 750 int32_t send_reset_start = -1; 751 752 char *crom_string = NULL; 753 char *crom_string_hex = NULL; 754 char *recv_data = NULL; 755 char *send_data = NULL; 756 757 if (argc < 2) { 758 for (current_board = 0; current_board < MAX_BOARDS; current_board++) { 759 snprintf(devbase, sizeof(devbase), "%s%d.0", device_string, current_board); 760 if (open_dev(&fd, devbase) < 0) { 761 if (current_board == 0) { 762 usage(); 763 err(EX_IOERR, "%s: Error opening firewire controller #%d %s", 764 __func__, current_board, devbase); 765 } 766 return EIO; 767 } 768 list_dev(fd); 769 close(fd); 770 fd = -1; 771 } 772 } 773 /* 774 * Parse all command line options, then execute requested operations. 775 */ 776 while ((ch = getopt(argc, argv, "b:c:d:f:g:l:M:m:o:pR:rS:s:tu:")) != -1) { 777 switch (ch) { 778 case 'b': 779 priority_budget = strtol(optarg, NULL, 0); 780 if (priority_budget < 0 || priority_budget > INT32_MAX) 781 errx(EX_USAGE, 782 "%s: priority_budget out of range: %s", 783 __func__, optarg); 784 command_set = true; 785 open_needed = true; 786 display_board_only = false; 787 break; 788 case 'c': 789 crom_string = malloc(strlen(optarg)+1); 790 if (crom_string == NULL) 791 err(EX_SOFTWARE, "%s:crom_string malloc", 792 __func__); 793 if (strtol(crom_string, NULL, 0) < 0 || 794 strtol(crom_string, NULL, 0) > MAX_BOARDS) 795 errx(EX_USAGE, "%s:Invalid value for node", 796 __func__); 797 strcpy(crom_string, optarg); 798 display_crom = 1; 799 open_needed = true; 800 command_set = true; 801 display_board_only = false; 802 break; 803 case 'd': 804 crom_string_hex = malloc(strlen(optarg)+1); 805 if (crom_string_hex == NULL) 806 err(EX_SOFTWARE, "%s:crom_string_hex malloc", 807 __func__); 808 strcpy(crom_string_hex, optarg); 809 display_crom_hex = 1; 810 open_needed = true; 811 command_set = true; 812 display_board_only = false; 813 break; 814 case 'f': 815 #define MAX_PHY_CONFIG 0x3f 816 set_root_node = strtol(optarg, NULL, 0); 817 if (set_root_node < 0 || set_root_node > MAX_PHY_CONFIG) 818 errx(EX_USAGE, "%s:set_root_node out of range", 819 __func__); 820 open_needed = true; 821 command_set = true; 822 display_board_only = false; 823 break; 824 case 'g': 825 set_gap_count = strtol(optarg, NULL, 0); 826 if (set_gap_count < 0 || set_gap_count > MAX_PHY_CONFIG) 827 errx(EX_USAGE, "%s:set_gap_count out of range", 828 __func__); 829 open_needed = true; 830 command_set = true; 831 display_board_only = false; 832 break; 833 case 'l': 834 load_crom_from_file = 1; 835 load_crom(optarg, crom_buf); 836 command_set = true; 837 display_board_only = false; 838 break; 839 case 'm': 840 set_fwmem_target = 1; 841 open_needed = 0; 842 command_set = true; 843 display_board_only = false; 844 if (eui64_hostton(optarg, &target) != 0 && 845 eui64_aton(optarg, &target) != 0) 846 errx(EX_USAGE, "%s: invalid target: %s", 847 __func__, optarg); 848 break; 849 case 'o': 850 send_link_on = str2node(fd, optarg); 851 if (send_link_on < 0 || send_link_on > MAX_PHY_CONFIG) 852 errx(EX_USAGE, "%s: node out of range: %s\n", 853 __func__, optarg); 854 open_needed = true; 855 command_set = true; 856 display_board_only = false; 857 break; 858 case 'p': 859 dump_phy_reg = 1; 860 open_needed = true; 861 command_set = true; 862 display_board_only = false; 863 break; 864 case 'r': 865 send_bus_reset = 1; 866 open_needed = true; 867 command_set = true; 868 display_board_only = false; 869 break; 870 case 's': 871 send_reset_start = str2node(fd, optarg); 872 if (send_reset_start < 0 || 873 send_reset_start > MAX_PHY_CONFIG) 874 errx(EX_USAGE, "%s: node out of range: %s\n", 875 __func__, optarg); 876 open_needed = true; 877 command_set = true; 878 display_board_only = false; 879 break; 880 case 't': 881 dump_topology = 1; 882 open_needed = true; 883 command_set = true; 884 display_board_only = false; 885 break; 886 case 'u': 887 if (!command_set) 888 display_board_only = true; 889 current_board = strtol(optarg, NULL, 0); 890 open_needed = true; 891 break; 892 case 'M': 893 switch (optarg[0]) { 894 case 'm': 895 recvfn = mpegtsrecv; 896 break; 897 case 'd': 898 recvfn = dvrecv; 899 break; 900 default: 901 errx(EX_USAGE, "unrecognized method: %s", 902 optarg); 903 } 904 command_set = true; 905 display_board_only = false; 906 break; 907 case 'R': 908 recv_data = malloc(strlen(optarg)+1); 909 if (recv_data == NULL) 910 err(EX_SOFTWARE, "%s:recv_data malloc", 911 __func__); 912 strcpy(recv_data, optarg); 913 open_needed = false; 914 command_set = true; 915 display_board_only = false; 916 break; 917 case 'S': 918 send_data = malloc(strlen(optarg)+1); 919 if (send_data == NULL) 920 err(EX_SOFTWARE, "%s:send_data malloc", 921 __func__); 922 strcpy(send_data, optarg); 923 open_needed = true; 924 command_set = true; 925 display_board_only = false; 926 break; 927 case '?': 928 default: 929 usage(); 930 errx(EINVAL, "%s: Unknown command line arguments", 931 __func__); 932 return 0; 933 } 934 } /* end while */ 935 936 /* 937 * Catch the error case when the user 938 * executes the command with non ''-'' 939 * delimited arguments. 940 * Generate the usage() display and exit. 941 */ 942 if (!command_set && !display_board_only) { 943 usage(); 944 errx(EINVAL, "%s: Unknown command line arguments", __func__); 945 return 0; 946 } 947 948 /* 949 * If -u <bus_number> is passed, execute 950 * command for that card only. 951 * 952 * If -u <bus_number> is not passed, execute 953 * command for card 0 only. 954 * 955 */ 956 if (open_needed) { 957 snprintf(devbase, sizeof(devbase), 958 "%s%d.0", device_string, current_board); 959 if (open_dev(&fd, devbase) < 0) { 960 err(EX_IOERR, 961 "%s: Error opening firewire controller #%d %s", 962 __func__, current_board, devbase); 963 } 964 } 965 /* 966 * display the nodes on this board "-u" only 967 */ 968 if (display_board_only) 969 list_dev(fd); 970 971 /* 972 * dump_phy_reg "-p" 973 */ 974 if (dump_phy_reg) 975 dump_phy_registers(fd); 976 977 /* 978 * send a BUS_RESET Event "-r" 979 */ 980 if (send_bus_reset) 981 if (ioctl(fd, FW_IBUSRST, &tmp) < 0) 982 err(EX_IOERR, "%s: Ioctl of bus reset failed for %s", 983 __func__, devbase); 984 /* 985 * Print out the CROM for this node "-c" 986 */ 987 if (display_crom) { 988 tmp = str2node(fd, crom_string); 989 get_crom(fd, tmp, crom_buf, len); 990 show_crom(crom_buf); 991 free(crom_string); 992 } 993 /* 994 * Hex Dump the CROM for this node "-d" 995 */ 996 if (display_crom_hex) { 997 tmp = str2node(fd, crom_string_hex); 998 get_crom(fd, tmp, crom_buf_hex, len); 999 dump_crom(crom_buf_hex); 1000 free(crom_string_hex); 1001 } 1002 /* 1003 * Set Priority Budget to value for this node "-b" 1004 */ 1005 if (priority_budget >= 0) 1006 set_pri_req(fd, priority_budget); 1007 1008 /* 1009 * Explicitly set the root node of this bus to value "-f" 1010 */ 1011 if (set_root_node >= 0) 1012 send_phy_config(fd, set_root_node, -1); 1013 1014 /* 1015 * Set the gap count for this card/bus "-g" 1016 */ 1017 if (set_gap_count >= 0) 1018 send_phy_config(fd, -1, set_gap_count); 1019 1020 /* 1021 * Load a CROM from a file "-l" 1022 */ 1023 if (load_crom_from_file) 1024 show_crom(crom_buf); 1025 /* 1026 * Set the fwmem target for a node to argument "-m" 1027 */ 1028 if (set_fwmem_target) { 1029 eui.hi = ntohl(*(uint32_t*)&(target.octet[0])); 1030 eui.lo = ntohl(*(uint32_t*)&(target.octet[4])); 1031 sysctl_set_int("hw.fwmem.eui64_hi", eui.hi); 1032 sysctl_set_int("hw.fwmem.eui64_lo", eui.lo); 1033 } 1034 1035 /* 1036 * Send a link on to this board/bus "-o" 1037 */ 1038 if (send_link_on >= 0) 1039 link_on(fd, send_link_on); 1040 1041 /* 1042 * Send a reset start to this board/bus "-s" 1043 */ 1044 if (send_reset_start >= 0) 1045 reset_start(fd, send_reset_start); 1046 1047 /* 1048 * Dump the node topology for this board/bus "-t" 1049 */ 1050 if (dump_topology) 1051 show_topology_map(fd); 1052 1053 /* 1054 * Recieve data file from node "-R" 1055 */ 1056 #define TAG (1<<6) 1057 #define CHANNEL 63 1058 if (recv_data != NULL){ 1059 if (recvfn == NULL) { /* guess... */ 1060 recvfn = detect_recv_fn(fd, TAG | CHANNEL); 1061 close(fd); 1062 fd = -1; 1063 } 1064 snprintf(devbase, sizeof(devbase), "%s%d.0", 1065 device_string, current_board); 1066 if (open_dev(&fd, devbase) < 0) 1067 err(EX_IOERR, "%s: Error opening firewire controller #%d %s in recv_data\n", 1068 __func__, current_board, devbase); 1069 (*recvfn)(fd, recv_data, TAG | CHANNEL, -1); 1070 free(recv_data); 1071 } 1072 1073 /* 1074 * Send data file to node "-S" 1075 */ 1076 if (send_data != NULL){ 1077 dvsend(fd, send_data, TAG | CHANNEL, -1); 1078 free(send_data); 1079 } 1080 1081 if (fd > 0) { 1082 close(fd); 1083 fd = -1; 1084 } 1085 return 0; 1086 } 1087