fwdev.c revision 106813
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 106813 2002-11-12 15:22: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 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 fp = (struct fw_pkt *)(it->stproc->buf + it->queued * it->psize); 387 fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t)); 388 err = uiomove(it->stproc->buf + it->queued * it->psize, 389 uio->uio_resid, uio); 390 it->queued ++; 391 if(it->queued >= it->btpacket){ 392 s = splfw(); 393 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 394 splx(s); 395 it->stproc = NULL; 396 fw_tbuf_update(sc->fc, sub, 0); 397 err = sc->fc->itx_enable(sc->fc, sub); 398 } 399 return err; 400 } if(xferq == NULL && it->flag & FWXFERQ_DV){ 401dvloop: 402 if(it->dvproc == NULL){ 403 it->dvproc = STAILQ_FIRST(&it->dvfree); 404 if(it->dvproc != NULL){ 405 s = splfw(); 406 STAILQ_REMOVE_HEAD(&it->dvfree, link); 407 splx(s); 408 it->dvptr = 0; 409 }else if(slept == 0){ 410 slept = 1; 411 err = sc->fc->itx_enable(sc->fc, sub); 412 if(err){ 413 return err; 414 } 415 err = tsleep((caddr_t)it, FWPRI, "fw_write", hz); 416 if(err){ 417 return err; 418 } 419 goto dvloop; 420 }else{ 421 err = EIO; 422 return err; 423 } 424 } 425 fp = (struct fw_pkt *)(it->dvproc->buf + it->queued * it->psize); 426 fp->mode.stream.len = htons(uio->uio_resid - sizeof(u_int32_t)); 427 err = uiomove(it->dvproc->buf + it->dvptr, 428 uio->uio_resid, uio); 429 it->dvptr += it->psize; 430 if(err){ 431 return err; 432 } 433 if(it->dvptr >= it->psize * it->dvpacket){ 434 s = splfw(); 435 STAILQ_INSERT_TAIL(&it->dvvalid, it->dvproc, link); 436 splx(s); 437 it->dvproc = NULL; 438 err = fw_tbuf_update(sc->fc, sub, 0); 439 if(err){ 440 return err; 441 } 442 err = sc->fc->itx_enable(sc->fc, sub); 443 } 444 return err; 445 } 446 if(xferq != NULL){ 447 xfer = fw_xfer_alloc(); 448 if(xfer == NULL){ 449 err = ENOMEM; 450 return err; 451 } 452 xfer->send.buf = malloc(uio->uio_resid, M_DEVBUF, M_NOWAIT); 453 if(xfer->send.buf == NULL){ 454 fw_xfer_free( xfer); 455 err = ENOBUFS; 456 return err; 457 } 458 xfer->dst = ntohs(fp->mode.hdr.dst); 459#if 0 460 switch(fp->mode.common.tcode){ 461 case FWTCODE_WREQQ: 462 case FWTCODE_WREQB: 463 if((tl = fw_get_tlabel(fc, xfer)) == -1 ){ 464 fw_xfer_free( xfer); 465 err = EAGAIN; 466 return err; 467 } 468 fp->mode.hdr.tlrt = tl << 2; 469 default: 470 break; 471 } 472 473 xfer->tl = fp->mode.hdr.tlrt >> 2; 474 xfer->tcode = fp->mode.common.tcode; 475 xfer->fc = fc; 476 xfer->q = xferq; 477 xfer->act_type = FWACT_XFER; 478 xfer->retry_req = fw_asybusy; 479#endif 480 xfer->send.len = uio->uio_resid; 481 xfer->send.off = 0; 482 xfer->spd = 0;/* XXX: how to setup it */ 483 xfer->act.hand = fw_asy_callback; 484 485 err = uiomove(xfer->send.buf, uio->uio_resid, uio); 486 if(err){ 487 fw_xfer_free( xfer); 488 return err; 489 } 490#if 0 491 fw_asystart(xfer); 492#else 493 fw_asyreq(fc, -1, xfer); 494#endif 495 err = tsleep((caddr_t)xfer, FWPRI, "fw_write", hz); 496 if(xfer->resp == EBUSY) 497 return EBUSY; 498 fw_xfer_free( xfer); 499 return err; 500 } 501 return EINVAL; 502} 503 504/* 505 * ioctl support. 506 */ 507int 508fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 509{ 510 struct firewire_softc *sc; 511 int unit = DEV2UNIT(dev); 512 int sub = DEV2DMACH(dev); 513 int i, len, err = 0; 514 struct fw_device *fwdev; 515 struct fw_bind *fwb; 516 struct fw_xferq *ir, *it; 517 struct fw_xfer *xfer; 518 struct fw_pkt *fp; 519 520 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 521 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 522 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 523 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 524 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 525#if 0 526 struct fw_map_buf *map_buf = (struct fw_map_buf *)data; 527#endif 528 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 529 530 if (DEV_FWMEM(dev)) 531 return fwmem_ioctl(dev, cmd, data, flag, td); 532 533 sc = devclass_get_softc(firewire_devclass, unit); 534 if (!data) 535 return(EINVAL); 536 537 switch (cmd) { 538 case FW_STSTREAM: 539 sc->fc->it[sub]->flag &= ~0xff; 540 sc->fc->it[sub]->flag |= (0x3f & ichreq->ch); 541 sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6); 542 err = 0; 543 break; 544 case FW_GTSTREAM: 545 ichreq->ch = sc->fc->it[sub]->flag & 0x3f; 546 ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3; 547 err = 0; 548 break; 549 case FW_SRSTREAM: 550 sc->fc->ir[sub]->flag &= ~0xff; 551 sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch); 552 sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6); 553 err = sc->fc->irx_enable(sc->fc, sub); 554 break; 555 case FW_GRSTREAM: 556 ichreq->ch = sc->fc->ir[sub]->flag & 0x3f; 557 ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3; 558 err = 0; 559 break; 560 case FW_SSTDV: 561 ibufreq = (struct fw_isobufreq *) 562 malloc(sizeof(struct fw_isobufreq), M_DEVBUF, M_NOWAIT); 563 if(ibufreq == NULL){ 564 err = ENOMEM; 565 break; 566 } 567#define FWDVPACKET 250 568#define FWDVPMAX 512 569 ibufreq->rx.nchunk = 8; 570 ibufreq->rx.npacket = 50; 571 ibufreq->rx.psize = FWDVPMAX; 572 573 ibufreq->tx.nchunk = 5; 574 ibufreq->tx.npacket = 300; 575 ibufreq->tx.psize = FWDVPMAX; 576 577 err = fw_ioctl(dev, FW_SSTBUF, (caddr_t)ibufreq, flag, td); 578 sc->fc->it[sub]->dvpacket = FWDVPACKET; 579 free(ibufreq, M_DEVBUF); 580/* reserve a buffer space */ 581#define NDVCHUNK 8 582 sc->fc->it[sub]->dvproc = NULL; 583 sc->fc->it[sub]->dvdma = NULL; 584 sc->fc->it[sub]->flag |= FWXFERQ_DV; 585 sc->fc->it[sub]->dvbuf 586 = (struct fw_dvbuf *)malloc(sizeof(struct fw_dvbuf) * NDVCHUNK, M_DEVBUF, M_DONTWAIT); 587 STAILQ_INIT(&sc->fc->it[sub]->dvvalid); 588 STAILQ_INIT(&sc->fc->it[sub]->dvfree); 589 for( i = 0 ; i < NDVCHUNK ; i++){ 590 sc->fc->it[sub]->dvbuf[i].buf 591 = malloc(FWDVPMAX * sc->fc->it[sub]->dvpacket, M_DEVBUF, M_DONTWAIT); 592 STAILQ_INSERT_TAIL(&sc->fc->it[sub]->dvfree, 593 &sc->fc->it[sub]->dvbuf[i], link); 594 } 595 break; 596 case FW_SSTBUF: 597 ir = sc->fc->ir[sub]; 598 it = sc->fc->it[sub]; 599 600 if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){ 601 return(EBUSY); 602 } 603 if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){ 604 return(EBUSY); 605 } 606 if((ibufreq->rx.nchunk * 607 ibufreq->rx.psize * ibufreq->rx.npacket) + 608 (ibufreq->tx.nchunk * 609 ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){ 610 return(EINVAL); 611 } 612 if(ibufreq->rx.nchunk > FWSTMAXCHUNK || 613 ibufreq->tx.nchunk > FWSTMAXCHUNK){ 614 return(EINVAL); 615 } 616 ir->bulkxfer 617 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_DEVBUF, M_DONTWAIT); 618 if(ir->bulkxfer == NULL){ 619 return(ENOMEM); 620 } 621 it->bulkxfer 622 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_DEVBUF, M_DONTWAIT); 623 if(it->bulkxfer == NULL){ 624 return(ENOMEM); 625 } 626 ir->buf = malloc( 627 ibufreq->rx.nchunk * ibufreq->rx.npacket 628 * ((ibufreq->rx.psize + 3) &~3), 629 M_DEVBUF, M_DONTWAIT); 630 if(ir->buf == NULL){ 631 free(ir->bulkxfer, M_DEVBUF); 632 free(it->bulkxfer, M_DEVBUF); 633 ir->bulkxfer = NULL; 634 it->bulkxfer = NULL; 635 it->buf = NULL; 636 return(ENOMEM); 637 } 638 it->buf = malloc( 639 ibufreq->tx.nchunk * ibufreq->tx.npacket 640 * ((ibufreq->tx.psize + 3) &~3), 641 M_DEVBUF, M_DONTWAIT); 642 if(it->buf == NULL){ 643 free(ir->bulkxfer, M_DEVBUF); 644 free(it->bulkxfer, M_DEVBUF); 645 free(ir->buf, M_DEVBUF); 646 ir->bulkxfer = NULL; 647 it->bulkxfer = NULL; 648 it->buf = NULL; 649 return(ENOMEM); 650 } 651 652 ir->bnchunk = ibufreq->rx.nchunk; 653 ir->bnpacket = ibufreq->rx.npacket; 654 ir->btpacket = ibufreq->rx.npacket; 655 ir->psize = (ibufreq->rx.psize + 3) & ~3; 656 ir->queued = 0; 657 658 it->bnchunk = ibufreq->tx.nchunk; 659 it->bnpacket = ibufreq->tx.npacket; 660 it->btpacket = ibufreq->tx.npacket; 661 it->psize = (ibufreq->tx.psize + 3) & ~3; 662 ir->queued = 0; 663 it->dvdbc = 0; 664 it->dvdiff = 0; 665 it->dvsync = 0; 666 667 STAILQ_INIT(&ir->stvalid); 668 STAILQ_INIT(&ir->stfree); 669 ir->stdma = NULL; 670 ir->stdma2 = NULL; 671 ir->stproc = NULL; 672 673 STAILQ_INIT(&it->stvalid); 674 STAILQ_INIT(&it->stfree); 675 it->stdma = NULL; 676 it->stdma2 = NULL; 677 it->stproc = NULL; 678 679 for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){ 680 ir->bulkxfer[i].buf = 681 ir->buf + 682 i * sc->fc->ir[sub]->bnpacket * 683 sc->fc->ir[sub]->psize; 684 ir->bulkxfer[i].flag = 0; 685 STAILQ_INSERT_TAIL(&ir->stfree, 686 &ir->bulkxfer[i], link); 687 ir->bulkxfer[i].npacket = ir->bnpacket; 688 } 689 for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){ 690 it->bulkxfer[i].buf = 691 it->buf + 692 i * sc->fc->it[sub]->bnpacket * 693 sc->fc->it[sub]->psize; 694 it->bulkxfer[i].flag = 0; 695 STAILQ_INSERT_TAIL(&it->stfree, 696 &it->bulkxfer[i], link); 697 it->bulkxfer[i].npacket = it->bnpacket; 698 } 699 ir->flag &= ~FWXFERQ_MODEMASK; 700 ir->flag |= FWXFERQ_STREAM; 701 ir->flag |= FWXFERQ_EXTBUF; 702 703 it->flag &= ~FWXFERQ_MODEMASK; 704 it->flag |= FWXFERQ_STREAM; 705 it->flag |= FWXFERQ_EXTBUF; 706 err = 0; 707 break; 708 case FW_GSTBUF: 709 ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk; 710 ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket; 711 ibufreq->rx.psize = sc->fc->ir[sub]->psize; 712 713 ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk; 714 ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket; 715 ibufreq->tx.psize = sc->fc->it[sub]->psize; 716 break; 717 case FW_ASYREQ: 718 xfer = fw_xfer_alloc(); 719 if(xfer == NULL){ 720 err = ENOMEM; 721 return err; 722 } 723 fp = &asyreq->pkt; 724 switch (asyreq->req.type) { 725 case FWASREQNODE: 726 xfer->dst = ntohs(fp->mode.hdr.dst); 727 break; 728 case FWASREQEUI: 729 fwdev = fw_noderesolve(sc->fc, asyreq->req.dst.eui); 730 if (fwdev == NULL) { 731 printf("%s:cannot found node\n", 732 device_get_nameunit(sc->fc->dev)); 733 err = EINVAL; 734 goto error; 735 } 736 xfer->dst = fwdev->dst; 737 fp->mode.hdr.dst = htons(FWLOCALBUS | xfer->dst); 738 break; 739 case FWASRESTL: 740 /* XXX what's this? */ 741 break; 742 case FWASREQSTREAM: 743 /* nothing to do */ 744 break; 745 } 746 xfer->spd = asyreq->req.sped; 747 xfer->send.len = asyreq->req.len; 748 xfer->send.buf = malloc(xfer->send.len, M_DEVBUF, M_NOWAIT); 749 if(xfer->send.buf == NULL){ 750 return ENOMEM; 751 } 752 xfer->send.off = 0; 753 bcopy(fp, xfer->send.buf, xfer->send.len); 754 xfer->act.hand = fw_asy_callback; 755 err = fw_asyreq(sc->fc, sub, xfer); 756 if(err){ 757 fw_xfer_free( xfer); 758 return err; 759 } 760 err = tsleep((caddr_t)xfer, FWPRI, "asyreq", hz); 761 if(err == 0){ 762 if(asyreq->req.len >= xfer->recv.len){ 763 asyreq->req.len = xfer->recv.len; 764 }else{ 765 err = EINVAL; 766 } 767 bcopy(xfer->recv.buf + xfer->recv.off, fp, asyreq->req.len); 768 } 769error: 770 fw_xfer_free( xfer); 771 break; 772 case FW_IBUSRST: 773 sc->fc->ibr(sc->fc); 774 break; 775 case FW_CBINDADDR: 776 fwb = fw_bindlookup(sc->fc, 777 bindreq->start.hi, bindreq->start.lo); 778 if(fwb == NULL){ 779 err = EINVAL; 780 break; 781 } 782 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 783 STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist); 784 free(fwb, M_DEVBUF); 785 break; 786 case FW_SBINDADDR: 787 if(bindreq->len <= 0 ){ 788 err = EINVAL; 789 break; 790 } 791 if(bindreq->start.hi > 0xffff ){ 792 err = EINVAL; 793 break; 794 } 795 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_DEVBUF, M_DONTWAIT); 796 if(fwb == NULL){ 797 err = ENOMEM; 798 break; 799 } 800 fwb->start_hi = bindreq->start.hi; 801 fwb->start_lo = bindreq->start.lo; 802 fwb->addrlen = bindreq->len; 803 804 xfer = fw_xfer_alloc(); 805 if(xfer == NULL){ 806 err = ENOMEM; 807 return err; 808 } 809 xfer->act_type = FWACT_CH; 810 xfer->sub = sub; 811 xfer->fc = sc->fc; 812 813 fwb->xfer = xfer; 814 err = fw_bindadd(sc->fc, fwb); 815 break; 816 case FW_GDEVLST: 817 i = 0; 818 for(fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL; 819 fwdev = TAILQ_NEXT(fwdev, link)){ 820 if(i < fwdevlst->n){ 821 fwdevlst->dst[i] = fwdev->dst; 822 fwdevlst->status[i] = 823 (fwdev->status == FWDEVATTACHED)?1:0; 824 fwdevlst->eui[i].hi = fwdev->eui.hi; 825 fwdevlst->eui[i].lo = fwdev->eui.lo; 826 } 827 i++; 828 } 829 fwdevlst->n = i; 830 break; 831 case FW_GTPMAP: 832 bcopy(sc->fc->topology_map, data, 833 (sc->fc->topology_map->crc_len + 1) * 4); 834 break; 835 case FW_GSPMAP: 836 /* speed_map is larger than a page */ 837 err = copyout(sc->fc->speed_map, *(void **)data, 838 (sc->fc->speed_map->crc_len + 1) * 4); 839 break; 840 case FW_GCROM: 841 for (fwdev = TAILQ_FIRST(&sc->fc->devices); fwdev != NULL; 842 fwdev = TAILQ_NEXT(fwdev, link)) { 843 if (fwdev->eui.hi == crom_buf->eui.hi && 844 fwdev->eui.lo == crom_buf->eui.lo) 845 break; 846 } 847 if (fwdev == NULL) { 848 err = FWNODE_INVAL; 849 break; 850 } 851#if 0 852 if (fwdev->csrrom[0] >> 24 == 1) 853 len = 4; 854 else 855 len = (1 + ((fwdev->csrrom[0] >> 16) & 0xff)) * 4; 856#else 857 if (fwdev->rommax < CSRROMOFF) 858 len = 0; 859 else 860 len = fwdev->rommax - CSRROMOFF + 4; 861#endif 862 if (crom_buf->len < len) 863 len = crom_buf->len; 864 else 865 crom_buf->len = len; 866 err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len); 867 break; 868 default: 869 sc->fc->ioctl (dev, cmd, data, flag, td); 870 break; 871 } 872 return err; 873} 874int 875fw_poll(dev_t dev, int events, fw_proc *td) 876{ 877 int revents; 878 int tmp; 879 int unit = DEV2UNIT(dev); 880 int sub = DEV2DMACH(dev); 881 struct firewire_softc *sc; 882 883 if (DEV_FWMEM(dev)) 884 return fwmem_poll(dev, events, td); 885 886 sc = devclass_get_softc(firewire_devclass, unit); 887 revents = 0; 888 tmp = POLLIN | POLLRDNORM; 889 if (events & tmp) { 890 if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL) 891 revents |= tmp; 892 else 893 selrecord(td, &sc->fc->ir[sub]->rsel); 894 } 895 tmp = POLLOUT | POLLWRNORM; 896 if (events & tmp) { 897 /* XXX should be fixed */ 898 revents |= tmp; 899 } 900 901 return revents; 902} 903 904static int 905fw_mmap (dev_t dev, vm_offset_t offset, int nproto) 906{ 907 struct firewire_softc *fc; 908 int unit = DEV2UNIT(dev); 909 910 if (DEV_FWMEM(dev)) 911 return fwmem_mmap(dev, offset, nproto); 912 913 fc = devclass_get_softc(firewire_devclass, unit); 914 915 return EINVAL; 916} 917