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