fwdev.c revision 109814
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 109814 2003-01-25 14:47:33Z 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 struct fw_devinfo *devinfo; 535 536 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 537 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 538 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 539 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 540 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 541 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 542 543 if (DEV_FWMEM(dev)) 544 return fwmem_ioctl(dev, cmd, data, flag, td); 545 546 sc = devclass_get_softc(firewire_devclass, unit); 547 if (!data) 548 return(EINVAL); 549 550 switch (cmd) { 551 case FW_STSTREAM: 552 sc->fc->it[sub]->flag &= ~0xff; 553 sc->fc->it[sub]->flag |= (0x3f & ichreq->ch); 554 sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6); 555 err = 0; 556 break; 557 case FW_GTSTREAM: 558 ichreq->ch = sc->fc->it[sub]->flag & 0x3f; 559 ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3; 560 err = 0; 561 break; 562 case FW_SRSTREAM: 563 sc->fc->ir[sub]->flag &= ~0xff; 564 sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch); 565 sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6); 566 err = sc->fc->irx_enable(sc->fc, sub); 567 break; 568 case FW_GRSTREAM: 569 ichreq->ch = sc->fc->ir[sub]->flag & 0x3f; 570 ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3; 571 err = 0; 572 break; 573#ifdef FWXFERQ_DV 574 case FW_SSTDV: 575 ibufreq = (struct fw_isobufreq *) 576 malloc(sizeof(struct fw_isobufreq), M_DEVBUF, M_NOWAIT); 577 if(ibufreq == NULL){ 578 err = ENOMEM; 579 break; 580 } 581#if DV_PAL 582#define FWDVPACKET 300 583#else 584#define FWDVPACKET 250 585#endif 586#define FWDVPMAX 512 587 ibufreq->rx.nchunk = 8; 588 ibufreq->rx.npacket = 50; 589 ibufreq->rx.psize = FWDVPMAX; 590 591 ibufreq->tx.nchunk = 5; 592 ibufreq->tx.npacket = FWDVPACKET + 30; /* > 320 or 267 */ 593 ibufreq->tx.psize = FWDVPMAX; 594 595 err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td); 596 sc->fc->it[sub]->dvpacket = FWDVPACKET; 597 free(ibufreq, M_DEVBUF); 598/* reserve a buffer space */ 599#define NDVCHUNK 8 600 sc->fc->it[sub]->dvproc = NULL; 601 sc->fc->it[sub]->dvdma = NULL; 602 sc->fc->it[sub]->flag |= FWXFERQ_DV; 603 /* XXX check malloc failure */ 604 sc->fc->it[sub]->dvbuf 605 = (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_DEVBUF, M_NOWAIT); 606 STAILQ_INIT(&sc->fc->it[sub]->dvvalid); 607 STAILQ_INIT(&sc->fc->it[sub]->dvfree); 608 for( i = 0 ; i < NDVCHUNK ; i++){ 609 /* XXX check malloc failure */ 610 sc->fc->it[sub]->dvbuf[i].buf 611 = malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_DEVBUF, M_NOWAIT); 612 STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree, 613 &sc->fc->it[sub]->dvbuf[i], link); 614 } 615 break; 616#endif 617 case FW_SSTBUF: 618 ir = sc->fc->ir[sub]; 619 it = sc->fc->it[sub]; 620 621 if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){ 622 return(EBUSY); 623 } 624 if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){ 625 return(EBUSY); 626 } 627 if((ibufreq->rx.nchunk * 628 ibufreq->rx.psize * ibufreq->rx.npacket) + 629 (ibufreq->tx.nchunk * 630 ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){ 631 return(EINVAL); 632 } 633 if(ibufreq->rx.nchunk > FWSTMAXCHUNK || 634 ibufreq->tx.nchunk > FWSTMAXCHUNK){ 635 return(EINVAL); 636 } 637 ir->bulkxfer 638 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_DEVBUF, M_NOWAIT); 639 if(ir->bulkxfer == NULL){ 640 return(ENOMEM); 641 } 642 it->bulkxfer 643 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_DEVBUF, M_NOWAIT); 644 if(it->bulkxfer == NULL){ 645 return(ENOMEM); 646 } 647 ir->buf = malloc( 648 ibufreq->rx.nchunk * ibufreq->rx.npacket 649 /* XXX psize must be 2^n and less or 650 equal to PAGE_SIZE */ 651 * ((ibufreq->rx.psize + 3) &~3), 652 M_DEVBUF, M_NOWAIT); 653 if(ir->buf == NULL){ 654 free(ir->bulkxfer, M_DEVBUF); 655 free(it->bulkxfer, M_DEVBUF); 656 ir->bulkxfer = NULL; 657 it->bulkxfer = NULL; 658 it->buf = NULL; 659 return(ENOMEM); 660 } 661 it->buf = malloc( 662 ibufreq->tx.nchunk * ibufreq->tx.npacket 663 /* XXX psize must be 2^n and less or 664 equal to PAGE_SIZE */ 665 * ((ibufreq->tx.psize + 3) &~3), 666 M_DEVBUF, M_NOWAIT); 667 if(it->buf == NULL){ 668 free(ir->bulkxfer, M_DEVBUF); 669 free(it->bulkxfer, M_DEVBUF); 670 free(ir->buf, M_DEVBUF); 671 ir->bulkxfer = NULL; 672 it->bulkxfer = NULL; 673 it->buf = NULL; 674 return(ENOMEM); 675 } 676 677 ir->bnchunk = ibufreq->rx.nchunk; 678 ir->bnpacket = ibufreq->rx.npacket; 679 ir->btpacket = ibufreq->rx.npacket; 680 ir->psize = (ibufreq->rx.psize + 3) & ~3; 681 ir->queued = 0; 682 683 it->bnchunk = ibufreq->tx.nchunk; 684 it->bnpacket = ibufreq->tx.npacket; 685 it->btpacket = ibufreq->tx.npacket; 686 it->psize = (ibufreq->tx.psize + 3) & ~3; 687 ir->queued = 0; 688 it->dvdbc = 0; 689 it->dvdiff = 0; 690 it->dvsync = 0; 691 it->dvoffset = 0; 692 693 STAILQ_INIT(&ir->stvalid); 694 STAILQ_INIT(&ir->stfree); 695 ir->stdma = NULL; 696 ir->stdma2 = NULL; 697 ir->stproc = NULL; 698 699 STAILQ_INIT(&it->stvalid); 700 STAILQ_INIT(&it->stfree); 701 it->stdma = NULL; 702 it->stdma2 = NULL; 703 it->stproc = NULL; 704 705 for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){ 706 ir->bulkxfer[i].buf = 707 ir->buf + 708 i * sc->fc->ir[sub]->bnpacket * 709 sc->fc->ir[sub]->psize; 710 ir->bulkxfer[i].flag = 0; 711 STAILQ_INSERT_TAIL(&ir->stfree, 712 &ir->bulkxfer[i], link); 713 ir->bulkxfer[i].npacket = ir->bnpacket; 714 } 715 for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){ 716 it->bulkxfer[i].buf = 717 it->buf + 718 i * sc->fc->it[sub]->bnpacket * 719 sc->fc->it[sub]->psize; 720 it->bulkxfer[i].flag = 0; 721 STAILQ_INSERT_TAIL(&it->stfree, 722 &it->bulkxfer[i], link); 723 it->bulkxfer[i].npacket = it->bnpacket; 724 } 725 ir->flag &= ~FWXFERQ_MODEMASK; 726 ir->flag |= FWXFERQ_STREAM; 727 ir->flag |= FWXFERQ_EXTBUF; 728 729 it->flag &= ~FWXFERQ_MODEMASK; 730 it->flag |= FWXFERQ_STREAM; 731 it->flag |= FWXFERQ_EXTBUF; 732 err = 0; 733 break; 734 case FW_GSTBUF: 735 ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk; 736 ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket; 737 ibufreq->rx.psize = sc->fc->ir[sub]->psize; 738 739 ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk; 740 ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket; 741 ibufreq->tx.psize = sc->fc->it[sub]->psize; 742 break; 743 case FW_ASYREQ: 744 xfer = fw_xfer_alloc(); 745 if(xfer == NULL){ 746 err = ENOMEM; 747 return err; 748 } 749 fp = &asyreq->pkt; 750 switch (asyreq->req.type) { 751 case FWASREQNODE: 752 xfer->dst = ntohs(fp->mode.hdr.dst); 753 break; 754 case FWASREQEUI: 755 fwdev = fw_noderesolve(sc->fc, asyreq->req.dst.eui); 756 if (fwdev == NULL) { 757 device_printf(sc->fc->bdev, 758 "cannot find node\n"); 759 err = EINVAL; 760 goto error; 761 } 762 xfer->dst = fwdev->dst; 763 fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst); 764 break; 765 case FWASRESTL: 766 /* XXX what's this? */ 767 break; 768 case FWASREQSTREAM: 769 /* nothing to do */ 770 break; 771 } 772 xfer->spd = asyreq->req.sped; 773 xfer->send.len = asyreq->req.len; 774 xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT); 775 if(xfer->send.buf == NULL){ 776 return ENOMEM; 777 } 778 xfer->send.off = 0; 779 bcopy(fp, xfer->send.buf, xfer->send.len); 780 xfer->act.hand = fw_asy_callback; 781 err = fw_asyreq(sc->fc, sub, xfer); 782 if(err){ 783 fw_xfer_free( xfer); 784 return err; 785 } 786 err = tsleep((caddr_t)xfer, FWPRI, "asyreq", hz); 787 if(err == 0){ 788 if(asyreq->req.len >= xfer->recv.len){ 789 asyreq->req.len = xfer->recv.len; 790 }else{ 791 err = EINVAL; 792 } 793 bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len); 794 } 795error: 796 fw_xfer_free( xfer); 797 break; 798 case FW_IBUSRST: 799 sc->fc->ibr(sc->fc); 800 break; 801 case FW_CBINDADDR: 802 fwb = fw_bindlookup(sc->fc, 803 bindreq->start.hi, bindreq->start.lo); 804 if(fwb == NULL){ 805 err = EINVAL; 806 break; 807 } 808 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 809 STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist); 810 free(fwb, M_DEVBUF); 811 break; 812 case FW_SBINDADDR: 813 if(bindreq->len <= 0 ){ 814 err = EINVAL; 815 break; 816 } 817 if(bindreq->start.hi > 0xffff ){ 818 err = EINVAL; 819 break; 820 } 821 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_DEVBUF, M_NOWAIT); 822 if(fwb == NULL){ 823 err = ENOMEM; 824 break; 825 } 826 fwb->start_hi = bindreq->start.hi; 827 fwb->start_lo = bindreq->start.lo; 828 fwb->addrlen = bindreq->len; 829 830 xfer = fw_xfer_alloc(); 831 if(xfer == NULL){ 832 err = ENOMEM; 833 return err; 834 } 835 xfer->act_type = FWACT_CH; 836 xfer->sub = sub; 837 xfer->fc = sc->fc; 838 839 fwb->xfer = xfer; 840 err = fw_bindadd(sc->fc, fwb); 841 break; 842 case FW_GDEVLST: 843 i = len = 1; 844 /* myself */ 845 devinfo = &fwdevlst->dev[0]; 846 devinfo->dst = sc->fc->nodeid; 847 devinfo->status = 0; /* XXX */ 848 devinfo->eui.hi = sc->fc->eui.hi; 849 devinfo->eui.lo = sc->fc->eui.lo; 850 for (fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL; 851 fwdev = TAILQ_NEXT(fwdev, link)) { 852 if(len < FW_MAX_DEVLST){ 853 devinfo = &fwdevlst->dev[len++]; 854 devinfo->dst = fwdev->dst; 855 devinfo->status = 856 (fwdev->status == FWDEVINVAL)?0:1; 857 devinfo->eui.hi = fwdev->eui.hi; 858 devinfo->eui.lo = fwdev->eui.lo; 859 } 860 i++; 861 } 862 fwdevlst->n = i; 863 fwdevlst->info_len = len; 864 break; 865 case FW_GTPMAP: 866 bcopy(sc->fc->topology_map, data, 867 (sc->fc->topology_map->crc_len + 1) * 4); 868 break; 869 case FW_GCROM: 870 for (fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL; 871 fwdev = TAILQ_NEXT(fwdev, link)) { 872 if (fwdev->eui.hi == crom_buf->eui.hi && 873 fwdev->eui.lo == crom_buf->eui.lo) 874 break; 875 } 876 if (fwdev == NULL) { 877 err = FWNODE_INVAL; 878 break; 879 } 880#if 0 881 if (fwdev->csrrom[0] >> 24 == 1) 882 len = 4; 883 else 884 len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4; 885#else 886 if (fwdev->rommax < CSRROMOFF) 887 len = 0; 888 else 889 len = fwdev->rommax - CSRROMOFF + 4; 890#endif 891 if (crom_buf->len < len) 892 len = crom_buf->len; 893 else 894 crom_buf->len = len; 895 err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len); 896 break; 897 default: 898 sc->fc->ioctl (dev, cmd, data, flag, td); 899 break; 900 } 901 return err; 902} 903int 904fw_poll(dev_t dev, int events, fw_proc *td) 905{ 906 int revents; 907 int tmp; 908 int unit = DEV2UNIT(dev); 909 int sub = DEV2DMACH(dev); 910 struct firewire_softc *sc; 911 912 if (DEV_FWMEM(dev)) 913 return fwmem_poll(dev, events, td); 914 915 sc = devclass_get_softc(firewire_devclass, unit); 916 revents = 0; 917 tmp = POLLIN | POLLRDNORM; 918 if (events & tmp) { 919 if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL) 920 revents |= tmp; 921 else 922 selrecord(td, &sc->fc->ir[sub]->rsel); 923 } 924 tmp = POLLOUT | POLLWRNORM; 925 if (events & tmp) { 926 /* XXX should be fixed */ 927 revents |= tmp; 928 } 929 930 return revents; 931} 932 933static int 934fw_mmap (dev_t dev, vm_offset_t offset, int nproto) 935{ 936 struct firewire_softc *fc; 937 int unit = DEV2UNIT(dev); 938 939 if (DEV_FWMEM(dev)) 940 return fwmem_mmap(dev, offset, nproto); 941 942 fc = devclass_get_softc(firewire_devclass, unit); 943 944 return EINVAL; 945} 946