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