]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/fwcontrol/fwcontrol.c
This commit was generated by cvs2svn to compensate for changes in r137015,
[FreeBSD/FreeBSD.git] / usr.sbin / fwcontrol / fwcontrol.c
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  * $FreeBSD$
35  */
36
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>
46
47 #include <netinet/in.h>
48 #include <fcntl.h>
49 #include <stdio.h>
50 #include <err.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54
55 extern int dvrecv(int, char *, char, int);
56 extern int dvsend(int, char *, char, int);
57
58 static void
59 usage(void)
60 {
61         fprintf(stderr,
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"
71                 "\t-r: bus reset\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");
77         exit(0);
78 }
79
80 static void
81 fweui2eui64(const struct fw_eui64 *fweui, struct eui64 *eui)
82 {
83         *(u_int32_t*)&(eui->octet[0]) = htonl(fweui->hi);
84         *(u_int32_t*)&(eui->octet[4]) = htonl(fweui->lo);
85 }
86
87 static struct fw_devlstreq *
88 get_dev(int fd)
89 {
90         struct fw_devlstreq *data;
91
92         data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq));
93         if (data == NULL)
94                 err(1, "malloc");
95         if( ioctl(fd, FW_GDEVLST, data) < 0) {
96                         err(1, "ioctl");
97         }
98         return data;
99 }
100
101 static int
102 str2node(int fd, const char *nodestr)
103 {
104         struct eui64 eui, tmpeui;
105         struct fw_devlstreq *data;
106         char *endptr;
107         int i, node;
108
109         if (nodestr == '\0')
110                 return (-1);
111
112         /*
113          * Deal with classic node specifications.
114          */
115         node = strtol(nodestr, &endptr, 0);
116         if (*endptr == '\0')
117                 goto gotnode;
118
119         /*
120          * Try to get an eui and match it against available nodes.
121          */
122         if (eui64_hostton(nodestr, &eui) != 0 && eui64_aton(nodestr, &eui) != 0)
123                 return (-1);
124
125         data = get_dev(fd);
126
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;
131                         goto gotnode;
132                 }
133         }
134         if (i >= data->info_len)
135                 return (-1);
136
137 gotnode:
138         if (node < 0 || node > 63)
139                 return (-1);
140         else
141                 return (node);
142 }
143
144 static void
145 list_dev(int fd)
146 {
147         struct fw_devlstreq *data;
148         struct fw_devinfo *devinfo;
149         struct eui64 eui;
150         char addr[EUI64_SIZ];
151         int i;
152
153         data = get_dev(fd);
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,
162                         addr,
163                         devinfo->status
164                 );
165         }
166         free((void *)data);
167 }
168
169 static u_int32_t
170 read_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int read, u_int32_t data)
171 {
172         struct fw_asyreq *asyreq;
173         u_int32_t *qld, res;
174
175         asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16);
176         asyreq->req.len = 16;
177 #if 0
178         asyreq->req.type = FWASREQNODE;
179         asyreq->pkt.mode.rreqq.dst = FWLOCALBUS | node;
180 #else
181         asyreq->req.type = FWASREQEUI;
182         asyreq->req.dst.eui = eui;
183 #endif
184         asyreq->pkt.mode.rreqq.tlrt = 0;
185         if (read)
186                 asyreq->pkt.mode.rreqq.tcode = FWTCODE_RREQQ;
187         else
188                 asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ;
189
190         asyreq->pkt.mode.rreqq.dest_hi = 0xffff;
191         asyreq->pkt.mode.rreqq.dest_lo = addr_lo;
192
193         qld = (u_int32_t *)&asyreq->pkt;
194         if (!read)
195                 asyreq->pkt.mode.wreqq.data = data;
196
197         if (ioctl(fd, FW_ASYREQ, asyreq) < 0) {
198                 err(1, "ioctl");
199         }
200         res = qld[3];
201         free(asyreq);
202         if (read)
203                 return ntohl(res);
204         else
205                 return 0;
206 }
207
208 static void
209 send_phy_config(int fd, int root_node, int gap_count)
210 {
211         struct fw_asyreq *asyreq;
212
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;
219         if (root_node >= 0)
220                 asyreq->pkt.mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23;
221         if (gap_count >= 0)
222                 asyreq->pkt.mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16;
223         asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
224
225         printf("send phy_config root_node=%d gap_count=%d\n",
226                                                 root_node, gap_count);
227
228         if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
229                 err(1, "ioctl");
230         free(asyreq);
231 }
232
233 static void
234 send_link_on(int fd, int node)
235 {
236         struct fw_asyreq *asyreq;
237
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];
244
245         if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
246                 err(1, "ioctl");
247         free(asyreq);
248 }
249
250 static void
251 reset_start(int fd, int node)
252 {
253         struct fw_asyreq *asyreq;
254
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;
261
262         asyreq->pkt.mode.wreqq.dest_hi = 0xffff;
263         asyreq->pkt.mode.wreqq.dest_lo = 0xf0000000 | RESET_START;
264
265         asyreq->pkt.mode.wreqq.data = htonl(0x1);
266
267         if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
268                 err(1, "ioctl");
269         free(asyreq);
270 }
271
272 static void
273 set_pri_req(int fd, int pri_req)
274 {
275         struct fw_devlstreq *data;
276         struct fw_devinfo *devinfo;
277         struct eui64 eui;
278         char addr[EUI64_SIZ];
279         u_int32_t max, reg, old;
280         int i;
281
282         data = get_dev(fd);
283 #define BUGET_REG 0xf0000218
284         for (i = 0; i < data->info_len; i++) {
285                 devinfo = &data->dev[i];
286                 if (!devinfo->status)
287                         continue;
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) {
294                         old = (reg & 0x3f);
295                         max = (reg & 0x3f00) >> 8;
296                         if (pri_req > max)
297                                 pri_req =  max;
298                         printf(" 0x%x -> 0x%x\n", old, pri_req);
299                         read_write_quad(fd, devinfo->eui, BUGET_REG, 0, pri_req);
300                 } else {
301                         printf("\n");
302                 }
303         }
304         free((void *)data);
305 }
306
307 static void
308 parse_bus_info_block(u_int32_t *p, int info_len)
309 {
310         int i;
311         char addr[EUI64_SIZ];
312         struct bus_info *bi;
313         struct eui64 eui;
314
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"
322                 "EUI64: %s\n",
323                 bi->bus_name,
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,
327                 addr);
328 }
329
330 static int
331 get_crom(int fd, int node, void *crom_buf, int len)
332 {
333         struct fw_crom_buf buf;
334         int i, error;
335         struct fw_devlstreq *data;
336
337         data = get_dev(fd);
338
339         for (i = 0; i < data->info_len; i++) {
340                 if (data->dev[i].dst == node && data->dev[i].eui.lo != 0)
341                         break;
342         }
343         if (i == data->info_len)
344                 errx(1, "no such node %d.", node);
345         else
346                 buf.eui = data->dev[i].eui;
347         free((void *)data);
348
349         buf.len = len;
350         buf.ptr = crom_buf;
351         bzero(crom_buf, len);
352         if ((error = ioctl(fd, FW_GCROM, &buf)) < 0) {
353                 err(1, "ioctl");
354         }
355
356         return error;
357 }
358
359 static void
360 show_crom(u_int32_t *crom_buf)
361 {
362         int i;
363         struct crom_context cc;
364         char *desc, info[256];
365         static char *key_types = "ICLD";
366         struct csrreg *reg;
367         struct csrdirectory *dir;
368         struct csrhdr *hdr;
369         u_int16_t crc;
370
371         printf("first quad: 0x%08x ", *crom_buf);
372         if (crom_buf[0] == 0) {
373                 printf("(Invalid Configuration ROM)\n");
374                 return;
375         }
376         hdr = (struct csrhdr *)crom_buf;
377         if (hdr->info_len == 1) {
378                 /* minimum ROM */
379                 struct csrreg *reg;
380                 reg = (struct csrreg *)hdr;
381                 printf("verndor ID: 0x%06x\n",  reg->val);
382                 return;
383         }
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);
387         if (crc == hdr->crc)
388                 printf("(OK)\n");
389         else
390                 printf("(NG)\n");
391         parse_bus_info_block(crom_buf+1, hdr->info_len);
392
393         crom_init_context(&cc, crom_buf);
394         dir = cc.stack[0].dir;
395         if (!dir) {
396                 printf("no root directory - giving up\n");
397                 return;
398         }
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);
402         if (crc == dir->crc)
403                 printf("(OK)\n");
404         else
405                 printf("(NG)\n");
406         if (dir->crc_len < 1)
407                 return;
408         while (cc.depth >= 0) {
409                 desc = crom_desc(&cc, info, sizeof(info));
410                 reg = crom_get(&cc);
411                 for (i = 0; i < cc.depth; i++)
412                         printf("\t");
413                 printf("%02x(%c:%02x) %06x %s: %s\n",
414                         reg->key,
415                         key_types[(reg->key & CSRTYPE_MASK)>>6],
416                         reg->key & CSRKEY_MASK, reg->val,
417                         desc, info);
418                 crom_next(&cc);
419         }
420 }
421
422 #define DUMP_FORMAT     "%08x %08x %08x %08x %08x %08x %08x %08x\n"
423
424 static void
425 dump_crom(u_int32_t *p)
426 {
427         int len=1024, i;
428
429         for (i = 0; i < len/(4*8); i ++) {
430                 printf(DUMP_FORMAT,
431                         p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
432                 p += 8;
433         }
434 }
435
436 static void
437 load_crom(char *filename, u_int32_t *p)
438 {
439         FILE *file;
440         int len=1024, i;
441
442         if ((file = fopen(filename, "r")) == NULL)
443                 err(1, "load_crom");
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);
447                 p += 8;
448         }
449 }
450
451 static void
452 show_topology_map(int fd)
453 {
454         struct fw_topology_map *tmap;
455         union fw_self_id sid;
456         int i;
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));
462         if (tmap == NULL)
463                 return;
464         if (ioctl(fd, FW_GTPMAP, tmap) < 0) {
465                 err(1, "ioctl");
466         }
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"
471                 " ini more\n");
472         for (i = 0; i < tmap->crc_len - 2; i++) {
473                 sid = tmap->self_id[i];
474                 if (sid.p0.sequel) {
475                         printf("%02d sequel packet\n", sid.p0.phy_id);
476                         continue;
477                 }
478                 printf("%02d   %2d      %2d  %4s     %d    %d   %3s"
479                                 "     %s     %s     %s   %d    %d\n",
480                         sid.p0.phy_id,
481                         sid.p0.link_active,
482                         sid.p0.gap_count,
483                         speed[sid.p0.phy_speed],
484                         sid.p0.phy_delay,
485                         sid.p0.contender,
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,
491                         sid.p0.more_packets
492                 );
493         }
494         free(tmap);
495 }
496
497 static void
498 read_phy_registers(int fd, u_int8_t *buf, int offset, int len)
499 {
500         struct fw_reg_req_t reg;
501         int i;
502
503         for (i = 0; i < len; i++) {
504                 reg.addr = offset + i;
505                 if (ioctl(fd, FWOHCI_RDPHYREG, &reg) < 0)
506                         err(1, "ioctl");
507                 buf[i] = (u_int8_t) reg.data;
508                 printf("0x%02x ",  reg.data);
509         }
510         printf("\n");
511 }
512
513 static void
514 read_phy_page(int fd, u_int8_t *buf, int page, int port)
515 {
516         struct fw_reg_req_t reg;
517
518         reg.addr = 0x7;
519         reg.data = ((page & 7) << 5) | (port & 0xf);
520         if (ioctl(fd, FWOHCI_WRPHYREG, &reg) < 0)
521                 err(1, "ioctl");
522         read_phy_registers(fd, buf, 8, 8);
523 }
524
525 static void
526 dump_phy_registers(int fd)
527 {
528         struct phyreg_base b;
529         struct phyreg_page0 p;
530         struct phyreg_page1 v;
531         int i;
532
533         printf("=== base register ===\n");
534         read_phy_registers(fd, (u_int8_t *)&b, 0, 8);
535         printf(
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
552         );
553
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);
557                 printf(
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"
562                     "Port_error:0x%x\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,
568                     p.port_error,
569                     p.loop_disable, p.in_standby, p.hard_disable
570                 );
571         }
572         printf("\n=== page 1 ===\n");
573         read_phy_page(fd, (u_int8_t *)&v, 1, 0);
574         printf(
575             "Compliance:%d\n"
576             "Vendor_ID:0x%06x\n"
577             "Product_ID:0x%06x\n",
578             v.compliance,
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]
581         );
582 }
583
584 static void
585 open_dev(int *fd, char *devbase)
586 {
587         char devname[256];
588         int i;
589
590         if (*fd < 0) {
591                 for (i = 0; i < 4; i++) {
592                         snprintf(devname, sizeof(devname), "%s.%d", devbase, i);
593                         if ((*fd = open(devname, O_RDWR)) >= 0)
594                                 break;
595                 }
596                 if (*fd < 0)
597                         err(1, "open");
598
599         }
600 }
601
602 int
603 sysctl_set_int(char *name, int val)
604 {
605         if (sysctlbyname(name, NULL, NULL, &val, sizeof(int)) < 0)
606                 err(1, "sysctl %s failed.", name);
607 }
608
609 int
610 main(int argc, char **argv)
611 {
612         u_int32_t crom_buf[1024/4];
613         char devbase[1024] = "/dev/fw0";
614         int fd, i, tmp, ch, len=1024;
615         struct fw_eui64 eui;
616         struct eui64 target;
617
618         fd = -1;
619
620         if (argc < 2) {
621                 open_dev(&fd, devbase);
622                 list_dev(fd);
623         }
624
625         while ((ch = getopt(argc, argv, "g:m:o:s:b:prtc:d:l:u:R:S:")) != -1)
626                 switch(ch) {
627                 case 'b':
628                         tmp = strtol(optarg, NULL, 0);
629                         open_dev(&fd, devbase);
630                         set_pri_req(fd, tmp);
631                         break;
632                 case 'c':
633                         open_dev(&fd, devbase);
634                         tmp = str2node(fd, optarg);
635                         get_crom(fd, tmp, crom_buf, len);
636                         show_crom(crom_buf);
637                         break;
638                 case 'd':
639                         open_dev(&fd, devbase);
640                         tmp = str2node(fd, optarg);
641                         get_crom(fd, tmp, crom_buf, len);
642                         dump_crom(crom_buf);
643                         break;
644                 case 'g':
645                         tmp = strtol(optarg, NULL, 0);
646                         open_dev(&fd, devbase);
647                         send_phy_config(fd, -1, tmp);
648                         break;
649                 case 'l':
650                         load_crom(optarg, crom_buf);
651                         show_crom(crom_buf);
652                         break;
653                 case 'm':
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);
661                         break;
662                 case 'o':
663                         open_dev(&fd, devbase);
664                         tmp = str2node(fd, optarg);
665                         send_link_on(fd, tmp);
666                         break;
667                 case 'p':
668                         open_dev(&fd, devbase);
669                         dump_phy_registers(fd);
670                         break;
671                 case 'r':
672                         open_dev(&fd, devbase);
673                         if(ioctl(fd, FW_IBUSRST, &tmp) < 0)
674                                 err(1, "ioctl");
675                         break;
676                 case 's':
677                         open_dev(&fd, devbase);
678                         tmp = str2node(fd, optarg);
679                         reset_start(fd, tmp);
680                         break;
681                 case 't':
682                         open_dev(&fd, devbase);
683                         show_topology_map(fd);
684                         break;
685                 case 'u':
686                         tmp = strtol(optarg, NULL, 0);
687                         snprintf(devbase, sizeof(devbase), "/dev/fw%d",  tmp);
688                         if (fd > 0) {
689                                 close(fd);
690                                 fd = -1;
691                         }
692                         if (argc == optind) {
693                                 open_dev(&fd, devbase);
694                                 list_dev(fd);
695                         }
696                         break;
697 #define TAG     (1<<6)
698 #define CHANNEL 63
699                 case 'R':
700                         open_dev(&fd, devbase);
701                         dvrecv(fd, optarg, TAG | CHANNEL, -1);
702                         break;
703                 case 'S':
704                         open_dev(&fd, devbase);
705                         dvsend(fd, optarg, TAG | CHANNEL, -1);
706                         break;
707                 default:
708                         usage();
709                 }
710         return 0;
711 }