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.7 2004/02/05 17:51:43 joerg 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 #include <machine/bus.h> 57 58 #include <sys/ioccom.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 cdevsw firewire_cdevsw = 87 { 88 #ifdef __DragonFly__ 89 "fw", CDEV_MAJOR, D_MEM, NULL, 0, 90 fw_open, fw_close, fw_read, fw_write, fw_ioctl, 91 fw_poll, fw_mmap, fw_strategy, nodump, nopsize, 92 #elif __FreeBSD_version >= 500104 93 .d_open = fw_open, 94 .d_close = fw_close, 95 .d_read = fw_read, 96 .d_write = fw_write, 97 .d_ioctl = fw_ioctl, 98 .d_poll = fw_poll, 99 .d_mmap = fw_mmap, 100 .d_strategy = fw_strategy, 101 .d_name = "fw", 102 .d_maj = CDEV_MAJOR, 103 .d_flags = D_MEM 104 #else 105 fw_open, fw_close, fw_read, fw_write, fw_ioctl, 106 fw_poll, fw_mmap, fw_strategy, "fw", CDEV_MAJOR, 107 nodump, nopsize, D_MEM, -1 108 #endif 109 }; 110 111 struct fw_drv1 { 112 struct fw_xferq *ir; 113 struct fw_xferq *it; 114 struct fw_isobufreq bufreq; 115 }; 116 117 static int 118 fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 119 struct fw_bufspec *b) 120 { 121 int i; 122 123 if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 124 return(EBUSY); 125 126 q->bulkxfer = (struct fw_bulkxfer *) malloc( 127 sizeof(struct fw_bulkxfer) * b->nchunk, 128 M_FW, M_WAITOK); 129 if (q->bulkxfer == NULL) 130 return(ENOMEM); 131 132 b->psize = roundup2(b->psize, sizeof(u_int32_t)); 133 q->buf = fwdma_malloc_multiseg(fc, sizeof(u_int32_t), 134 b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK); 135 136 if (q->buf == NULL) { 137 free(q->bulkxfer, M_FW); 138 q->bulkxfer = NULL; 139 return(ENOMEM); 140 } 141 q->bnchunk = b->nchunk; 142 q->bnpacket = b->npacket; 143 q->psize = (b->psize + 3) & ~3; 144 q->queued = 0; 145 146 STAILQ_INIT(&q->stvalid); 147 STAILQ_INIT(&q->stfree); 148 STAILQ_INIT(&q->stdma); 149 q->stproc = NULL; 150 151 for(i = 0 ; i < q->bnchunk; i++){ 152 q->bulkxfer[i].poffset = i * q->bnpacket; 153 q->bulkxfer[i].mbuf = NULL; 154 STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 155 } 156 157 q->flag &= ~FWXFERQ_MODEMASK; 158 q->flag |= FWXFERQ_STREAM; 159 q->flag |= FWXFERQ_EXTBUF; 160 161 return (0); 162 } 163 164 static int 165 fwdev_freebuf(struct fw_xferq *q) 166 { 167 if (q->flag & FWXFERQ_EXTBUF) { 168 if (q->buf != NULL) 169 fwdma_free_multiseg(q->buf); 170 q->buf = NULL; 171 free(q->bulkxfer, M_FW); 172 q->bulkxfer = NULL; 173 q->flag &= ~FWXFERQ_EXTBUF; 174 q->psize = 0; 175 q->maxq = FWMAXQUEUE; 176 } 177 return (0); 178 } 179 180 181 static int 182 fw_open (dev_t dev, int flags, int fmt, fw_proc *td) 183 { 184 int err = 0; 185 186 if (DEV_FWMEM(dev)) 187 return fwmem_open(dev, flags, fmt, td); 188 189 if (dev->si_drv1 != NULL) 190 return (EBUSY); 191 192 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 193 if ((dev->si_flags & SI_NAMED) == 0) { 194 int unit = DEV2UNIT(dev); 195 int sub = DEV2SUB(dev); 196 197 make_dev(&firewire_cdevsw, minor(dev), 198 UID_ROOT, GID_OPERATOR, 0660, 199 "fw%d.%d", unit, sub); 200 } 201 #endif 202 203 dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 204 205 return err; 206 } 207 208 static int 209 fw_close (dev_t dev, int flags, int fmt, fw_proc *td) 210 { 211 struct firewire_softc *sc; 212 struct firewire_comm *fc; 213 struct fw_drv1 *d; 214 int unit = DEV2UNIT(dev); 215 struct fw_xfer *xfer; 216 struct fw_bind *fwb; 217 int err = 0; 218 219 if (DEV_FWMEM(dev)) 220 return fwmem_close(dev, flags, fmt, td); 221 222 sc = devclass_get_softc(firewire_devclass, unit); 223 fc = sc->fc; 224 d = (struct fw_drv1 *)dev->si_drv1; 225 226 if (d->ir != NULL) { 227 struct fw_xferq *ir = d->ir; 228 229 if ((ir->flag & FWXFERQ_OPEN) == 0) 230 return (EINVAL); 231 if (ir->flag & FWXFERQ_RUNNING) { 232 ir->flag &= ~FWXFERQ_RUNNING; 233 fc->irx_disable(fc, ir->dmach); 234 } 235 /* free extbuf */ 236 fwdev_freebuf(ir); 237 /* drain receiving buffer */ 238 for (xfer = STAILQ_FIRST(&ir->q); 239 xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 240 ir->queued --; 241 STAILQ_REMOVE_HEAD(&ir->q, link); 242 243 xfer->resp = 0; 244 fw_xfer_done(xfer); 245 } 246 /* remove binding */ 247 for (fwb = STAILQ_FIRST(&ir->binds); fwb != NULL; 248 fwb = STAILQ_FIRST(&ir->binds)) { 249 STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist); 250 STAILQ_REMOVE_HEAD(&ir->binds, chlist); 251 free(fwb, M_FW); 252 } 253 ir->flag &= ~(FWXFERQ_OPEN | 254 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 255 d->ir = NULL; 256 257 } 258 if (d->it != NULL) { 259 struct fw_xferq *it = d->it; 260 261 if ((it->flag & FWXFERQ_OPEN) == 0) 262 return (EINVAL); 263 if (it->flag & FWXFERQ_RUNNING) { 264 it->flag &= ~FWXFERQ_RUNNING; 265 fc->itx_disable(fc, it->dmach); 266 } 267 /* free extbuf */ 268 fwdev_freebuf(it); 269 it->flag &= ~(FWXFERQ_OPEN | 270 FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 271 d->it = NULL; 272 } 273 free(dev->si_drv1, M_FW); 274 dev->si_drv1 = NULL; 275 276 return err; 277 } 278 279 /* 280 * read request. 281 */ 282 static int 283 fw_read (dev_t dev, struct uio *uio, int ioflag) 284 { 285 struct firewire_softc *sc; 286 struct fw_xferq *ir; 287 struct fw_xfer *xfer; 288 int err = 0, s, slept = 0; 289 int unit = DEV2UNIT(dev); 290 struct fw_pkt *fp; 291 292 if (DEV_FWMEM(dev)) 293 return physio(dev, uio, ioflag); 294 295 sc = devclass_get_softc(firewire_devclass, unit); 296 297 ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 298 if (ir == NULL || ir->buf == NULL) 299 return (EIO); 300 301 readloop: 302 xfer = STAILQ_FIRST(&ir->q); 303 if (ir->stproc == NULL) { 304 /* iso bulkxfer */ 305 ir->stproc = STAILQ_FIRST(&ir->stvalid); 306 if (ir->stproc != NULL) { 307 s = splfw(); 308 STAILQ_REMOVE_HEAD(&ir->stvalid, link); 309 splx(s); 310 ir->queued = 0; 311 } 312 } 313 if (xfer == NULL && ir->stproc == NULL) { 314 /* no data avaliable */ 315 if (slept == 0) { 316 slept = 1; 317 ir->flag |= FWXFERQ_WAKEUP; 318 err = tsleep(ir, FWPRI, "fw_read", hz); 319 ir->flag &= ~FWXFERQ_WAKEUP; 320 if (err == 0) 321 goto readloop; 322 } else if (slept == 1) 323 err = EIO; 324 return err; 325 } else if(xfer != NULL) { 326 #if 0 /* XXX broken */ 327 /* per packet mode or FWACT_CH bind?*/ 328 s = splfw(); 329 ir->queued --; 330 STAILQ_REMOVE_HEAD(&ir->q, link); 331 splx(s); 332 fp = &xfer->recv.hdr; 333 if (sc->fc->irx_post != NULL) 334 sc->fc->irx_post(sc->fc, fp->mode.ld); 335 err = uiomove((void *)fp, 1 /* XXX header size */, uio); 336 /* XXX copy payload too */ 337 /* XXX we should recycle this xfer */ 338 #endif 339 fw_xfer_free( xfer); 340 } else if(ir->stproc != NULL) { 341 /* iso bulkxfer */ 342 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 343 ir->stproc->poffset + ir->queued); 344 if(sc->fc->irx_post != NULL) 345 sc->fc->irx_post(sc->fc, fp->mode.ld); 346 if(fp->mode.stream.len == 0){ 347 err = EIO; 348 return err; 349 } 350 err = uiomove((caddr_t)fp, 351 fp->mode.stream.len + sizeof(u_int32_t), uio); 352 ir->queued ++; 353 if(ir->queued >= ir->bnpacket){ 354 s = splfw(); 355 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 356 splx(s); 357 sc->fc->irx_enable(sc->fc, ir->dmach); 358 ir->stproc = NULL; 359 } 360 if (uio->uio_resid >= ir->psize) { 361 slept = -1; 362 goto readloop; 363 } 364 } 365 return err; 366 } 367 368 static int 369 fw_write (dev_t dev, struct uio *uio, int ioflag) 370 { 371 int err = 0; 372 struct firewire_softc *sc; 373 int unit = DEV2UNIT(dev); 374 int s, slept = 0; 375 struct fw_pkt *fp; 376 struct firewire_comm *fc; 377 struct fw_xferq *it; 378 379 if (DEV_FWMEM(dev)) 380 return physio(dev, uio, ioflag); 381 382 sc = devclass_get_softc(firewire_devclass, unit); 383 fc = sc->fc; 384 it = ((struct fw_drv1 *)dev->si_drv1)->it; 385 if (it == NULL || it->buf == NULL) 386 return (EIO); 387 isoloop: 388 if (it->stproc == NULL) { 389 it->stproc = STAILQ_FIRST(&it->stfree); 390 if (it->stproc != NULL) { 391 s = splfw(); 392 STAILQ_REMOVE_HEAD(&it->stfree, link); 393 splx(s); 394 it->queued = 0; 395 } else if (slept == 0) { 396 slept = 1; 397 err = sc->fc->itx_enable(sc->fc, it->dmach); 398 if (err) 399 return err; 400 err = tsleep(it, FWPRI, "fw_write", hz); 401 if (err) 402 return err; 403 goto isoloop; 404 } else { 405 err = EIO; 406 return err; 407 } 408 } 409 fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 410 it->stproc->poffset + it->queued); 411 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 412 err = uiomove((caddr_t)fp->mode.stream.payload, 413 fp->mode.stream.len, uio); 414 it->queued ++; 415 if (it->queued >= it->bnpacket) { 416 s = splfw(); 417 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 418 splx(s); 419 it->stproc = NULL; 420 err = sc->fc->itx_enable(sc->fc, it->dmach); 421 } 422 if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 423 slept = 0; 424 goto isoloop; 425 } 426 return err; 427 } 428 /* 429 * ioctl support. 430 */ 431 int 432 fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 433 { 434 struct firewire_softc *sc; 435 struct firewire_comm *fc; 436 struct fw_drv1 *d; 437 int unit = DEV2UNIT(dev); 438 int s, i, len, err = 0; 439 struct fw_device *fwdev; 440 struct fw_bind *fwb; 441 struct fw_xferq *ir, *it; 442 struct fw_xfer *xfer; 443 struct fw_pkt *fp; 444 struct fw_devinfo *devinfo; 445 void *ptr; 446 447 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 448 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 449 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 450 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 451 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 452 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 453 454 if (DEV_FWMEM(dev)) 455 return fwmem_ioctl(dev, cmd, data, flag, td); 456 457 if (!data) 458 return(EINVAL); 459 460 sc = devclass_get_softc(firewire_devclass, unit); 461 fc = sc->fc; 462 d = (struct fw_drv1 *)dev->si_drv1; 463 ir = d->ir; 464 it = d->it; 465 466 switch (cmd) { 467 case FW_STSTREAM: 468 if (it == NULL) { 469 for (i = 0; i < fc->nisodma; i ++) { 470 it = fc->it[i]; 471 if ((it->flag & FWXFERQ_OPEN) == 0) 472 break; 473 } 474 if (i >= fc->nisodma) { 475 err = EBUSY; 476 break; 477 } 478 err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 479 if (err) 480 break; 481 it->flag |= FWXFERQ_OPEN; 482 } 483 it->flag &= ~0xff; 484 it->flag |= (0x3f & ichreq->ch); 485 it->flag |= ((0x3 & ichreq->tag) << 6); 486 d->it = it; 487 break; 488 case FW_GTSTREAM: 489 if (it != NULL) { 490 ichreq->ch = it->flag & 0x3f; 491 ichreq->tag = it->flag >> 2 & 0x3; 492 } else 493 err = EINVAL; 494 break; 495 case FW_SRSTREAM: 496 if (ir == NULL) { 497 for (i = 0; i < fc->nisodma; i ++) { 498 ir = fc->ir[i]; 499 if ((ir->flag & FWXFERQ_OPEN) == 0) 500 break; 501 } 502 if (i >= fc->nisodma) { 503 err = EBUSY; 504 break; 505 } 506 err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 507 if (err) 508 break; 509 ir->flag |= FWXFERQ_OPEN; 510 } 511 ir->flag &= ~0xff; 512 ir->flag |= (0x3f & ichreq->ch); 513 ir->flag |= ((0x3 & ichreq->tag) << 6); 514 d->ir = ir; 515 err = fc->irx_enable(fc, ir->dmach); 516 break; 517 case FW_GRSTREAM: 518 if (d->ir != NULL) { 519 ichreq->ch = ir->flag & 0x3f; 520 ichreq->tag = ir->flag >> 2 & 0x3; 521 } else 522 err = EINVAL; 523 break; 524 case FW_SSTBUF: 525 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 526 break; 527 case FW_GSTBUF: 528 bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 529 if (ir != NULL) { 530 ibufreq->rx.nchunk = ir->bnchunk; 531 ibufreq->rx.npacket = ir->bnpacket; 532 ibufreq->rx.psize = ir->psize; 533 } 534 bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 535 if (it != NULL) { 536 ibufreq->tx.nchunk = it->bnchunk; 537 ibufreq->tx.npacket = it->bnpacket; 538 ibufreq->tx.psize = it->psize; 539 } 540 break; 541 case FW_ASYREQ: 542 { 543 struct tcode_info *tinfo; 544 int pay_len = 0; 545 546 fp = &asyreq->pkt; 547 tinfo = &sc->fc->tcode[fp->mode.hdr.tcode]; 548 549 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 550 pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 551 552 xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 553 if (xfer == NULL) 554 return (ENOMEM); 555 556 switch (asyreq->req.type) { 557 case FWASREQNODE: 558 break; 559 case FWASREQEUI: 560 fwdev = fw_noderesolve_eui64(sc->fc, 561 &asyreq->req.dst.eui); 562 if (fwdev == NULL) { 563 device_printf(sc->fc->bdev, 564 "cannot find node\n"); 565 err = EINVAL; 566 goto out; 567 } 568 fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 569 break; 570 case FWASRESTL: 571 /* XXX what's this? */ 572 break; 573 case FWASREQSTREAM: 574 /* nothing to do */ 575 break; 576 } 577 578 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 579 if (pay_len > 0) 580 bcopy((char *)fp + tinfo->hdr_len, 581 (void *)&xfer->send.payload, pay_len); 582 xfer->send.spd = asyreq->req.sped; 583 xfer->act.hand = fw_asy_callback; 584 585 if ((err = fw_asyreq(sc->fc, -1, xfer)) != 0) 586 goto out; 587 if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0) 588 goto out; 589 if (xfer->resp != 0) { 590 err = EIO; 591 goto out; 592 } 593 if ((tinfo->flag & FWTI_TLABEL) == 0) 594 goto out; 595 596 /* copy response */ 597 tinfo = &sc->fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 598 if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) 599 asyreq->req.len = xfer->recv.pay_len; 600 else 601 err = EINVAL; 602 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 603 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, 604 MAX(0, asyreq->req.len - tinfo->hdr_len)); 605 out: 606 fw_xfer_free_buf(xfer); 607 break; 608 } 609 case FW_IBUSRST: 610 sc->fc->ibr(sc->fc); 611 break; 612 case FW_CBINDADDR: 613 fwb = fw_bindlookup(sc->fc, 614 bindreq->start.hi, bindreq->start.lo); 615 if(fwb == NULL){ 616 err = EINVAL; 617 break; 618 } 619 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 620 STAILQ_REMOVE(&ir->binds, fwb, fw_bind, chlist); 621 free(fwb, M_FW); 622 break; 623 case FW_SBINDADDR: 624 if(bindreq->len <= 0 ){ 625 err = EINVAL; 626 break; 627 } 628 if(bindreq->start.hi > 0xffff ){ 629 err = EINVAL; 630 break; 631 } 632 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); 633 if(fwb == NULL){ 634 err = ENOMEM; 635 break; 636 } 637 fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 638 bindreq->start.lo; 639 fwb->end = fwb->start + bindreq->len; 640 /* XXX */ 641 fwb->sub = ir->dmach; 642 fwb->act_type = FWACT_CH; 643 644 /* XXX alloc buf */ 645 xfer = fw_xfer_alloc(M_FWXFER); 646 if(xfer == NULL){ 647 free(fwb, M_FW); 648 return (ENOMEM); 649 } 650 xfer->fc = sc->fc; 651 652 s = splfw(); 653 /* XXX broken. need multiple xfer */ 654 STAILQ_INIT(&fwb->xferlist); 655 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 656 splx(s); 657 err = fw_bindadd(sc->fc, fwb); 658 break; 659 case FW_GDEVLST: 660 i = len = 1; 661 /* myself */ 662 devinfo = &fwdevlst->dev[0]; 663 devinfo->dst = sc->fc->nodeid; 664 devinfo->status = 0; /* XXX */ 665 devinfo->eui.hi = sc->fc->eui.hi; 666 devinfo->eui.lo = sc->fc->eui.lo; 667 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) { 668 if(len < FW_MAX_DEVLST){ 669 devinfo = &fwdevlst->dev[len++]; 670 devinfo->dst = fwdev->dst; 671 devinfo->status = 672 (fwdev->status == FWDEVINVAL)?0:1; 673 devinfo->eui.hi = fwdev->eui.hi; 674 devinfo->eui.lo = fwdev->eui.lo; 675 } 676 i++; 677 } 678 fwdevlst->n = i; 679 fwdevlst->info_len = len; 680 break; 681 case FW_GTPMAP: 682 bcopy(sc->fc->topology_map, data, 683 (sc->fc->topology_map->crc_len + 1) * 4); 684 break; 685 case FW_GCROM: 686 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) 687 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 688 break; 689 if (fwdev == NULL) { 690 if (!FW_EUI64_EQUAL(sc->fc->eui, crom_buf->eui)) { 691 err = FWNODE_INVAL; 692 break; 693 } 694 /* myself */ 695 ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 696 len = CROMSIZE; 697 for (i = 0; i < CROMSIZE/4; i++) 698 ((u_int32_t *)ptr)[i] 699 = ntohl(sc->fc->config_rom[i]); 700 } else { 701 /* found */ 702 ptr = (void *)&fwdev->csrrom[0]; 703 if (fwdev->rommax < CSRROMOFF) 704 len = 0; 705 else 706 len = fwdev->rommax - CSRROMOFF + 4; 707 } 708 if (crom_buf->len < len) 709 len = crom_buf->len; 710 else 711 crom_buf->len = len; 712 err = copyout(ptr, crom_buf->ptr, len); 713 if (fwdev == NULL) 714 /* myself */ 715 free(ptr, M_FW); 716 break; 717 default: 718 sc->fc->ioctl (dev, cmd, data, flag, td); 719 break; 720 } 721 return err; 722 } 723 int 724 fw_poll(dev_t dev, int events, fw_proc *td) 725 { 726 struct firewire_softc *sc; 727 struct fw_xferq *ir; 728 int revents; 729 int tmp; 730 int unit = DEV2UNIT(dev); 731 732 if (DEV_FWMEM(dev)) 733 return fwmem_poll(dev, events, td); 734 735 sc = devclass_get_softc(firewire_devclass, unit); 736 ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 737 revents = 0; 738 tmp = POLLIN | POLLRDNORM; 739 if (events & tmp) { 740 if (STAILQ_FIRST(&ir->q) != NULL) 741 revents |= tmp; 742 else 743 selrecord(td, &ir->rsel); 744 } 745 tmp = POLLOUT | POLLWRNORM; 746 if (events & tmp) { 747 /* XXX should be fixed */ 748 revents |= tmp; 749 } 750 751 return revents; 752 } 753 754 static int 755 #if defined(__DragonFly__) || __FreeBSD_version < 500102 756 fw_mmap (dev_t dev, vm_offset_t offset, int nproto) 757 #else 758 fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) 759 #endif 760 { 761 struct firewire_softc *sc; 762 int unit = DEV2UNIT(dev); 763 764 if (DEV_FWMEM(dev)) 765 #if defined(__DragonFly__) || __FreeBSD_version < 500102 766 return fwmem_mmap(dev, offset, nproto); 767 #else 768 return fwmem_mmap(dev, offset, paddr, nproto); 769 #endif 770 771 sc = devclass_get_softc(firewire_devclass, unit); 772 773 return EINVAL; 774 } 775 776 static void 777 fw_strategy(struct bio *bp) 778 { 779 dev_t dev; 780 781 dev = bp->bio_dev; 782 if (DEV_FWMEM(dev)) { 783 fwmem_strategy(bp); 784 return; 785 } 786 787 bp->bio_error = EOPNOTSUPP; 788 bp->bio_flags |= BIO_ERROR; 789 bp->bio_resid = bp->bio_bcount; 790 biodone(bp); 791 } 792 793 int 794 fwdev_makedev(struct firewire_softc *sc) 795 { 796 int err = 0; 797 798 #if defined(__DragonFly__) || __FreeBSD_version < 500000 799 cdevsw_add(&firewire_cdevsw); 800 #else 801 dev_t d; 802 int unit; 803 804 unit = device_get_unit(sc->fc->bdev); 805 sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), 806 UID_ROOT, GID_OPERATOR, 0660, 807 "fw%d.%d", unit, 0); 808 d = make_dev(&firewire_cdevsw, 809 MAKEMINOR(FWMEM_FLAG, unit, 0), 810 UID_ROOT, GID_OPERATOR, 0660, 811 "fwmem%d.%d", unit, 0); 812 dev_depends(sc->dev, d); 813 make_dev_alias(sc->dev, "fw%d", unit); 814 make_dev_alias(d, "fwmem%d", unit); 815 #endif 816 817 return (err); 818 } 819 820 int 821 fwdev_destroydev(struct firewire_softc *sc) 822 { 823 int err = 0; 824 825 #if defined(__DragonFly__) || __FreeBSD_version < 500000 826 cdevsw_remove(&firewire_cdevsw); 827 #else 828 destroy_dev(sc->dev); 829 #endif 830 return (err); 831 } 832 833 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 834 #define NDEVTYPE 2 835 void 836 fwdev_clone(void *arg, char *name, int namelen, dev_t *dev) 837 { 838 struct firewire_softc *sc; 839 char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 840 char *subp = NULL; 841 int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 842 int i, unit = 0, sub = 0; 843 844 if (*dev != NODEV) 845 return; 846 847 for (i = 0; i < NDEVTYPE; i++) 848 if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 849 goto found; 850 /* not match */ 851 return; 852 found: 853 854 if (subp == NULL || *subp++ != '.') 855 return; 856 857 /* /dev/fwU.S */ 858 while (isdigit(*subp)) { 859 sub *= 10; 860 sub += *subp++ - '0'; 861 } 862 if (*subp != '\0') 863 return; 864 865 sc = devclass_get_softc(firewire_devclass, unit); 866 if (sc == NULL) 867 return; 868 *dev = make_dev(&firewire_cdevsw, MAKEMINOR(devflag[i], unit, sub), 869 UID_ROOT, GID_OPERATOR, 0660, 870 "%s%d.%d", devnames[i], unit, sub); 871 (*dev)->si_flags |= SI_CHEAPCLONE; 872 dev_depends(sc->dev, *dev); 873 return; 874 } 875 #endif 876