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