3 * Hidetoshi Shimokawa. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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:
16 * This product includes software developed by Hidetoshi Shimokawa.
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.
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
37 #include <sys/param.h>
38 #include <sys/malloc.h>
39 #include <sys/socket.h>
40 #include <sys/ioctl.h>
41 #include <sys/errno.h>
42 #include <sys/eui64.h>
43 #include <dev/firewire/firewire.h>
44 #include <dev/firewire/iec13213.h>
45 #include <dev/firewire/fwphyreg.h>
47 #include <netinet/in.h>
55 extern int dvrecv(int, char *, char, int);
56 extern int dvsend(int, char *, char, int);
62 "fwcontrol [-u bus_num] [-rt] [-g gap_count] [-o node] "
63 "[-b pri_req] [-c node] [-d node] [-l file] "
64 "[-R file] [-S file]\n"
65 "\t-u: specify bus number\n"
66 "\t-g: broadcast gap_count by phy_config packet\n"
67 "\t-o: send link-on packet to the node\n"
68 "\t-s: write RESET_START register on the node\n"
69 "\t-b: set PRIORITY_BUDGET register on all supported nodes\n"
70 "\t-c: read configuration ROM\n"
72 "\t-t: read topology map\n"
73 "\t-d: hex dump of configuration ROM\n"
74 "\t-l: load and parse hex dump file of configuration ROM\n"
75 "\t-R: Receive DV stream\n"
76 "\t-S: Send DV stream\n");
81 fweui2eui64(const struct fw_eui64 *fweui, struct eui64 *eui)
83 *(u_int32_t*)&(eui->octet[0]) = htonl(fweui->hi);
84 *(u_int32_t*)&(eui->octet[4]) = htonl(fweui->lo);
87 static struct fw_devlstreq *
90 struct fw_devlstreq *data;
92 data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq));
95 if( ioctl(fd, FW_GDEVLST, data) < 0) {
102 str2node(int fd, const char *nodestr)
104 struct eui64 eui, tmpeui;
105 struct fw_devlstreq *data;
113 * Deal with classic node specifications.
115 node = strtol(nodestr, &endptr, 0);
120 * Try to get an eui and match it against available nodes.
122 if (eui64_hostton(nodestr, &eui) != 0 && eui64_aton(nodestr, &eui) != 0)
127 for (i = 0; i < data->info_len; i++) {
128 fweui2eui64(&data->dev[i].eui, &tmpeui);
129 if (memcmp(&eui, &tmpeui, sizeof(struct eui64)) == 0) {
130 node = data->dev[i].dst;
134 if (i >= data->info_len)
138 if (node < 0 || node > 63)
147 struct fw_devlstreq *data;
148 struct fw_devinfo *devinfo;
150 char addr[EUI64_SIZ];
154 printf("%d devices (info_len=%d)\n", data->n, data->info_len);
155 printf("node EUI64 status\n");
156 for (i = 0; i < data->info_len; i++) {
157 devinfo = &data->dev[i];
158 fweui2eui64(&devinfo->eui, &eui);
159 eui64_ntoa(&eui, addr, sizeof(addr));
160 printf("%4d %s %6d\n",
161 (devinfo->status || i == 0) ? devinfo->dst : -1,
170 read_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int read, u_int32_t data)
172 struct fw_asyreq *asyreq;
175 asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16);
176 asyreq->req.len = 16;
178 asyreq->req.type = FWASREQNODE;
179 asyreq->pkt.mode.rreqq.dst = FWLOCALBUS | node;
181 asyreq->req.type = FWASREQEUI;
182 asyreq->req.dst.eui = eui;
184 asyreq->pkt.mode.rreqq.tlrt = 0;
186 asyreq->pkt.mode.rreqq.tcode = FWTCODE_RREQQ;
188 asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ;
190 asyreq->pkt.mode.rreqq.dest_hi = 0xffff;
191 asyreq->pkt.mode.rreqq.dest_lo = addr_lo;
193 qld = (u_int32_t *)&asyreq->pkt;
195 asyreq->pkt.mode.wreqq.data = data;
197 if (ioctl(fd, FW_ASYREQ, asyreq) < 0) {
209 send_phy_config(int fd, int root_node, int gap_count)
211 struct fw_asyreq *asyreq;
213 asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12);
214 asyreq->req.len = 12;
215 asyreq->req.type = FWASREQNODE;
216 asyreq->pkt.mode.ld[0] = 0;
217 asyreq->pkt.mode.ld[1] = 0;
218 asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
220 asyreq->pkt.mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23;
222 asyreq->pkt.mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16;
223 asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
225 printf("send phy_config root_node=%d gap_count=%d\n",
226 root_node, gap_count);
228 if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
234 send_link_on(int fd, int node)
236 struct fw_asyreq *asyreq;
238 asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12);
239 asyreq->req.len = 12;
240 asyreq->req.type = FWASREQNODE;
241 asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
242 asyreq->pkt.mode.ld[1] |= (1 << 30) | ((node & 0x3f) << 24);
243 asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
245 if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
251 reset_start(int fd, int node)
253 struct fw_asyreq *asyreq;
255 asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16);
256 asyreq->req.len = 16;
257 asyreq->req.type = FWASREQNODE;
258 asyreq->pkt.mode.wreqq.dst = FWLOCALBUS | (node & 0x3f);
259 asyreq->pkt.mode.wreqq.tlrt = 0;
260 asyreq->pkt.mode.wreqq.tcode = FWTCODE_WREQQ;
262 asyreq->pkt.mode.wreqq.dest_hi = 0xffff;
263 asyreq->pkt.mode.wreqq.dest_lo = 0xf0000000 | RESET_START;
265 asyreq->pkt.mode.wreqq.data = htonl(0x1);
267 if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
273 set_pri_req(int fd, int pri_req)
275 struct fw_devlstreq *data;
276 struct fw_devinfo *devinfo;
278 char addr[EUI64_SIZ];
279 u_int32_t max, reg, old;
283 #define BUGET_REG 0xf0000218
284 for (i = 0; i < data->info_len; i++) {
285 devinfo = &data->dev[i];
286 if (!devinfo->status)
288 reg = read_write_quad(fd, devinfo->eui, BUGET_REG, 1, 0);
289 fweui2eui64(&devinfo->eui, &eui);
290 eui64_ntoa(&eui, addr, sizeof(addr));
291 printf("%d %s, %08x",
292 devinfo->dst, addr, reg);
293 if (reg > 0 && pri_req >= 0) {
295 max = (reg & 0x3f00) >> 8;
298 printf(" 0x%x -> 0x%x\n", old, pri_req);
299 read_write_quad(fd, devinfo->eui, BUGET_REG, 0, pri_req);
308 parse_bus_info_block(u_int32_t *p, int info_len)
311 char addr[EUI64_SIZ];
315 bi = (struct bus_info *)p;
316 fweui2eui64(&bi->eui64, &eui);
317 eui64_ntoa(&eui, addr, sizeof(addr));
318 printf("bus_name: 0x%04x\n"
319 "irmc:%d cmc:%d isc:%d bmc:%d pmc:%d\n"
320 "cyc_clk_acc:%d max_rec:%d max_rom:%d\n"
321 "generation:%d link_spd:%d\n"
324 bi->irmc, bi->cmc, bi->isc, bi->bmc, bi->pmc,
325 bi->cyc_clk_acc, bi->max_rec, bi->max_rom,
326 bi->generation, bi->link_spd,
331 get_crom(int fd, int node, void *crom_buf, int len)
333 struct fw_crom_buf buf;
335 struct fw_devlstreq *data;
339 for (i = 0; i < data->info_len; i++) {
340 if (data->dev[i].dst == node && data->dev[i].eui.lo != 0)
343 if (i == data->info_len)
344 errx(1, "no such node %d.", node);
346 buf.eui = data->dev[i].eui;
351 bzero(crom_buf, len);
352 if ((error = ioctl(fd, FW_GCROM, &buf)) < 0) {
360 show_crom(u_int32_t *crom_buf)
363 struct crom_context cc;
364 char *desc, info[256];
365 static char *key_types = "ICLD";
367 struct csrdirectory *dir;
371 printf("first quad: 0x%08x ", *crom_buf);
372 if (crom_buf[0] == 0) {
373 printf("(Invalid Configuration ROM)\n");
376 hdr = (struct csrhdr *)crom_buf;
377 if (hdr->info_len == 1) {
380 reg = (struct csrreg *)hdr;
381 printf("verndor ID: 0x%06x\n", reg->val);
384 printf("info_len=%d crc_len=%d crc=0x%04x",
385 hdr->info_len, hdr->crc_len, hdr->crc);
386 crc = crom_crc(crom_buf+1, hdr->crc_len);
391 parse_bus_info_block(crom_buf+1, hdr->info_len);
393 crom_init_context(&cc, crom_buf);
394 dir = cc.stack[0].dir;
396 printf("no root directory - giving up\n");
399 printf("root_directory: len=0x%04x(%d) crc=0x%04x",
400 dir->crc_len, dir->crc_len, dir->crc);
401 crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
406 if (dir->crc_len < 1)
408 while (cc.depth >= 0) {
409 desc = crom_desc(&cc, info, sizeof(info));
411 for (i = 0; i < cc.depth; i++)
413 printf("%02x(%c:%02x) %06x %s: %s\n",
415 key_types[(reg->key & CSRTYPE_MASK)>>6],
416 reg->key & CSRKEY_MASK, reg->val,
422 #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
425 dump_crom(u_int32_t *p)
429 for (i = 0; i < len/(4*8); i ++) {
431 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
437 load_crom(char *filename, u_int32_t *p)
442 if ((file = fopen(filename, "r")) == NULL)
444 for (i = 0; i < len/(4*8); i ++) {
445 fscanf(file, DUMP_FORMAT,
446 p, p+1, p+2, p+3, p+4, p+5, p+6, p+7);
452 show_topology_map(int fd)
454 struct fw_topology_map *tmap;
455 union fw_self_id sid;
457 static char *port_status[] = {" ", "-", "P", "C"};
458 static char *pwr_class[] = {" 0W", "15W", "30W", "45W",
459 "-1W", "-2W", "-5W", "-9W"};
460 static char *speed[] = {"S100", "S200", "S400", "S800"};
461 tmap = malloc(sizeof(struct fw_topology_map));
464 if (ioctl(fd, FW_GTPMAP, tmap) < 0) {
467 printf("crc_len: %d generation:%d node_count:%d sid_count:%d\n",
468 tmap->crc_len, tmap->generation,
469 tmap->node_count, tmap->self_id_count);
470 printf("id link gap_cnt speed delay cIRM power port0 port1 port2"
472 for (i = 0; i < tmap->crc_len - 2; i++) {
473 sid = tmap->self_id[i];
475 printf("%02d sequel packet\n", sid.p0.phy_id);
478 printf("%02d %2d %2d %4s %d %d %3s"
483 speed[sid.p0.phy_speed],
486 pwr_class[sid.p0.power_class],
487 port_status[sid.p0.port0],
488 port_status[sid.p0.port1],
489 port_status[sid.p0.port2],
490 sid.p0.initiated_reset,
498 read_phy_registers(int fd, u_int8_t *buf, int offset, int len)
500 struct fw_reg_req_t reg;
503 for (i = 0; i < len; i++) {
504 reg.addr = offset + i;
505 if (ioctl(fd, FWOHCI_RDPHYREG, ®) < 0)
507 buf[i] = (u_int8_t) reg.data;
508 printf("0x%02x ", reg.data);
514 read_phy_page(int fd, u_int8_t *buf, int page, int port)
516 struct fw_reg_req_t reg;
519 reg.data = ((page & 7) << 5) | (port & 0xf);
520 if (ioctl(fd, FWOHCI_WRPHYREG, ®) < 0)
522 read_phy_registers(fd, buf, 8, 8);
526 dump_phy_registers(int fd)
528 struct phyreg_base b;
529 struct phyreg_page0 p;
530 struct phyreg_page1 v;
533 printf("=== base register ===\n");
534 read_phy_registers(fd, (u_int8_t *)&b, 0, 8);
536 "Physical_ID:%d R:%d CPS:%d\n"
537 "RHB:%d IBR:%d Gap_Count:%d\n"
538 "Extended:%d Num_Ports:%d\n"
539 "PHY_Speed:%d Delay:%d\n"
540 "LCtrl:%d C:%d Jitter:%d Pwr_Class:%d\n"
541 "WDIE:%d ISBR:%d CTOI:%d CPSI:%d STOI:%d PEI:%d EAA:%d EMC:%d\n"
542 "Max_Legacy_SPD:%d BLINK:%d Bridge:%d\n"
543 "Page_Select:%d Port_Select%d\n",
544 b.phy_id, b.r, b.cps,
545 b.rhb, b.ibr, b.gap_count,
546 b.extended, b.num_ports,
547 b.phy_speed, b.delay,
548 b.lctrl, b.c, b.jitter, b.pwr_class,
549 b.wdie, b.isbr, b.ctoi, b.cpsi, b.stoi, b.pei, b.eaa, b.emc,
550 b.legacy_spd, b.blink, b.bridge,
551 b.page_select, b.port_select
554 for (i = 0; i < b.num_ports; i ++) {
555 printf("\n=== page 0 port %d ===\n", i);
556 read_phy_page(fd, (u_int8_t *)&p, 0, i);
558 "Astat:%d BStat:%d Ch:%d Con:%d RXOK:%d Dis:%d\n"
559 "Negotiated_speed:%d PIE:%d Fault:%d Stanby_fault:%d Disscrm:%d B_Only:%d\n"
560 "DC_connected:%d Max_port_speed:%d LPP:%d Cable_speed:%d\n"
561 "Connection_unreliable:%d Beta_mode:%d\n"
563 "Loop_disable:%d In_standby:%d Hard_disable:%d\n",
564 p.astat, p.bstat, p.ch, p.con, p.rxok, p.dis,
565 p.negotiated_speed, p.pie, p.fault, p.stanby_fault, p.disscrm, p.b_only,
566 p.dc_connected, p.max_port_speed, p.lpp, p.cable_speed,
567 p.connection_unreliable, p.beta_mode,
569 p.loop_disable, p.in_standby, p.hard_disable
572 printf("\n=== page 1 ===\n");
573 read_phy_page(fd, (u_int8_t *)&v, 1, 0);
577 "Product_ID:0x%06x\n",
579 (v.vendor_id[0] << 16) | (v.vendor_id[1] << 8) | v.vendor_id[2],
580 (v.product_id[0] << 16) | (v.product_id[1] << 8) | v.product_id[2]
585 open_dev(int *fd, char *devbase)
591 for (i = 0; i < 4; i++) {
592 snprintf(devname, sizeof(devname), "%s.%d", devbase, i);
593 if ((*fd = open(devname, O_RDWR)) >= 0)
603 sysctl_set_int(char *name, int val)
605 if (sysctlbyname(name, NULL, NULL, &val, sizeof(int)) < 0)
606 err(1, "sysctl %s failed.", name);
610 main(int argc, char **argv)
612 u_int32_t crom_buf[1024/4];
613 char devbase[1024] = "/dev/fw0";
614 int fd, i, tmp, ch, len=1024;
621 open_dev(&fd, devbase);
625 while ((ch = getopt(argc, argv, "g:m:o:s:b:prtc:d:l:u:R:S:")) != -1)
628 tmp = strtol(optarg, NULL, 0);
629 open_dev(&fd, devbase);
630 set_pri_req(fd, tmp);
633 open_dev(&fd, devbase);
634 tmp = str2node(fd, optarg);
635 get_crom(fd, tmp, crom_buf, len);
639 open_dev(&fd, devbase);
640 tmp = str2node(fd, optarg);
641 get_crom(fd, tmp, crom_buf, len);
645 tmp = strtol(optarg, NULL, 0);
646 open_dev(&fd, devbase);
647 send_phy_config(fd, -1, tmp);
650 load_crom(optarg, crom_buf);
654 if (eui64_hostton(optarg, &target) != 0 &&
655 eui64_aton(optarg, &target) != 0)
656 errx(1, "invalid target: %s", optarg);
657 eui.hi = ntohl(*(u_int32_t*)&(target.octet[0]));
658 eui.lo = ntohl(*(u_int32_t*)&(target.octet[4]));
659 sysctl_set_int("hw.firewire.fwmem.eui64_hi", eui.hi);
660 sysctl_set_int("hw.firewire.fwmem.eui64_lo", eui.lo);
663 open_dev(&fd, devbase);
664 tmp = str2node(fd, optarg);
665 send_link_on(fd, tmp);
668 open_dev(&fd, devbase);
669 dump_phy_registers(fd);
672 open_dev(&fd, devbase);
673 if(ioctl(fd, FW_IBUSRST, &tmp) < 0)
677 open_dev(&fd, devbase);
678 tmp = str2node(fd, optarg);
679 reset_start(fd, tmp);
682 open_dev(&fd, devbase);
683 show_topology_map(fd);
686 tmp = strtol(optarg, NULL, 0);
687 snprintf(devbase, sizeof(devbase), "/dev/fw%d", tmp);
692 if (argc == optind) {
693 open_dev(&fd, devbase);
700 open_dev(&fd, devbase);
701 dvrecv(fd, optarg, TAG | CHANNEL, -1);
704 open_dev(&fd, devbase);
705 dvsend(fd, optarg, TAG | CHANNEL, -1);