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