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