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