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