1 /* 2 * Copyright (c) 2003 Hidetoshi Shimokawa 3 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the acknowledgement as bellow: 16 * 17 * This product includes software developed by K. Kobayashi and H. Shimokawa 18 * 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 26 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 28 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 * 34 * $FreeBSD$ 35 * 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/types.h> 41 #include <sys/mbuf.h> 42 43 #include <sys/kernel.h> 44 #include <sys/malloc.h> 45 #include <sys/conf.h> 46 #include <sys/poll.h> 47 48 #include <sys/bus.h> 49 #include <machine/bus.h> 50 51 #include <sys/ioccom.h> 52 53 #include <dev/firewire/firewire.h> 54 #include <dev/firewire/firewirereg.h> 55 #include <dev/firewire/fwdma.h> 56 #include <dev/firewire/fwmem.h> 57 #include <dev/firewire/iec68113.h> 58 59 #define CDEV_MAJOR 127 60 #define FWNODE_INVAL 0xffff 61 62 static d_open_t fw_open; 63 static d_close_t fw_close; 64 static d_ioctl_t fw_ioctl; 65 static d_poll_t fw_poll; 66 static d_read_t fw_read; /* for Isochronous packet */ 67 static d_write_t fw_write; 68 static d_mmap_t fw_mmap; 69 70 struct cdevsw firewire_cdevsw = 71 { 72 #if __FreeBSD_version >= 500104 73 .d_open = fw_open, 74 .d_close = fw_close, 75 .d_read = fw_read, 76 .d_write = fw_write, 77 .d_ioctl = fw_ioctl, 78 .d_poll = fw_poll, 79 .d_mmap = fw_mmap, 80 .d_name = "fw", 81 .d_maj = CDEV_MAJOR, 82 .d_flags = D_MEM 83 #else 84 fw_open, fw_close, fw_read, fw_write, fw_ioctl, 85 fw_poll, fw_mmap, nostrategy, "fw", CDEV_MAJOR, nodump, nopsize, D_MEM 86 #endif 87 }; 88 89 static int 90 fw_open (dev_t dev, int flags, int fmt, fw_proc *td) 91 { 92 struct firewire_softc *sc; 93 int unit = DEV2UNIT(dev); 94 int sub = DEV2DMACH(dev); 95 96 int err = 0; 97 98 if (DEV_FWMEM(dev)) 99 return fwmem_open(dev, flags, fmt, td); 100 101 sc = devclass_get_softc(firewire_devclass, unit); 102 if(sc->fc->ir[sub]->flag & FWXFERQ_OPEN){ 103 err = EBUSY; 104 return err; 105 } 106 if(sc->fc->it[sub]->flag & FWXFERQ_OPEN){ 107 err = EBUSY; 108 return err; 109 } 110 if(sc->fc->ir[sub]->flag & FWXFERQ_MODEMASK){ 111 err = EBUSY; 112 return err; 113 } 114 /* Default is per packet mode */ 115 sc->fc->ir[sub]->flag |= FWXFERQ_OPEN; 116 sc->fc->it[sub]->flag |= FWXFERQ_OPEN; 117 return err; 118 } 119 120 static int 121 fw_close (dev_t dev, int flags, int fmt, fw_proc *td) 122 { 123 struct firewire_softc *sc; 124 int unit = DEV2UNIT(dev); 125 int sub = DEV2DMACH(dev); 126 struct fw_xfer *xfer; 127 struct fw_bind *fwb; 128 int err = 0; 129 130 if (DEV_FWMEM(dev)) 131 return fwmem_close(dev, flags, fmt, td); 132 133 sc = devclass_get_softc(firewire_devclass, unit); 134 if(!(sc->fc->ir[sub]->flag & FWXFERQ_OPEN)){ 135 err = EINVAL; 136 return err; 137 } 138 sc->fc->ir[sub]->flag &= ~FWXFERQ_OPEN; 139 if(!(sc->fc->it[sub]->flag & FWXFERQ_OPEN)){ 140 err = EINVAL; 141 return err; 142 } 143 sc->fc->it[sub]->flag &= ~FWXFERQ_OPEN; 144 145 if(sc->fc->ir[sub]->flag & FWXFERQ_RUNNING){ 146 sc->fc->irx_disable(sc->fc, sub); 147 } 148 if(sc->fc->it[sub]->flag & FWXFERQ_RUNNING){ 149 sc->fc->it[sub]->flag &= ~FWXFERQ_RUNNING; 150 sc->fc->itx_disable(sc->fc, sub); 151 } 152 if(sc->fc->ir[sub]->flag & FWXFERQ_EXTBUF){ 153 if (sc->fc->ir[sub]->buf != NULL) 154 fwdma_free_multiseg(sc->fc->ir[sub]->buf); 155 sc->fc->ir[sub]->buf = NULL; 156 free(sc->fc->ir[sub]->bulkxfer, M_FW); 157 sc->fc->ir[sub]->bulkxfer = NULL; 158 sc->fc->ir[sub]->flag &= ~FWXFERQ_EXTBUF; 159 sc->fc->ir[sub]->psize = PAGE_SIZE; 160 sc->fc->ir[sub]->maxq = FWMAXQUEUE; 161 } 162 if(sc->fc->it[sub]->flag & FWXFERQ_EXTBUF){ 163 if (sc->fc->it[sub]->buf != NULL) 164 fwdma_free_multiseg(sc->fc->it[sub]->buf); 165 sc->fc->it[sub]->buf = NULL; 166 free(sc->fc->it[sub]->bulkxfer, M_FW); 167 sc->fc->it[sub]->bulkxfer = NULL; 168 sc->fc->it[sub]->flag &= ~FWXFERQ_EXTBUF; 169 sc->fc->it[sub]->psize = 0; 170 sc->fc->it[sub]->maxq = FWMAXQUEUE; 171 } 172 for(xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q); 173 xfer != NULL; xfer = STAILQ_FIRST(&sc->fc->ir[sub]->q)){ 174 sc->fc->ir[sub]->queued--; 175 STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->q, link); 176 177 xfer->resp = 0; 178 fw_xfer_done(xfer); 179 } 180 for(fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds); fwb != NULL; 181 fwb = STAILQ_FIRST(&sc->fc->ir[sub]->binds)){ 182 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 183 STAILQ_REMOVE_HEAD(&sc->fc->ir[sub]->binds, chlist); 184 free(fwb, M_FW); 185 } 186 sc->fc->ir[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 187 sc->fc->it[sub]->flag &= ~(FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 188 return err; 189 } 190 191 /* 192 * read request. 193 */ 194 static int 195 fw_read (dev_t dev, struct uio *uio, int ioflag) 196 { 197 struct firewire_softc *sc; 198 struct fw_xferq *ir; 199 struct fw_xfer *xfer; 200 int err = 0, s, slept = 0; 201 int unit = DEV2UNIT(dev); 202 int sub = DEV2DMACH(dev); 203 struct fw_pkt *fp; 204 205 if (DEV_FWMEM(dev)) 206 return fwmem_read(dev, uio, ioflag); 207 208 sc = devclass_get_softc(firewire_devclass, unit); 209 210 ir = sc->fc->ir[sub]; 211 212 readloop: 213 xfer = STAILQ_FIRST(&ir->q); 214 if (ir->stproc == NULL) { 215 /* iso bulkxfer */ 216 ir->stproc = STAILQ_FIRST(&ir->stvalid); 217 if (ir->stproc != NULL) { 218 s = splfw(); 219 STAILQ_REMOVE_HEAD(&ir->stvalid, link); 220 splx(s); 221 ir->queued = 0; 222 } 223 } 224 if (xfer == NULL && ir->stproc == NULL) { 225 /* no data avaliable */ 226 if (slept == 0) { 227 slept = 1; 228 ir->flag |= FWXFERQ_WAKEUP; 229 err = tsleep(ir, FWPRI, "fw_read", hz); 230 ir->flag &= ~FWXFERQ_WAKEUP; 231 if (err == 0) 232 goto readloop; 233 } else if (slept == 1) 234 err = EIO; 235 return err; 236 } else if(xfer != NULL) { 237 /* per packet mode or FWACT_CH bind?*/ 238 s = splfw(); 239 ir->queued --; 240 STAILQ_REMOVE_HEAD(&ir->q, link); 241 splx(s); 242 fp = (struct fw_pkt *)xfer->recv.buf; 243 if(sc->fc->irx_post != NULL) 244 sc->fc->irx_post(sc->fc, fp->mode.ld); 245 err = uiomove(xfer->recv.buf, xfer->recv.len, uio); 246 /* XXX we should recycle this xfer */ 247 fw_xfer_free( xfer); 248 } else if(ir->stproc != NULL) { 249 /* iso bulkxfer */ 250 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 251 ir->stproc->poffset + ir->queued); 252 if(sc->fc->irx_post != NULL) 253 sc->fc->irx_post(sc->fc, fp->mode.ld); 254 if(fp->mode.stream.len == 0){ 255 err = EIO; 256 return err; 257 } 258 err = uiomove((caddr_t)fp, 259 fp->mode.stream.len + sizeof(u_int32_t), uio); 260 ir->queued ++; 261 if(ir->queued >= ir->bnpacket){ 262 s = splfw(); 263 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 264 splx(s); 265 sc->fc->irx_enable(sc->fc, sub); 266 ir->stproc = NULL; 267 } 268 if (uio->uio_resid >= ir->psize) { 269 slept = -1; 270 goto readloop; 271 } 272 } 273 return err; 274 } 275 276 static int 277 fw_write (dev_t dev, struct uio *uio, int ioflag) 278 { 279 int err = 0; 280 struct firewire_softc *sc; 281 int unit = DEV2UNIT(dev); 282 int sub = DEV2DMACH(dev); 283 int s, slept = 0; 284 struct fw_pkt *fp; 285 struct fw_xfer *xfer; 286 struct fw_xferq *xferq; 287 struct firewire_comm *fc; 288 struct fw_xferq *it; 289 290 if (DEV_FWMEM(dev)) 291 return fwmem_write(dev, uio, ioflag); 292 293 sc = devclass_get_softc(firewire_devclass, unit); 294 fc = sc->fc; 295 it = sc->fc->it[sub]; 296 297 xferq = NULL; 298 /* Discard unsent buffered stream packet, when sending Asyrequrst */ 299 if(xferq != NULL && it->stproc != NULL){ 300 s = splfw(); 301 STAILQ_INSERT_TAIL(&it->stfree, it->stproc, link); 302 splx(s); 303 it->stproc = NULL; 304 } 305 if (xferq == NULL) { 306 isoloop: 307 if (it->stproc == NULL) { 308 it->stproc = STAILQ_FIRST(&it->stfree); 309 if (it->stproc != NULL) { 310 s = splfw(); 311 STAILQ_REMOVE_HEAD(&it->stfree, link); 312 splx(s); 313 it->queued = 0; 314 } else if (slept == 0) { 315 slept = 1; 316 err = sc->fc->itx_enable(sc->fc, sub); 317 if (err) 318 return err; 319 err = tsleep(it, FWPRI, 320 "fw_write", hz); 321 if (err) 322 return err; 323 goto isoloop; 324 } else { 325 err = EIO; 326 return err; 327 } 328 } 329 fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 330 it->stproc->poffset + it->queued); 331 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 332 err = uiomove((caddr_t)fp->mode.stream.payload, 333 fp->mode.stream.len, uio); 334 it->queued ++; 335 if (it->queued >= it->bnpacket) { 336 s = splfw(); 337 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 338 splx(s); 339 it->stproc = NULL; 340 err = sc->fc->itx_enable(sc->fc, sub); 341 } 342 if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 343 slept = 0; 344 goto isoloop; 345 } 346 return err; 347 } 348 if (xferq != NULL) { 349 xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid, 12); 350 if(xfer == NULL){ 351 err = ENOMEM; 352 return err; 353 } 354 xfer->dst = fp->mode.hdr.dst; 355 xfer->send.len = uio->uio_resid; 356 xfer->spd = 0;/* XXX: how to setup it */ 357 xfer->act.hand = fw_asy_callback; 358 359 err = uiomove(xfer->send.buf, uio->uio_resid, uio); 360 if(err){ 361 fw_xfer_free( xfer); 362 return err; 363 } 364 fw_asyreq(fc, -1, xfer); 365 err = tsleep(xfer, FWPRI, "fw_write", hz); 366 if(xfer->resp == EBUSY) 367 return EBUSY; 368 fw_xfer_free( xfer); 369 return err; 370 } 371 return EINVAL; 372 } 373 374 /* 375 * ioctl support. 376 */ 377 int 378 fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 379 { 380 struct firewire_softc *sc; 381 int unit = DEV2UNIT(dev); 382 int sub = DEV2DMACH(dev); 383 int s, i, len, err = 0; 384 struct fw_device *fwdev; 385 struct fw_bind *fwb; 386 struct fw_xferq *ir, *it; 387 struct fw_xfer *xfer; 388 struct fw_pkt *fp; 389 struct fw_devinfo *devinfo; 390 391 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 392 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 393 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 394 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 395 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 396 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 397 398 if (DEV_FWMEM(dev)) 399 return fwmem_ioctl(dev, cmd, data, flag, td); 400 401 sc = devclass_get_softc(firewire_devclass, unit); 402 if (!data) 403 return(EINVAL); 404 405 switch (cmd) { 406 case FW_STSTREAM: 407 sc->fc->it[sub]->flag &= ~0xff; 408 sc->fc->it[sub]->flag |= (0x3f & ichreq->ch); 409 sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6); 410 err = 0; 411 break; 412 case FW_GTSTREAM: 413 ichreq->ch = sc->fc->it[sub]->flag & 0x3f; 414 ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3; 415 err = 0; 416 break; 417 case FW_SRSTREAM: 418 sc->fc->ir[sub]->flag &= ~0xff; 419 sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch); 420 sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6); 421 err = sc->fc->irx_enable(sc->fc, sub); 422 break; 423 case FW_GRSTREAM: 424 ichreq->ch = sc->fc->ir[sub]->flag & 0x3f; 425 ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3; 426 err = 0; 427 break; 428 case FW_SSTBUF: 429 ir = sc->fc->ir[sub]; 430 it = sc->fc->it[sub]; 431 432 if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){ 433 return(EBUSY); 434 } 435 if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){ 436 return(EBUSY); 437 } 438 if((ibufreq->rx.nchunk * 439 ibufreq->rx.psize * ibufreq->rx.npacket) + 440 (ibufreq->tx.nchunk * 441 ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){ 442 return(EINVAL); 443 } 444 ir->bulkxfer 445 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, M_WAITOK); 446 if(ir->bulkxfer == NULL){ 447 return(ENOMEM); 448 } 449 it->bulkxfer 450 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, M_WAITOK); 451 if(it->bulkxfer == NULL){ 452 return(ENOMEM); 453 } 454 if (ibufreq->rx.psize > 0) { 455 ibufreq->rx.psize = roundup2(ibufreq->rx.psize, 456 sizeof(u_int32_t)); 457 ir->buf = fwdma_malloc_multiseg( 458 sc->fc, sizeof(u_int32_t), 459 ibufreq->rx.psize, 460 ibufreq->rx.nchunk * ibufreq->rx.npacket, 461 BUS_DMA_WAITOK); 462 463 if(ir->buf == NULL){ 464 free(ir->bulkxfer, M_FW); 465 free(it->bulkxfer, M_FW); 466 ir->bulkxfer = NULL; 467 it->bulkxfer = NULL; 468 it->buf = NULL; 469 return(ENOMEM); 470 } 471 } 472 if (ibufreq->tx.psize > 0) { 473 ibufreq->tx.psize = roundup2(ibufreq->tx.psize, 474 sizeof(u_int32_t)); 475 it->buf = fwdma_malloc_multiseg( 476 sc->fc, sizeof(u_int32_t), 477 ibufreq->tx.psize, 478 ibufreq->tx.nchunk * ibufreq->tx.npacket, 479 BUS_DMA_WAITOK); 480 481 if(it->buf == NULL){ 482 free(ir->bulkxfer, M_FW); 483 free(it->bulkxfer, M_FW); 484 fwdma_free_multiseg(ir->buf); 485 ir->bulkxfer = NULL; 486 it->bulkxfer = NULL; 487 it->buf = NULL; 488 return(ENOMEM); 489 } 490 } 491 492 ir->bnchunk = ibufreq->rx.nchunk; 493 ir->bnpacket = ibufreq->rx.npacket; 494 ir->psize = (ibufreq->rx.psize + 3) & ~3; 495 ir->queued = 0; 496 497 it->bnchunk = ibufreq->tx.nchunk; 498 it->bnpacket = ibufreq->tx.npacket; 499 it->psize = (ibufreq->tx.psize + 3) & ~3; 500 it->queued = 0; 501 502 STAILQ_INIT(&ir->stvalid); 503 STAILQ_INIT(&ir->stfree); 504 STAILQ_INIT(&ir->stdma); 505 ir->stproc = NULL; 506 507 STAILQ_INIT(&it->stvalid); 508 STAILQ_INIT(&it->stfree); 509 STAILQ_INIT(&it->stdma); 510 it->stproc = NULL; 511 512 for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){ 513 ir->bulkxfer[i].poffset = i * ir->bnpacket; 514 ir->bulkxfer[i].mbuf = NULL; 515 STAILQ_INSERT_TAIL(&ir->stfree, 516 &ir->bulkxfer[i], link); 517 } 518 for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){ 519 it->bulkxfer[i].poffset = i * it->bnpacket; 520 it->bulkxfer[i].mbuf = NULL; 521 STAILQ_INSERT_TAIL(&it->stfree, 522 &it->bulkxfer[i], link); 523 } 524 ir->flag &= ~FWXFERQ_MODEMASK; 525 ir->flag |= FWXFERQ_STREAM; 526 ir->flag |= FWXFERQ_EXTBUF; 527 528 it->flag &= ~FWXFERQ_MODEMASK; 529 it->flag |= FWXFERQ_STREAM; 530 it->flag |= FWXFERQ_EXTBUF; 531 err = 0; 532 break; 533 case FW_GSTBUF: 534 ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk; 535 ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket; 536 ibufreq->rx.psize = sc->fc->ir[sub]->psize; 537 538 ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk; 539 ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket; 540 ibufreq->tx.psize = sc->fc->it[sub]->psize; 541 break; 542 case FW_ASYREQ: 543 xfer = fw_xfer_alloc_buf(M_FWXFER, asyreq->req.len, 544 PAGE_SIZE /* XXX */); 545 if(xfer == NULL){ 546 err = ENOMEM; 547 return err; 548 } 549 fp = &asyreq->pkt; 550 switch (asyreq->req.type) { 551 case FWASREQNODE: 552 xfer->dst = fp->mode.hdr.dst; 553 break; 554 case FWASREQEUI: 555 fwdev = fw_noderesolve_eui64(sc->fc, 556 &asyreq->req.dst.eui); 557 if (fwdev == NULL) { 558 device_printf(sc->fc->bdev, 559 "cannot find node\n"); 560 err = EINVAL; 561 goto error; 562 } 563 xfer->dst = fwdev->dst; 564 fp->mode.hdr.dst = FWLOCALBUS | xfer->dst; 565 break; 566 case FWASRESTL: 567 /* XXX what's this? */ 568 break; 569 case FWASREQSTREAM: 570 /* nothing to do */ 571 break; 572 } 573 xfer->spd = asyreq->req.sped; 574 bcopy(fp, xfer->send.buf, xfer->send.len); 575 xfer->act.hand = fw_asy_callback; 576 err = fw_asyreq(sc->fc, sub, xfer); 577 if(err){ 578 fw_xfer_free( xfer); 579 return err; 580 } 581 err = tsleep(xfer, FWPRI, "asyreq", hz); 582 if(err == 0){ 583 if(asyreq->req.len >= xfer->recv.len){ 584 asyreq->req.len = xfer->recv.len; 585 }else{ 586 err = EINVAL; 587 } 588 bcopy(xfer->recv.buf, fp, asyreq->req.len); 589 } 590 error: 591 fw_xfer_free( xfer); 592 break; 593 case FW_IBUSRST: 594 sc->fc->ibr(sc->fc); 595 break; 596 case FW_CBINDADDR: 597 fwb = fw_bindlookup(sc->fc, 598 bindreq->start.hi, bindreq->start.lo); 599 if(fwb == NULL){ 600 err = EINVAL; 601 break; 602 } 603 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 604 STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist); 605 free(fwb, M_FW); 606 break; 607 case FW_SBINDADDR: 608 if(bindreq->len <= 0 ){ 609 err = EINVAL; 610 break; 611 } 612 if(bindreq->start.hi > 0xffff ){ 613 err = EINVAL; 614 break; 615 } 616 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); 617 if(fwb == NULL){ 618 err = ENOMEM; 619 break; 620 } 621 fwb->start_hi = bindreq->start.hi; 622 fwb->start_lo = bindreq->start.lo; 623 fwb->addrlen = bindreq->len; 624 fwb->sub = sub; 625 fwb->act_type = FWACT_CH; 626 627 xfer = fw_xfer_alloc(M_FWXFER); 628 if(xfer == NULL){ 629 err = ENOMEM; 630 return err; 631 } 632 xfer->fc = sc->fc; 633 634 s = splfw(); 635 /* XXX broken. need multiple xfer */ 636 STAILQ_INIT(&fwb->xferlist); 637 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 638 splx(s); 639 err = fw_bindadd(sc->fc, fwb); 640 break; 641 case FW_GDEVLST: 642 i = len = 1; 643 /* myself */ 644 devinfo = &fwdevlst->dev[0]; 645 devinfo->dst = sc->fc->nodeid; 646 devinfo->status = 0; /* XXX */ 647 devinfo->eui.hi = sc->fc->eui.hi; 648 devinfo->eui.lo = sc->fc->eui.lo; 649 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) { 650 if(len < FW_MAX_DEVLST){ 651 devinfo = &fwdevlst->dev[len++]; 652 devinfo->dst = fwdev->dst; 653 devinfo->status = 654 (fwdev->status == FWDEVINVAL)?0:1; 655 devinfo->eui.hi = fwdev->eui.hi; 656 devinfo->eui.lo = fwdev->eui.lo; 657 } 658 i++; 659 } 660 fwdevlst->n = i; 661 fwdevlst->info_len = len; 662 break; 663 case FW_GTPMAP: 664 bcopy(sc->fc->topology_map, data, 665 (sc->fc->topology_map->crc_len + 1) * 4); 666 break; 667 case FW_GCROM: 668 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) 669 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 670 break; 671 if (fwdev == NULL) { 672 err = FWNODE_INVAL; 673 break; 674 } 675 if (fwdev->rommax < CSRROMOFF) 676 len = 0; 677 else 678 len = fwdev->rommax - CSRROMOFF + 4; 679 if (crom_buf->len < len) 680 len = crom_buf->len; 681 else 682 crom_buf->len = len; 683 err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len); 684 break; 685 default: 686 sc->fc->ioctl (dev, cmd, data, flag, td); 687 break; 688 } 689 return err; 690 } 691 int 692 fw_poll(dev_t dev, int events, fw_proc *td) 693 { 694 int revents; 695 int tmp; 696 int unit = DEV2UNIT(dev); 697 int sub = DEV2DMACH(dev); 698 struct firewire_softc *sc; 699 700 if (DEV_FWMEM(dev)) 701 return fwmem_poll(dev, events, td); 702 703 sc = devclass_get_softc(firewire_devclass, unit); 704 revents = 0; 705 tmp = POLLIN | POLLRDNORM; 706 if (events & tmp) { 707 if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL) 708 revents |= tmp; 709 else 710 selrecord(td, &sc->fc->ir[sub]->rsel); 711 } 712 tmp = POLLOUT | POLLWRNORM; 713 if (events & tmp) { 714 /* XXX should be fixed */ 715 revents |= tmp; 716 } 717 718 return revents; 719 } 720 721 static int 722 #if __FreeBSD_version < 500102 723 fw_mmap (dev_t dev, vm_offset_t offset, int nproto) 724 #else 725 fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) 726 #endif 727 { 728 struct firewire_softc *fc; 729 int unit = DEV2UNIT(dev); 730 731 if (DEV_FWMEM(dev)) 732 #if __FreeBSD_version < 500102 733 return fwmem_mmap(dev, offset, nproto); 734 #else 735 return fwmem_mmap(dev, offset, paddr, nproto); 736 #endif 737 738 fc = devclass_get_softc(firewire_devclass, unit); 739 740 return EINVAL; 741 } 742