1 /* 2 * Copyright (c) 2003 Hidetoshi Shimokawa 3 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 4 * 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 acknowledgement as bellow: 16 * 17 * This product includes software developed by K. Kobayashi and H. Shimokawa 18 * 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 * 34 * $FreeBSD: src/sys/dev/firewire/fwdev.c,v 1.36 2004/01/22 14:41:17 simokawa Exp $ 35 * $DragonFly: src/sys/bus/firewire/fwdev.c,v 1.20 2008/01/06 16:55:49 swildner Exp $ 36 * 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/types.h> 42 #include <sys/mbuf.h> 43 #if defined(__DragonFly__) || __FreeBSD_version < 500000 44 #include <sys/buf.h> 45 #else 46 #include <sys/bio.h> 47 #endif 48 49 #include <sys/kernel.h> 50 #include <sys/malloc.h> 51 #include <sys/conf.h> 52 #include <sys/poll.h> 53 54 #include <sys/bus.h> 55 #include <sys/ctype.h> 56 57 #include <sys/ioccom.h> 58 #include <sys/thread2.h> 59 60 #ifdef __DragonFly__ 61 #include "firewire.h" 62 #include "firewirereg.h" 63 #include "fwdma.h" 64 #include "fwmem.h" 65 #include "iec68113.h" 66 #else 67 #include <dev/firewire/firewire.h> 68 #include <dev/firewire/firewirereg.h> 69 #include <dev/firewire/fwdma.h> 70 #include <dev/firewire/fwmem.h> 71 #include <dev/firewire/iec68113.h> 72 #endif 73 74 #define CDEV_MAJOR 127 75 #define FWNODE_INVAL 0xffff 76 77 static d_open_t fw_open; 78 static d_close_t fw_close; 79 static d_ioctl_t fw_ioctl; 80 static d_poll_t fw_poll; 81 static d_read_t fw_read; /* for Isochronous packet */ 82 static d_write_t fw_write; 83 static d_mmap_t fw_mmap; 84 static d_strategy_t fw_strategy; 85 86 struct dev_ops firewire_ops = 87 { 88 { "fw", CDEV_MAJOR, D_MEM }, 89 .d_open = fw_open, 90 .d_close = fw_close, 91 .d_read = fw_read, 92 .d_write = fw_write, 93 .d_ioctl = fw_ioctl, 94 .d_poll = fw_poll, 95 .d_mmap = fw_mmap, 96 .d_strategy = fw_strategy, 97 }; 98 99 struct fw_drv1 { 100 struct fw_xferq *ir; 101 struct fw_xferq *it; 102 struct fw_isobufreq bufreq; 103 }; 104 105 static int 106 fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 107 struct fw_bufspec *b) 108 { 109 int i; 110 111 if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 112 return(EBUSY); 113 114 q->bulkxfer = (struct fw_bulkxfer *) kmalloc( 115 sizeof(struct fw_bulkxfer) * b->nchunk, 116 M_FW, M_WAITOK); 117 118 b->psize = roundup2(b->psize, sizeof(u_int32_t)); 119 q->buf = fwdma_malloc_multiseg(fc, sizeof(u_int32_t), 120 b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK); 121 122 if (q->buf == NULL) { 123 kfree(q->bulkxfer, M_FW); 124 q->bulkxfer = NULL; 125 return(ENOMEM); 126 } 127 q->bnchunk = b->nchunk; 128 q->bnpacket = b->npacket; 129 q->psize = (b->psize + 3) & ~3; 130 q->queued = 0; 131 132 STAILQ_INIT(&q->stvalid); 133 STAILQ_INIT(&q->stfree); 134 STAILQ_INIT(&q->stdma); 135 q->stproc = NULL; 136 137 for(i = 0 ; i < q->bnchunk; i++){ 138 q->bulkxfer[i].poffset = i * q->bnpacket; 139 q->bulkxfer[i].mbuf = NULL; 140 STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 141 } 142 143 q->flag &= ~FWXFERQ_MODEMASK; 144 q->flag |= FWXFERQ_STREAM; 145 q->flag |= FWXFERQ_EXTBUF; 146 147 return (0); 148 } 149 150 static int 151 fwdev_freebuf(struct fw_xferq *q) 152 { 153 if (q->flag & FWXFERQ_EXTBUF) { 154 if (q->buf != NULL) 155 fwdma_free_multiseg(q->buf); 156 q->buf = NULL; 157 kfree(q->bulkxfer, M_FW); 158 q->bulkxfer = NULL; 159 q->flag &= ~FWXFERQ_EXTBUF; 160 q->psize = 0; 161 q->maxq = FWMAXQUEUE; 162 } 163 return (0); 164 } 165 166 167 static int 168 fw_open (struct dev_open_args *ap) 169 { 170 cdev_t dev = ap->a_head.a_dev; 171 int err = 0; 172 173 if (DEV_FWMEM(dev)) 174 return fwmem_open(ap); 175 176 if (dev->si_drv1 != NULL) 177 return (EBUSY); 178 179 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 180 if ((dev->si_flags & SI_NAMED) == 0) { 181 int unit = DEV2UNIT(dev); 182 int sub = DEV2SUB(dev); 183 184 make_dev(&firewire_ops, minor(dev), 185 UID_ROOT, GID_OPERATOR, 0660, 186 "fw%d.%d", unit, sub); 187 } 188 #endif 189 190 dev->si_drv1 = kmalloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 191 192 return err; 193 } 194 195 static int 196 fw_close (struct dev_close_args *ap) 197 { 198 cdev_t dev = ap->a_head.a_dev; 199 struct firewire_softc *sc; 200 struct firewire_comm *fc; 201 struct fw_drv1 *d; 202 int unit = DEV2UNIT(dev); 203 struct fw_xfer *xfer; 204 struct fw_bind *fwb; 205 int err = 0; 206 207 if (DEV_FWMEM(dev)) 208 return fwmem_close(ap); 209 210 sc = devclass_get_softc(firewire_devclass, unit); 211 fc = sc->fc; 212 d = (struct fw_drv1 *)dev->si_drv1; 213 214 if (d->ir != NULL) { 215 struct fw_xferq *ir = d->ir; 216 217 if ((ir->flag & FWXFERQ_OPEN) == 0) 218 return (EINVAL); 219 if (ir->flag & FWXFERQ_RUNNING) { 220 ir->flag &= ~FWXFERQ_RUNNING; 221 fc->irx_disable(fc, ir->dmach); 222 } 223 /* free extbuf */ 224 fwdev_freebuf(ir); 225 /* drain receiving buffer */ 226 for (xfer = STAILQ_FIRST(&ir->q); 227 xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 228 ir->queued --; 229 STAILQ_REMOVE_HEAD(&ir->q, link); 230 231 xfer->resp = 0; 232 fw_xfer_done(xfer); 233 } 234 /* remove binding */ 235 for (fwb = STAILQ_FIRST(&ir->binds); fwb != NULL; 236 fwb = STAILQ_FIRST(&ir->binds)) { 237 STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist); 238 STAILQ_REMOVE_HEAD(&ir->binds, chlist); 239 kfree(fwb, M_FW); 240 } 241 ir->flag &= ~(FWXFERQ_OPEN | 242 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 243 d->ir = NULL; 244 245 } 246 if (d->it != NULL) { 247 struct fw_xferq *it = d->it; 248 249 if ((it->flag & FWXFERQ_OPEN) == 0) 250 return (EINVAL); 251 if (it->flag & FWXFERQ_RUNNING) { 252 it->flag &= ~FWXFERQ_RUNNING; 253 fc->itx_disable(fc, it->dmach); 254 } 255 /* free extbuf */ 256 fwdev_freebuf(it); 257 it->flag &= ~(FWXFERQ_OPEN | 258 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 259 d->it = NULL; 260 } 261 kfree(dev->si_drv1, M_FW); 262 dev->si_drv1 = NULL; 263 264 return err; 265 } 266 267 /* 268 * read request. 269 */ 270 static int 271 fw_read (struct dev_read_args *ap) 272 { 273 cdev_t dev = ap->a_head.a_dev; 274 struct uio *uio = ap->a_uio; 275 struct firewire_softc *sc; 276 struct fw_xferq *ir; 277 struct fw_xfer *xfer; 278 int err = 0, slept = 0; 279 int unit = DEV2UNIT(dev); 280 struct fw_pkt *fp; 281 282 if (DEV_FWMEM(dev)) 283 return physread(ap); 284 285 sc = devclass_get_softc(firewire_devclass, unit); 286 287 ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 288 if (ir == NULL || ir->buf == NULL) 289 return (EIO); 290 291 readloop: 292 xfer = STAILQ_FIRST(&ir->q); 293 if (ir->stproc == NULL) { 294 /* iso bulkxfer */ 295 ir->stproc = STAILQ_FIRST(&ir->stvalid); 296 if (ir->stproc != NULL) { 297 crit_enter(); 298 STAILQ_REMOVE_HEAD(&ir->stvalid, link); 299 crit_exit(); 300 ir->queued = 0; 301 } 302 } 303 if (xfer == NULL && ir->stproc == NULL) { 304 /* no data avaliable */ 305 if (slept == 0) { 306 slept = 1; 307 ir->flag |= FWXFERQ_WAKEUP; 308 err = tsleep(ir, FWPRI, "fw_read", hz); 309 ir->flag &= ~FWXFERQ_WAKEUP; 310 if (err == 0) 311 goto readloop; 312 } else if (slept == 1) 313 err = EIO; 314 return err; 315 } else if(xfer != NULL) { 316 #if 0 /* XXX broken */ 317 /* per packet mode or FWACT_CH bind?*/ 318 crit_enter(); 319 ir->queued --; 320 STAILQ_REMOVE_HEAD(&ir->q, link); 321 crit_exit(); 322 fp = &xfer->recv.hdr; 323 if (sc->fc->irx_post != NULL) 324 sc->fc->irx_post(sc->fc, fp->mode.ld); 325 err = uiomove((void *)fp, 1 /* XXX header size */, uio); 326 /* XXX copy payload too */ 327 /* XXX we should recycle this xfer */ 328 #endif 329 fw_xfer_free( xfer); 330 } else if(ir->stproc != NULL) { 331 /* iso bulkxfer */ 332 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 333 ir->stproc->poffset + ir->queued); 334 if(sc->fc->irx_post != NULL) 335 sc->fc->irx_post(sc->fc, fp->mode.ld); 336 if(fp->mode.stream.len == 0){ 337 err = EIO; 338 return err; 339 } 340 err = uiomove((caddr_t)fp, 341 fp->mode.stream.len + sizeof(u_int32_t), uio); 342 ir->queued ++; 343 if(ir->queued >= ir->bnpacket){ 344 crit_enter(); 345 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 346 crit_exit(); 347 sc->fc->irx_enable(sc->fc, ir->dmach); 348 ir->stproc = NULL; 349 } 350 if (uio->uio_resid >= ir->psize) { 351 slept = -1; 352 goto readloop; 353 } 354 } 355 return err; 356 } 357 358 static int 359 fw_write (struct dev_write_args *ap) 360 { 361 cdev_t dev = ap->a_head.a_dev; 362 struct uio *uio = ap->a_uio; 363 int err = 0; 364 struct firewire_softc *sc; 365 int unit = DEV2UNIT(dev); 366 int slept = 0; 367 struct fw_pkt *fp; 368 struct firewire_comm *fc; 369 struct fw_xferq *it; 370 371 if (DEV_FWMEM(dev)) 372 return physwrite(ap); 373 374 sc = devclass_get_softc(firewire_devclass, unit); 375 fc = sc->fc; 376 it = ((struct fw_drv1 *)dev->si_drv1)->it; 377 if (it == NULL || it->buf == NULL) 378 return (EIO); 379 isoloop: 380 if (it->stproc == NULL) { 381 it->stproc = STAILQ_FIRST(&it->stfree); 382 if (it->stproc != NULL) { 383 crit_enter(); 384 STAILQ_REMOVE_HEAD(&it->stfree, link); 385 crit_exit(); 386 it->queued = 0; 387 } else if (slept == 0) { 388 slept = 1; 389 err = sc->fc->itx_enable(sc->fc, it->dmach); 390 if (err) 391 return err; 392 err = tsleep(it, FWPRI, "fw_write", hz); 393 if (err) 394 return err; 395 goto isoloop; 396 } else { 397 err = EIO; 398 return err; 399 } 400 } 401 fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 402 it->stproc->poffset + it->queued); 403 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 404 err = uiomove((caddr_t)fp->mode.stream.payload, 405 fp->mode.stream.len, uio); 406 it->queued ++; 407 if (it->queued >= it->bnpacket) { 408 crit_enter(); 409 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 410 crit_exit(); 411 it->stproc = NULL; 412 err = sc->fc->itx_enable(sc->fc, it->dmach); 413 } 414 if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 415 slept = 0; 416 goto isoloop; 417 } 418 return err; 419 } 420 /* 421 * ioctl support. 422 */ 423 int 424 fw_ioctl (struct dev_ioctl_args *ap) 425 { 426 cdev_t dev = ap->a_head.a_dev; 427 struct firewire_softc *sc; 428 struct firewire_comm *fc; 429 struct fw_drv1 *d; 430 int unit = DEV2UNIT(dev); 431 int i, len, err = 0; 432 struct fw_device *fwdev; 433 struct fw_bind *fwb; 434 struct fw_xferq *ir, *it; 435 struct fw_xfer *xfer; 436 struct fw_pkt *fp; 437 struct fw_devinfo *devinfo; 438 void *ptr; 439 440 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)ap->a_data; 441 struct fw_asyreq *asyreq = (struct fw_asyreq *)ap->a_data; 442 struct fw_isochreq *ichreq = (struct fw_isochreq *)ap->a_data; 443 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)ap->a_data; 444 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)ap->a_data; 445 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)ap->a_data; 446 447 if (DEV_FWMEM(dev)) 448 return fwmem_ioctl(ap); 449 450 if (!ap->a_data) 451 return(EINVAL); 452 453 sc = devclass_get_softc(firewire_devclass, unit); 454 fc = sc->fc; 455 d = (struct fw_drv1 *)dev->si_drv1; 456 ir = d->ir; 457 it = d->it; 458 459 switch (ap->a_cmd) { 460 case FW_STSTREAM: 461 if (it == NULL) { 462 for (i = 0; i < fc->nisodma; i ++) { 463 it = fc->it[i]; 464 if ((it->flag & FWXFERQ_OPEN) == 0) 465 break; 466 } 467 if (i >= fc->nisodma) { 468 err = EBUSY; 469 break; 470 } 471 err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 472 if (err) 473 break; 474 it->flag |= FWXFERQ_OPEN; 475 } 476 it->flag &= ~0xff; 477 it->flag |= (0x3f & ichreq->ch); 478 it->flag |= ((0x3 & ichreq->tag) << 6); 479 d->it = it; 480 break; 481 case FW_GTSTREAM: 482 if (it != NULL) { 483 ichreq->ch = it->flag & 0x3f; 484 ichreq->tag = it->flag >> 2 & 0x3; 485 } else 486 err = EINVAL; 487 break; 488 case FW_SRSTREAM: 489 if (ir == NULL) { 490 for (i = 0; i < fc->nisodma; i ++) { 491 ir = fc->ir[i]; 492 if ((ir->flag & FWXFERQ_OPEN) == 0) 493 break; 494 } 495 if (i >= fc->nisodma) { 496 err = EBUSY; 497 break; 498 } 499 err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 500 if (err) 501 break; 502 ir->flag |= FWXFERQ_OPEN; 503 } 504 ir->flag &= ~0xff; 505 ir->flag |= (0x3f & ichreq->ch); 506 ir->flag |= ((0x3 & ichreq->tag) << 6); 507 d->ir = ir; 508 err = fc->irx_enable(fc, ir->dmach); 509 break; 510 case FW_GRSTREAM: 511 if (d->ir != NULL) { 512 ichreq->ch = ir->flag & 0x3f; 513 ichreq->tag = ir->flag >> 2 & 0x3; 514 } else 515 err = EINVAL; 516 break; 517 case FW_SSTBUF: 518 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 519 break; 520 case FW_GSTBUF: 521 bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 522 if (ir != NULL) { 523 ibufreq->rx.nchunk = ir->bnchunk; 524 ibufreq->rx.npacket = ir->bnpacket; 525 ibufreq->rx.psize = ir->psize; 526 } 527 bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 528 if (it != NULL) { 529 ibufreq->tx.nchunk = it->bnchunk; 530 ibufreq->tx.npacket = it->bnpacket; 531 ibufreq->tx.psize = it->psize; 532 } 533 break; 534 case FW_ASYREQ: 535 { 536 struct tcode_info *tinfo; 537 int pay_len = 0; 538 539 fp = &asyreq->pkt; 540 tinfo = &sc->fc->tcode[fp->mode.hdr.tcode]; 541 542 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 543 pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 544 545 xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 546 if (xfer == NULL) 547 return (ENOMEM); 548 549 switch (asyreq->req.type) { 550 case FWASREQNODE: 551 break; 552 case FWASREQEUI: 553 fwdev = fw_noderesolve_eui64(sc->fc, 554 &asyreq->req.dst.eui); 555 if (fwdev == NULL) { 556 device_printf(sc->fc->bdev, 557 "cannot find node\n"); 558 err = EINVAL; 559 goto out; 560 } 561 fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 562 break; 563 case FWASRESTL: 564 /* XXX what's this? */ 565 break; 566 case FWASREQSTREAM: 567 /* nothing to do */ 568 break; 569 } 570 571 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 572 if (pay_len > 0) 573 bcopy((char *)fp + tinfo->hdr_len, 574 (void *)&xfer->send.payload, pay_len); 575 xfer->send.spd = asyreq->req.sped; 576 xfer->act.hand = fw_asy_callback; 577 578 if ((err = fw_asyreq(sc->fc, -1, xfer)) != 0) 579 goto out; 580 if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0) 581 goto out; 582 if (xfer->resp != 0) { 583 err = EIO; 584 goto out; 585 } 586 if ((tinfo->flag & FWTI_TLABEL) == 0) 587 goto out; 588 589 /* copy response */ 590 tinfo = &sc->fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 591 if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) 592 asyreq->req.len = xfer->recv.pay_len; 593 else 594 err = EINVAL; 595 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 596 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, 597 MAX(0, asyreq->req.len - tinfo->hdr_len)); 598 out: 599 fw_xfer_free_buf(xfer); 600 break; 601 } 602 case FW_IBUSRST: 603 sc->fc->ibr(sc->fc); 604 break; 605 case FW_CBINDADDR: 606 fwb = fw_bindlookup(sc->fc, 607 bindreq->start.hi, bindreq->start.lo); 608 if(fwb == NULL){ 609 err = EINVAL; 610 break; 611 } 612 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 613 STAILQ_REMOVE(&ir->binds, fwb, fw_bind, chlist); 614 kfree(fwb, M_FW); 615 break; 616 case FW_SBINDADDR: 617 if(bindreq->len <= 0 ){ 618 err = EINVAL; 619 break; 620 } 621 if(bindreq->start.hi > 0xffff ){ 622 err = EINVAL; 623 break; 624 } 625 fwb = kmalloc(sizeof (struct fw_bind), M_FW, M_WAITOK); 626 fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 627 bindreq->start.lo; 628 fwb->end = fwb->start + bindreq->len; 629 /* XXX */ 630 fwb->sub = ir->dmach; 631 fwb->act_type = FWACT_CH; 632 633 /* XXX alloc buf */ 634 xfer = fw_xfer_alloc(M_FWXFER); 635 if(xfer == NULL){ 636 kfree(fwb, M_FW); 637 return (ENOMEM); 638 } 639 xfer->fc = sc->fc; 640 641 crit_enter(); 642 /* XXX broken. need multiple xfer */ 643 STAILQ_INIT(&fwb->xferlist); 644 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 645 crit_exit(); 646 err = fw_bindadd(sc->fc, fwb); 647 break; 648 case FW_GDEVLST: 649 i = len = 1; 650 /* myself */ 651 devinfo = &fwdevlst->dev[0]; 652 devinfo->dst = sc->fc->nodeid; 653 devinfo->status = 0; /* XXX */ 654 devinfo->eui.hi = sc->fc->eui.hi; 655 devinfo->eui.lo = sc->fc->eui.lo; 656 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) { 657 if(len < FW_MAX_DEVLST){ 658 devinfo = &fwdevlst->dev[len++]; 659 devinfo->dst = fwdev->dst; 660 devinfo->status = 661 (fwdev->status == FWDEVINVAL)?0:1; 662 devinfo->eui.hi = fwdev->eui.hi; 663 devinfo->eui.lo = fwdev->eui.lo; 664 } 665 i++; 666 } 667 fwdevlst->n = i; 668 fwdevlst->info_len = len; 669 break; 670 case FW_GTPMAP: 671 bcopy(sc->fc->topology_map, ap->a_data, 672 (sc->fc->topology_map->crc_len + 1) * 4); 673 break; 674 case FW_GCROM: 675 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) 676 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 677 break; 678 if (fwdev == NULL) { 679 if (!FW_EUI64_EQUAL(sc->fc->eui, crom_buf->eui)) { 680 err = FWNODE_INVAL; 681 break; 682 } 683 /* myself */ 684 ptr = kmalloc(CROMSIZE, M_FW, M_WAITOK); 685 len = CROMSIZE; 686 for (i = 0; i < CROMSIZE/4; i++) 687 ((u_int32_t *)ptr)[i] 688 = ntohl(sc->fc->config_rom[i]); 689 } else { 690 /* found */ 691 ptr = (void *)&fwdev->csrrom[0]; 692 if (fwdev->rommax < CSRROMOFF) 693 len = 0; 694 else 695 len = fwdev->rommax - CSRROMOFF + 4; 696 } 697 if (crom_buf->len < len && crom_buf->len >= 0) 698 len = crom_buf->len; 699 else 700 crom_buf->len = len; 701 err = copyout(ptr, crom_buf->ptr, len); 702 if (fwdev == NULL) 703 /* myself */ 704 kfree(ptr, M_FW); 705 break; 706 default: 707 sc->fc->ioctl(ap); 708 break; 709 } 710 return err; 711 } 712 int 713 fw_poll(struct dev_poll_args *ap) 714 { 715 cdev_t dev = ap->a_head.a_dev; 716 struct firewire_softc *sc; 717 struct fw_xferq *ir; 718 int revents; 719 int tmp; 720 int unit = DEV2UNIT(dev); 721 722 if (DEV_FWMEM(dev)) 723 return fwmem_poll(ap); 724 725 sc = devclass_get_softc(firewire_devclass, unit); 726 ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 727 revents = 0; 728 tmp = POLLIN | POLLRDNORM; 729 if (ap->a_events & tmp) { 730 if (STAILQ_FIRST(&ir->q) != NULL) 731 revents |= tmp; 732 else 733 selrecord(curthread, &ir->rsel); 734 } 735 tmp = POLLOUT | POLLWRNORM; 736 if (ap->a_events & tmp) { 737 /* XXX should be fixed */ 738 revents |= tmp; 739 } 740 ap->a_events = revents; 741 return(0); 742 } 743 744 static int 745 fw_mmap (struct dev_mmap_args *ap) 746 { 747 cdev_t dev = ap->a_head.a_dev; 748 struct firewire_softc *sc; 749 int unit = DEV2UNIT(dev); 750 751 if (DEV_FWMEM(dev)) 752 return fwmem_mmap(ap); 753 sc = devclass_get_softc(firewire_devclass, unit); 754 755 return EINVAL; 756 } 757 758 static int 759 fw_strategy(struct dev_strategy_args *ap) 760 { 761 cdev_t dev = ap->a_head.a_dev; 762 struct bio *bio = ap->a_bio; 763 struct buf *bp = bio->bio_buf; 764 765 if (DEV_FWMEM(dev)) { 766 fwmem_strategy(ap); 767 return(0); 768 } 769 bp->b_error = EOPNOTSUPP; 770 bp->b_flags |= B_ERROR; 771 bp->b_resid = bp->b_bcount; 772 biodone(bio); 773 return(0); 774 } 775 776 int 777 fwdev_makedev(struct firewire_softc *sc) 778 { 779 int unit; 780 781 unit = device_get_unit(sc->fc->bdev); 782 dev_ops_add(&firewire_ops, FW_UNITMASK, FW_UNIT(unit)); 783 return(0); 784 } 785 786 int 787 fwdev_destroydev(struct firewire_softc *sc) 788 { 789 int unit; 790 791 unit = device_get_unit(sc->fc->bdev); 792 dev_ops_remove(&firewire_ops, FW_UNITMASK, FW_UNIT(unit)); 793 return(0); 794 } 795 796 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 797 #define NDEVTYPE 2 798 void 799 fwdev_clone(void *arg, char *name, int namelen, cdev_t *dev) 800 { 801 struct firewire_softc *sc; 802 char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 803 char *subp = NULL; 804 int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 805 int i, unit = 0, sub = 0; 806 807 if (*dev != NULL) 808 return; 809 810 for (i = 0; i < NDEVTYPE; i++) 811 if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 812 goto found; 813 /* not match */ 814 return; 815 found: 816 817 if (subp == NULL || *subp++ != '.') 818 return; 819 820 /* /dev/fwU.S */ 821 while (isdigit(*subp)) { 822 sub *= 10; 823 sub += *subp++ - '0'; 824 } 825 if (*subp != '\0') 826 return; 827 828 sc = devclass_get_softc(firewire_devclass, unit); 829 if (sc == NULL) 830 return; 831 *dev = make_dev(&firewire_ops, MAKEMINOR(devflag[i], unit, sub), 832 UID_ROOT, GID_OPERATOR, 0660, 833 "%s%d.%d", devnames[i], unit, sub); 834 (*dev)->si_flags |= SI_CHEAPCLONE; 835 dev_depends(sc->dev, *dev); 836 return; 837 } 838 #endif 839