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