1 /* 2 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 3 * 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 acknowledgement as bellow: 15 * 16 * This product includes software developed by K. Kobayashi and H. Shimokawa 17 * 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $FreeBSD$ 34 * 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/types.h> 40 #include <sys/mbuf.h> 41 42 #include <sys/kernel.h> 43 #include <sys/malloc.h> 44 #include <sys/conf.h> 45 #include <sys/uio.h> 46 #include <sys/poll.h> 47 48 #include <sys/bus.h> 49 50 #include <sys/ioccom.h> 51 52 #include <dev/firewire/firewire.h> 53 #include <dev/firewire/firewirereg.h> 54 #include <dev/firewire/fwmem.h> 55 #include <dev/firewire/iec68113.h> 56 57 #define CDEV_MAJOR 127 58 #define FWNODE_INVAL 0xffff 59 60 static d_open_t fw_open; 61 static d_close_t fw_close; 62 static d_ioctl_t fw_ioctl; 63 static d_poll_t fw_poll; 64 static d_read_t fw_read; /* for Isochronous packet */ 65 static d_write_t fw_write; 66 static d_mmap_t fw_mmap; 67 68 struct cdevsw firewire_cdevsw = 69 { 70 #if __FreeBSD_version >= 500104 71 .d_open = fw_open, 72 .d_close = fw_close, 73 .d_read = fw_read, 74 .d_write = fw_write, 75 .d_ioctl = fw_ioctl, 76 .d_poll = fw_poll, 77 .d_mmap = fw_mmap, 78 .d_name = "fw", 79 .d_maj = CDEV_MAJOR, 80 .d_flags = D_MEM 81 #else 82 fw_open, fw_close, fw_read, fw_write, fw_ioctl, 83 fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM 84 #endif 85 }; 86 87 static int 88 fw_open (dev_t dev, int flags, int fmt, fw_proc *td) 89 { 90 struct firewire_softc *sc; 91 int unit = DEV2UNIT(dev); 92 int sub = DEV2DMACH(dev); 93 94 int err = 0; 95 96 if (DEV_FWMEM(dev)) 97 return fwmem_open(dev, flags, fmt, td); 98 99 sc = devclass_get_softc(firewire_devclass, unit); 100 if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){ 101 err = EBUSY; 102 return err; 103 } 104 if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){ 105 err = EBUSY; 106 return err; 107 } 108 if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){ 109 err = EBUSY; 110 return err; 111 } 112 /* Default is per packet mode */ 113 sc->fc->ir[sub]->flag |= FWXFERQ_OPEN; 114 sc->fc->it[sub]->flag |= FWXFERQ_OPEN; 115 sc->fc->ir[sub]->flag |= FWXFERQ_PACKET; 116 return err; 117 } 118 119 static int 120 fw_close (dev_t dev, int flags, int fmt, fw_proc *td) 121 { 122 struct firewire_softc *sc; 123 int unit = DEV2UNIT(dev); 124 int sub = DEV2DMACH(dev); 125 struct fw_xfer *xfer; 126 struct fw_bind *fwb; 127 int err = 0; 128 129 if (DEV_FWMEM(dev)) 130 return fwmem_close(dev, flags, fmt, td); 131 132 sc = devclass_get_softc(firewire_devclass, unit); 133 if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){ 134 err = EINVAL; 135 return err; 136 } 137 sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN; 138 if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){ 139 err = EINVAL; 140 return err; 141 } 142 sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN; 143 144 if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){ 145 sc->fc->irx_disable(sc->fc, sub); 146 } 147 if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){ 148 sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING; 149 sc->fc->itx_disable(sc->fc, sub); 150 } 151 #ifdef FWXFERQ_DV 152 if(sc->fc->it[sub]->flag & FWXFERQ_DV){ 153 struct fw_dvbuf *dvbuf; 154 155 if((dvbuf = sc->fc->it[sub]->dvproc) != NULL){ 156 free(dvbuf->buf, M_FW); 157 sc->fc->it[sub]->dvproc = NULL; 158 } 159 if((dvbuf = sc->fc->it[sub]->dvdma) != NULL){ 160 free(dvbuf->buf, M_FW); 161 sc->fc->it[sub]->dvdma = NULL; 162 } 163 while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvvalid)) != NULL){ 164 STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvvalid, link); 165 free(dvbuf->buf, M_FW); 166 } 167 while((dvbuf = STAILQ_FIRST(&sc->fc->it[sub]->dvfree)) != NULL){ 168 STAILQ_REMOVE_HEAD(&sc->fc->it[sub]->dvfree, link); 169 free(dvbuf->buf, M_FW); 170 } 171 free(sc->fc->it[sub]->dvbuf, M_FW); 172 sc->fc->it[sub]->dvbuf = NULL; 173 } 174 #endif 175 if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){ 176 free(sc->fc->ir[sub]->buf, M_FW); 177 sc->fc->ir[sub]->buf = NULL; 178 free(sc->fc->ir[sub]->bulkxfer, M_FW); 179 sc->fc->ir[sub]->bulkxfer = NULL; 180 sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF; 181 sc->fc->ir[sub]->psize = PAGE_SIZE; 182 sc->fc->ir[sub]->maxq = FWMAXQUEUE; 183 } 184 if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){ 185 free(sc->fc->it[sub]->buf, M_FW); 186 sc->fc->it[sub]->buf = NULL; 187 free(sc->fc->it[sub]->bulkxfer, M_FW); 188 sc->fc->it[sub]->bulkxfer = NULL; 189 #ifdef FWXFERQ_DV 190 sc->fc->it[sub]->dvbuf = NULL; 191 #endif 192 sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF; 193 sc->fc->it[sub]->psize = 0; 194 sc->fc->it[sub]->maxq = FWMAXQUEUE; 195 } 196 for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q); 197 xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){ 198 sc->fc->ir[sub]->queued--; 199 STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link); 200 201 xfer->resp = 0; 202 switch(xfer->act_type){ 203 case FWACT_XFER: 204 fw_xfer_done(xfer); 205 break; 206 default: 207 break; 208 } 209 fw_xfer_free(xfer); 210 } 211 for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL; 212 fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){ 213 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 214 STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist); 215 free(fwb, M_FW); 216 } 217 sc->fc->ir[sub]->flag &= ~FWXFERQ_MODEMASK; 218 sc->fc->it[sub]->flag &= ~FWXFERQ_MODEMASK; 219 return err; 220 } 221 222 /* 223 * read request. 224 */ 225 static int 226 fw_read (dev_t dev, struct uio *uio, int ioflag) 227 { 228 struct firewire_softc *sc; 229 struct fw_xferq *ir; 230 struct fw_xfer *xfer; 231 int err = 0, s, slept = 0; 232 int unit = DEV2UNIT(dev); 233 int sub = DEV2DMACH(dev); 234 struct fw_pkt *fp; 235 236 if (DEV_FWMEM(dev)) 237 return fwmem_read(dev, uio, ioflag); 238 239 sc = devclass_get_softc(firewire_devclass, unit); 240 241 ir = sc->fc->ir[sub]; 242 243 if (ir->flag & FWXFERQ_PACKET) { 244 ir->stproc = NULL; 245 } 246 readloop: 247 xfer = STAILQ_FIRST(&ir->q); 248 if ((ir->flag & FWXFERQ_PACKET) == 0 && ir->stproc == NULL) { 249 /* iso bulkxfer */ 250 ir->stproc = STAILQ_FIRST(&ir->stvalid); 251 if (ir->stproc != NULL) { 252 s = splfw(); 253 STAILQ_REMOVE_HEAD(&ir->stvalid, link); 254 splx(s); 255 ir->queued = 0; 256 } 257 } 258 if (xfer == NULL && ir->stproc == NULL) { 259 /* no data avaliable */ 260 if (slept == 0) { 261 slept = 1; 262 if ((ir->flag & FWXFERQ_RUNNING) == 0 263 && (ir->flag & FWXFERQ_PACKET)) { 264 err = sc->fc->irx_enable(sc->fc, sub); 265 if (err) 266 return err; 267 } 268 ir->flag |= FWXFERQ_WAKEUP; 269 err = tsleep(ir, FWPRI, "fw_read", hz); 270 ir->flag &= ~FWXFERQ_WAKEUP; 271 if (err == 0) 272 goto readloop; 273 } else if (slept == 1) 274 err = EIO; 275 return err; 276 } else if(xfer != NULL) { 277 /* per packet mode */ 278 s = splfw(); 279 ir->queued --; 280 STAILQ_REMOVE_HEAD(&ir->q, link); 281 splx(s); 282 fp = (struct fw_pkt *)(xfer->recv.buf + xfer->recv.off); 283 if(sc->fc->irx_post != NULL) 284 sc->fc->irx_post(sc->fc, fp->mode.ld); 285 err = uiomove(xfer->recv.buf + xfer->recv.off, xfer->recv.len, uio); 286 fw_xfer_free( xfer); 287 } else if(ir->stproc != NULL) { 288 /* iso bulkxfer */ 289 fp = (struct fw_pkt *)(ir->stproc->buf + ir->queued * ir->psize); 290 if(sc->fc->irx_post != NULL) 291 sc->fc->irx_post(sc->fc, fp->mode.ld); 292 if(ntohs(fp->mode.stream.len) == 0){ 293 err = EIO; 294 return err; 295 } 296 err = uiomove((caddr_t)fp, 297 ntohs(fp->mode.stream.len) + sizeof(u_int32_t), uio); 298 #if 0 299 fp->mode.stream.len = 0; 300 #endif 301 ir->queued ++; 302 if(ir->queued >= ir->bnpacket){ 303 s = splfw(); 304 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 305 splx(s); 306 sc->fc->irx_enable(sc->fc, sub); 307 ir->stproc = NULL; 308 } 309 if (uio->uio_resid >= ir->psize) { 310 slept = -1; 311 goto readloop; 312 } 313 } 314 return err; 315 } 316 317 static int 318 fw_write (dev_t dev, struct uio *uio, int ioflag) 319 { 320 int err = 0; 321 struct firewire_softc *sc; 322 int unit = DEV2UNIT(dev); 323 int sub = DEV2DMACH(dev); 324 int s, slept = 0; 325 struct fw_pkt *fp; 326 struct fw_xfer *xfer; 327 struct fw_xferq *xferq; 328 struct firewire_comm *fc; 329 struct fw_xferq *it; 330 331 if (DEV_FWMEM(dev)) 332 return fwmem_write(dev, uio, ioflag); 333 334 sc = devclass_get_softc(firewire_devclass, unit); 335 fc = sc->fc; 336 it = sc->fc->it[sub]; 337 338 fp = (struct fw_pkt *)uio->uio_iov->iov_base; 339 switch(fp->mode.common.tcode){ 340 case FWTCODE_RREQQ: 341 case FWTCODE_RREQB: 342 case FWTCODE_LREQ: 343 err = EINVAL; 344 return err; 345 case FWTCODE_WREQQ: 346 case FWTCODE_WREQB: 347 xferq = fc->atq; 348 break; 349 case FWTCODE_STREAM: 350 if(it->flag & FWXFERQ_PACKET){ 351 xferq = fc->atq; 352 }else{ 353 xferq = NULL; 354 } 355 break; 356 case FWTCODE_WRES: 357 case FWTCODE_RRESQ: 358 case FWTCODE_RRESB: 359 case FWTCODE_LRES: 360 xferq = fc->ats; 361 break; 362 default: 363 err = EINVAL; 364 return err; 365 } 366 /* Discard unsent buffered stream packet, when sending Asyrequrst */ 367 if(xferq != NULL && it->stproc != NULL){ 368 s = splfw(); 369 STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link); 370 splx(s); 371 it->stproc = NULL; 372 } 373 #ifdef FWXFERQ_DV 374 if(xferq == NULL && !(it->flag & FWXFERQ_DV)){ 375 #else 376 if (xferq == NULL) { 377 #endif 378 isoloop: 379 if (it->stproc == NULL) { 380 it->stproc = STAILQ_FIRST(&it->stfree); 381 if (it->stproc != NULL) { 382 s = splfw(); 383 STAILQ_REMOVE_HEAD(&it->stfree, link); 384 splx(s); 385 it->queued = 0; 386 } else if (slept == 0) { 387 slept = 1; 388 err = sc->fc->itx_enable(sc->fc, sub); 389 if (err) 390 return err; 391 err = tsleep(it, FWPRI, 392 "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 *) 402 (it->stproc->buf + it->queued * it->psize); 403 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 404 err = uiomove((caddr_t)fp->mode.stream.payload, 405 ntohs(fp->mode.stream.len), uio); 406 it->queued ++; 407 if (it->queued >= it->bnpacket) { 408 s = splfw(); 409 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 410 splx(s); 411 it->stproc = NULL; 412 err = sc->fc->itx_enable(sc->fc, sub); 413 } 414 if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 415 slept = 0; 416 goto isoloop; 417 } 418 return err; 419 } 420 #ifdef FWXFERQ_DV 421 if(xferq == NULL && it->flag & FWXFERQ_DV){ 422 dvloop: 423 if(it->dvproc == NULL){ 424 it->dvproc = STAILQ_FIRST(&it->dvfree); 425 if(it->dvproc != NULL){ 426 s = splfw(); 427 STAILQ_REMOVE_HEAD(&it->dvfree, link); 428 splx(s); 429 it->dvptr = 0; 430 }else if(slept == 0){ 431 slept = 1; 432 err = sc->fc->itx_enable(sc->fc, sub); 433 if(err){ 434 return err; 435 } 436 err = tsleep(it, FWPRI, "fw_write", hz); 437 if(err){ 438 return err; 439 } 440 goto dvloop; 441 }else{ 442 err = EIO; 443 return err; 444 } 445 } 446 #if 0 /* What's this for? (it->dvptr? overwritten by the following uiomove)*/ 447 fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize); 448 fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t)); 449 #endif 450 err = uiomove(it->dvproc->buf + it->dvptr, 451 uio->uio_resid, uio); 452 it->dvptr += it->psize; 453 if(err){ 454 return err; 455 } 456 if(it->dvptr >= it->psize * it->dvpacket){ 457 s = splfw(); 458 STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link); 459 splx(s); 460 it->dvproc = NULL; 461 err = fw_tbuf_update(sc->fc, sub, 0); 462 if(err){ 463 return err; 464 } 465 err = sc->fc->itx_enable(sc->fc, sub); 466 } 467 return err; 468 } 469 #endif 470 if(xferq != NULL){ 471 xfer = fw_xfer_alloc(M_FWXFER); 472 if(xfer == NULL){ 473 err = ENOMEM; 474 return err; 475 } 476 xfer->send.buf = malloc(uio->uio_resid, M_FW, M_NOWAIT); 477 if(xfer->send.buf == NULL){ 478 fw_xfer_free( xfer); 479 err = ENOBUFS; 480 return err; 481 } 482 xfer->dst = ntohs(fp->mode.hdr.dst); 483 #if 0 484 switch(fp->mode.common.tcode){ 485 case FWTCODE_WREQQ: 486 case FWTCODE_WREQB: 487 if((tl = fw_get_tlabel(fc, xfer)) == -1 ){ 488 fw_xfer_free( xfer); 489 err = EAGAIN; 490 return err; 491 } 492 fp->mode.hdr.tlrt = tl << 2; 493 default: 494 break; 495 } 496 497 xfer->tl = fp->mode.hdr.tlrt >> 2; 498 xfer->tcode = fp->mode.common.tcode; 499 xfer->fc = fc; 500 xfer->q = xferq; 501 xfer->act_type = FWACT_XFER; 502 xfer->retry_req = fw_asybusy; 503 #endif 504 xfer->send.len = uio->uio_resid; 505 xfer->send.off = 0; 506 xfer->spd = 0;/* XXX: how to setup it */ 507 xfer->act.hand = fw_asy_callback; 508 509 err = uiomove(xfer->send.buf, uio->uio_resid, uio); 510 if(err){ 511 fw_xfer_free( xfer); 512 return err; 513 } 514 #if 0 515 fw_asystart(xfer); 516 #else 517 fw_asyreq(fc, -1, xfer); 518 #endif 519 err = tsleep(xfer, FWPRI, "fw_write", hz); 520 if(xfer->resp == EBUSY) 521 return EBUSY; 522 fw_xfer_free( xfer); 523 return err; 524 } 525 return EINVAL; 526 } 527 528 /* 529 * ioctl support. 530 */ 531 int 532 fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 533 { 534 struct firewire_softc *sc; 535 int unit = DEV2UNIT(dev); 536 int sub = DEV2DMACH(dev); 537 int i, len, err = 0; 538 struct fw_device *fwdev; 539 struct fw_bind *fwb; 540 struct fw_xferq *ir, *it; 541 struct fw_xfer *xfer; 542 struct fw_pkt *fp; 543 struct fw_devinfo *devinfo; 544 545 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 546 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 547 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 548 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 549 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 550 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 551 552 if (DEV_FWMEM(dev)) 553 return fwmem_ioctl(dev, cmd, data, flag, td); 554 555 sc = devclass_get_softc(firewire_devclass, unit); 556 if (!data) 557 return(EINVAL); 558 559 switch (cmd) { 560 case FW_STSTREAM: 561 sc->fc->it[sub]->flag &= ~0xff; 562 sc->fc->it[sub]->flag |= (0x3f & ichreq->ch); 563 sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6); 564 err = 0; 565 break; 566 case FW_GTSTREAM: 567 ichreq->ch = sc->fc->it[sub]->flag & 0x3f; 568 ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3; 569 err = 0; 570 break; 571 case FW_SRSTREAM: 572 sc->fc->ir[sub]->flag &= ~0xff; 573 sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch); 574 sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6); 575 err = sc->fc->irx_enable(sc->fc, sub); 576 break; 577 case FW_GRSTREAM: 578 ichreq->ch = sc->fc->ir[sub]->flag & 0x3f; 579 ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3; 580 err = 0; 581 break; 582 #ifdef FWXFERQ_DV 583 case FW_SSTDV: 584 ibufreq = (struct fw_isobufreq *) 585 malloc(sizeof(struct fw_isobufreq), M_FW, M_NOWAIT); 586 if(ibufreq == NULL){ 587 err = ENOMEM; 588 break; 589 } 590 #if DV_PAL 591 #define FWDVPACKET 300 592 #else 593 #define FWDVPACKET 250 594 #endif 595 #define FWDVPMAX 512 596 ibufreq->rx.nchunk = 8; 597 ibufreq->rx.npacket = 50; 598 ibufreq->rx.psize = FWDVPMAX; 599 600 ibufreq->tx.nchunk = 5; 601 ibufreq->tx.npacket = FWDVPACKET + 30; /* > 320 or 267 */ 602 ibufreq->tx.psize = FWDVPMAX; 603 604 err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td); 605 sc->fc->it[sub]->dvpacket = FWDVPACKET; 606 free(ibufreq, M_FW); 607 /* reserve a buffer space */ 608 #define NDVCHUNK 8 609 sc->fc->it[sub]->dvproc = NULL; 610 sc->fc->it[sub]->dvdma = NULL; 611 sc->fc->it[sub]->flag |= FWXFERQ_DV; 612 /* XXX check malloc failure */ 613 sc->fc->it[sub]->dvbuf 614 = (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_FW, M_NOWAIT); 615 STAILQ_INIT(&sc->fc->it[sub]->dvvalid); 616 STAILQ_INIT(&sc->fc->it[sub]->dvfree); 617 for( i = 0 ; i < NDVCHUNK ; i++){ 618 /* XXX check malloc failure */ 619 sc->fc->it[sub]->dvbuf[i].buf 620 = malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_FW, M_NOWAIT); 621 STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree, 622 &sc->fc->it[sub]->dvbuf[i], link); 623 } 624 break; 625 #endif 626 case FW_SSTBUF: 627 ir = sc->fc->ir[sub]; 628 it = sc->fc->it[sub]; 629 630 if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){ 631 return(EBUSY); 632 } 633 if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){ 634 return(EBUSY); 635 } 636 if((ibufreq->rx.nchunk * 637 ibufreq->rx.psize * ibufreq->rx.npacket) + 638 (ibufreq->tx.nchunk * 639 ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){ 640 return(EINVAL); 641 } 642 if(ibufreq->rx.nchunk > FWSTMAXCHUNK || 643 ibufreq->tx.nchunk > FWSTMAXCHUNK){ 644 return(EINVAL); 645 } 646 ir->bulkxfer 647 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, 0); 648 if(ir->bulkxfer == NULL){ 649 return(ENOMEM); 650 } 651 it->bulkxfer 652 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, 0); 653 if(it->bulkxfer == NULL){ 654 return(ENOMEM); 655 } 656 ir->buf = malloc( 657 ibufreq->rx.nchunk * ibufreq->rx.npacket 658 /* XXX psize must be 2^n and less or 659 equal to PAGE_SIZE */ 660 * ((ibufreq->rx.psize + 3) &~3), 661 M_FW, 0); 662 if(ir->buf == NULL){ 663 free(ir->bulkxfer, M_FW); 664 free(it->bulkxfer, M_FW); 665 ir->bulkxfer = NULL; 666 it->bulkxfer = NULL; 667 it->buf = NULL; 668 return(ENOMEM); 669 } 670 it->buf = malloc( 671 ibufreq->tx.nchunk * ibufreq->tx.npacket 672 /* XXX psize must be 2^n and less or 673 equal to PAGE_SIZE */ 674 * ((ibufreq->tx.psize + 3) &~3), 675 M_FW, 0); 676 if(it->buf == NULL){ 677 free(ir->bulkxfer, M_FW); 678 free(it->bulkxfer, M_FW); 679 free(ir->buf, M_FW); 680 ir->bulkxfer = NULL; 681 it->bulkxfer = NULL; 682 it->buf = NULL; 683 return(ENOMEM); 684 } 685 686 ir->bnchunk = ibufreq->rx.nchunk; 687 ir->bnpacket = ibufreq->rx.npacket; 688 ir->psize = (ibufreq->rx.psize + 3) & ~3; 689 ir->queued = 0; 690 691 it->bnchunk = ibufreq->tx.nchunk; 692 it->bnpacket = ibufreq->tx.npacket; 693 it->psize = (ibufreq->tx.psize + 3) & ~3; 694 it->queued = 0; 695 696 #ifdef FWXFERQ_DV 697 it->dvdbc = 0; 698 it->dvdiff = 0; 699 it->dvsync = 0; 700 it->dvoffset = 0; 701 #endif 702 703 STAILQ_INIT(&ir->stvalid); 704 STAILQ_INIT(&ir->stfree); 705 STAILQ_INIT(&ir->stdma); 706 ir->stproc = NULL; 707 708 STAILQ_INIT(&it->stvalid); 709 STAILQ_INIT(&it->stfree); 710 STAILQ_INIT(&it->stdma); 711 it->stproc = NULL; 712 713 for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){ 714 ir->bulkxfer[i].buf = 715 ir->buf + i * ir->bnpacket * ir->psize; 716 STAILQ_INSERT_TAIL(&ir->stfree, 717 &ir->bulkxfer[i], link); 718 ir->bulkxfer[i].npacket = ir->bnpacket; 719 } 720 for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){ 721 it->bulkxfer[i].buf = 722 it->buf + i * it->bnpacket * it->psize; 723 STAILQ_INSERT_TAIL(&it->stfree, 724 &it->bulkxfer[i], link); 725 it->bulkxfer[i].npacket = it->bnpacket; 726 } 727 ir->flag &= ~FWXFERQ_MODEMASK; 728 ir->flag |= FWXFERQ_STREAM; 729 ir->flag |= FWXFERQ_EXTBUF; 730 731 it->flag &= ~FWXFERQ_MODEMASK; 732 it->flag |= FWXFERQ_STREAM; 733 it->flag |= FWXFERQ_EXTBUF; 734 err = 0; 735 break; 736 case FW_GSTBUF: 737 ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk; 738 ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket; 739 ibufreq->rx.psize = sc->fc->ir[sub]->psize; 740 741 ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk; 742 ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket; 743 ibufreq->tx.psize = sc->fc->it[sub]->psize; 744 break; 745 case FW_ASYREQ: 746 xfer = fw_xfer_alloc(M_FWXFER); 747 if(xfer == NULL){ 748 err = ENOMEM; 749 return err; 750 } 751 fp = &asyreq->pkt; 752 switch (asyreq->req.type) { 753 case FWASREQNODE: 754 xfer->dst = ntohs(fp->mode.hdr.dst); 755 break; 756 case FWASREQEUI: 757 fwdev = fw_noderesolve_eui64(sc->fc, 758 &asyreq->req.dst.eui); 759 if (fwdev == NULL) { 760 device_printf(sc->fc->bdev, 761 "cannot find node\n"); 762 err = EINVAL; 763 goto error; 764 } 765 xfer->dst = fwdev->dst; 766 fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst); 767 break; 768 case FWASRESTL: 769 /* XXX what's this? */ 770 break; 771 case FWASREQSTREAM: 772 /* nothing to do */ 773 break; 774 } 775 xfer->spd = asyreq->req.sped; 776 xfer->send.len = asyreq->req.len; 777 xfer->send.buf = malloc(xfer->send.len, M_FW, M_NOWAIT); 778 if(xfer->send.buf == NULL){ 779 return ENOMEM; 780 } 781 xfer->send.off = 0; 782 bcopy(fp, xfer->send.buf, xfer->send.len); 783 xfer->act.hand = fw_asy_callback; 784 err = fw_asyreq(sc->fc, sub, xfer); 785 if(err){ 786 fw_xfer_free( xfer); 787 return err; 788 } 789 err = tsleep(xfer, FWPRI, "asyreq", hz); 790 if(err == 0){ 791 if(asyreq->req.len >= xfer->recv.len){ 792 asyreq->req.len = xfer->recv.len; 793 }else{ 794 err = EINVAL; 795 } 796 bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len); 797 } 798 error: 799 fw_xfer_free( xfer); 800 break; 801 case FW_IBUSRST: 802 sc->fc->ibr(sc->fc); 803 break; 804 case FW_CBINDADDR: 805 fwb = fw_bindlookup(sc->fc, 806 bindreq->start.hi, bindreq->start.lo); 807 if(fwb == NULL){ 808 err = EINVAL; 809 break; 810 } 811 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 812 STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist); 813 free(fwb, M_FW); 814 break; 815 case FW_SBINDADDR: 816 if(bindreq->len <= 0 ){ 817 err = EINVAL; 818 break; 819 } 820 if(bindreq->start.hi > 0xffff ){ 821 err = EINVAL; 822 break; 823 } 824 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); 825 if(fwb == NULL){ 826 err = ENOMEM; 827 break; 828 } 829 fwb->start_hi = bindreq->start.hi; 830 fwb->start_lo = bindreq->start.lo; 831 fwb->addrlen = bindreq->len; 832 833 xfer = fw_xfer_alloc(M_FWXFER); 834 if(xfer == NULL){ 835 err = ENOMEM; 836 return err; 837 } 838 xfer->act_type = FWACT_CH; 839 xfer->sub = sub; 840 xfer->fc = sc->fc; 841 842 fwb->xfer = xfer; 843 err = fw_bindadd(sc->fc, fwb); 844 break; 845 case FW_GDEVLST: 846 i = len = 1; 847 /* myself */ 848 devinfo = &fwdevlst->dev[0]; 849 devinfo->dst = sc->fc->nodeid; 850 devinfo->status = 0; /* XXX */ 851 devinfo->eui.hi = sc->fc->eui.hi; 852 devinfo->eui.lo = sc->fc->eui.lo; 853 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) { 854 if(len < FW_MAX_DEVLST){ 855 devinfo = &fwdevlst->dev[len++]; 856 devinfo->dst = fwdev->dst; 857 devinfo->status = 858 (fwdev->status == FWDEVINVAL)?0:1; 859 devinfo->eui.hi = fwdev->eui.hi; 860 devinfo->eui.lo = fwdev->eui.lo; 861 } 862 i++; 863 } 864 fwdevlst->n = i; 865 fwdevlst->info_len = len; 866 break; 867 case FW_GTPMAP: 868 bcopy(sc->fc->topology_map, data, 869 (sc->fc->topology_map->crc_len + 1) * 4); 870 break; 871 case FW_GCROM: 872 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) 873 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 874 break; 875 if (fwdev == NULL) { 876 err = FWNODE_INVAL; 877 break; 878 } 879 #if 0 880 if (fwdev->csrrom[0] >> 24 == 1) 881 len = 4; 882 else 883 len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4; 884 #else 885 if (fwdev->rommax < CSRROMOFF) 886 len = 0; 887 else 888 len = fwdev->rommax - CSRROMOFF + 4; 889 #endif 890 if (crom_buf->len < len) 891 len = crom_buf->len; 892 else 893 crom_buf->len = len; 894 err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len); 895 break; 896 default: 897 sc->fc->ioctl (dev, cmd, data, flag, td); 898 break; 899 } 900 return err; 901 } 902 int 903 fw_poll(dev_t dev, int events, fw_proc *td) 904 { 905 int revents; 906 int tmp; 907 int unit = DEV2UNIT(dev); 908 int sub = DEV2DMACH(dev); 909 struct firewire_softc *sc; 910 911 if (DEV_FWMEM(dev)) 912 return fwmem_poll(dev, events, td); 913 914 sc = devclass_get_softc(firewire_devclass, unit); 915 revents = 0; 916 tmp = POLLIN | POLLRDNORM; 917 if (events & tmp) { 918 if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL) 919 revents |= tmp; 920 else 921 selrecord(td, &sc->fc->ir[sub]->rsel); 922 } 923 tmp = POLLOUT | POLLWRNORM; 924 if (events & tmp) { 925 /* XXX should be fixed */ 926 revents |= tmp; 927 } 928 929 return revents; 930 } 931 932 static int 933 #if __FreeBSD_version < 500000 934 fw_mmap (dev_t dev, vm_offset_t offset, int nproto) 935 #else 936 fw_mmap (dev_t dev, vm_offset_t offset, vm_offset_t *paddr, int nproto) 937 #endif 938 { 939 struct firewire_softc *fc; 940 int unit = DEV2UNIT(dev); 941 942 if (DEV_FWMEM(dev)) 943 #if __FreeBSD_version < 500000 944 return fwmem_mmap(dev, offset, nproto); 945 #else 946 return fwmem_mmap(dev, offset, paddr, nproto); 947 #endif 948 949 fc = devclass_get_softc(firewire_devclass, unit); 950 951 return EINVAL; 952 } 953