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