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