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 firewire_comm *fc; 286 struct fw_xferq *it; 287 288 if (DEV_FWMEM(dev)) 289 return fwmem_write(dev, uio, ioflag); 290 291 sc = devclass_get_softc(firewire_devclass, unit); 292 fc = sc->fc; 293 it = sc->fc->it[sub]; 294 isoloop: 295 if (it->stproc == NULL) { 296 it->stproc = STAILQ_FIRST(&it->stfree); 297 if (it->stproc != NULL) { 298 s = splfw(); 299 STAILQ_REMOVE_HEAD(&it->stfree, link); 300 splx(s); 301 it->queued = 0; 302 } else if (slept == 0) { 303 slept = 1; 304 err = sc->fc->itx_enable(sc->fc, sub); 305 if (err) 306 return err; 307 err = tsleep(it, FWPRI, "fw_write", hz); 308 if (err) 309 return err; 310 goto isoloop; 311 } else { 312 err = EIO; 313 return err; 314 } 315 } 316 fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 317 it->stproc->poffset + it->queued); 318 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 319 err = uiomove((caddr_t)fp->mode.stream.payload, 320 fp->mode.stream.len, uio); 321 it->queued ++; 322 if (it->queued >= it->bnpacket) { 323 s = splfw(); 324 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 325 splx(s); 326 it->stproc = NULL; 327 err = sc->fc->itx_enable(sc->fc, sub); 328 } 329 if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 330 slept = 0; 331 goto isoloop; 332 } 333 return err; 334 } 335 336 /* 337 * ioctl support. 338 */ 339 int 340 fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 341 { 342 struct firewire_softc *sc; 343 int unit = DEV2UNIT(dev); 344 int sub = DEV2DMACH(dev); 345 int s, i, len, err = 0; 346 struct fw_device *fwdev; 347 struct fw_bind *fwb; 348 struct fw_xferq *ir, *it; 349 struct fw_xfer *xfer; 350 struct fw_pkt *fp; 351 struct fw_devinfo *devinfo; 352 353 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 354 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 355 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 356 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 357 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 358 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 359 360 if (DEV_FWMEM(dev)) 361 return fwmem_ioctl(dev, cmd, data, flag, td); 362 363 sc = devclass_get_softc(firewire_devclass, unit); 364 if (!data) 365 return(EINVAL); 366 367 switch (cmd) { 368 case FW_STSTREAM: 369 sc->fc->it[sub]->flag &= ~0xff; 370 sc->fc->it[sub]->flag |= (0x3f & ichreq->ch); 371 sc->fc->it[sub]->flag |= ((0x3 & ichreq->tag) << 6); 372 err = 0; 373 break; 374 case FW_GTSTREAM: 375 ichreq->ch = sc->fc->it[sub]->flag & 0x3f; 376 ichreq->tag =(sc->fc->it[sub]->flag) >> 2 & 0x3; 377 err = 0; 378 break; 379 case FW_SRSTREAM: 380 sc->fc->ir[sub]->flag &= ~0xff; 381 sc->fc->ir[sub]->flag |= (0x3f & ichreq->ch); 382 sc->fc->ir[sub]->flag |= ((0x3 & ichreq->tag) << 6); 383 err = sc->fc->irx_enable(sc->fc, sub); 384 break; 385 case FW_GRSTREAM: 386 ichreq->ch = sc->fc->ir[sub]->flag & 0x3f; 387 ichreq->tag =(sc->fc->ir[sub]->flag) >> 2 & 0x3; 388 err = 0; 389 break; 390 case FW_SSTBUF: 391 ir = sc->fc->ir[sub]; 392 it = sc->fc->it[sub]; 393 394 if(ir->flag & FWXFERQ_RUNNING || it->flag & FWXFERQ_RUNNING){ 395 return(EBUSY); 396 } 397 if((ir->flag & FWXFERQ_EXTBUF) || (it->flag & FWXFERQ_EXTBUF)){ 398 return(EBUSY); 399 } 400 if((ibufreq->rx.nchunk * 401 ibufreq->rx.psize * ibufreq->rx.npacket) + 402 (ibufreq->tx.nchunk * 403 ibufreq->tx.psize * ibufreq->tx.npacket) <= 0){ 404 return(EINVAL); 405 } 406 ir->bulkxfer 407 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->rx.nchunk, M_FW, M_WAITOK); 408 if(ir->bulkxfer == NULL){ 409 return(ENOMEM); 410 } 411 it->bulkxfer 412 = (struct fw_bulkxfer *)malloc(sizeof(struct fw_bulkxfer) * ibufreq->tx.nchunk, M_FW, M_WAITOK); 413 if(it->bulkxfer == NULL){ 414 return(ENOMEM); 415 } 416 if (ibufreq->rx.psize > 0) { 417 ibufreq->rx.psize = roundup2(ibufreq->rx.psize, 418 sizeof(u_int32_t)); 419 ir->buf = fwdma_malloc_multiseg( 420 sc->fc, sizeof(u_int32_t), 421 ibufreq->rx.psize, 422 ibufreq->rx.nchunk * ibufreq->rx.npacket, 423 BUS_DMA_WAITOK); 424 425 if(ir->buf == NULL){ 426 free(ir->bulkxfer, M_FW); 427 free(it->bulkxfer, M_FW); 428 ir->bulkxfer = NULL; 429 it->bulkxfer = NULL; 430 it->buf = NULL; 431 return(ENOMEM); 432 } 433 } 434 if (ibufreq->tx.psize > 0) { 435 ibufreq->tx.psize = roundup2(ibufreq->tx.psize, 436 sizeof(u_int32_t)); 437 it->buf = fwdma_malloc_multiseg( 438 sc->fc, sizeof(u_int32_t), 439 ibufreq->tx.psize, 440 ibufreq->tx.nchunk * ibufreq->tx.npacket, 441 BUS_DMA_WAITOK); 442 443 if(it->buf == NULL){ 444 free(ir->bulkxfer, M_FW); 445 free(it->bulkxfer, M_FW); 446 fwdma_free_multiseg(ir->buf); 447 ir->bulkxfer = NULL; 448 it->bulkxfer = NULL; 449 it->buf = NULL; 450 return(ENOMEM); 451 } 452 } 453 454 ir->bnchunk = ibufreq->rx.nchunk; 455 ir->bnpacket = ibufreq->rx.npacket; 456 ir->psize = (ibufreq->rx.psize + 3) & ~3; 457 ir->queued = 0; 458 459 it->bnchunk = ibufreq->tx.nchunk; 460 it->bnpacket = ibufreq->tx.npacket; 461 it->psize = (ibufreq->tx.psize + 3) & ~3; 462 it->queued = 0; 463 464 STAILQ_INIT(&ir->stvalid); 465 STAILQ_INIT(&ir->stfree); 466 STAILQ_INIT(&ir->stdma); 467 ir->stproc = NULL; 468 469 STAILQ_INIT(&it->stvalid); 470 STAILQ_INIT(&it->stfree); 471 STAILQ_INIT(&it->stdma); 472 it->stproc = NULL; 473 474 for(i = 0 ; i < sc->fc->ir[sub]->bnchunk; i++){ 475 ir->bulkxfer[i].poffset = i * ir->bnpacket; 476 ir->bulkxfer[i].mbuf = NULL; 477 STAILQ_INSERT_TAIL(&ir->stfree, 478 &ir->bulkxfer[i], link); 479 } 480 for(i = 0 ; i < sc->fc->it[sub]->bnchunk; i++){ 481 it->bulkxfer[i].poffset = i * it->bnpacket; 482 it->bulkxfer[i].mbuf = NULL; 483 STAILQ_INSERT_TAIL(&it->stfree, 484 &it->bulkxfer[i], link); 485 } 486 ir->flag &= ~FWXFERQ_MODEMASK; 487 ir->flag |= FWXFERQ_STREAM; 488 ir->flag |= FWXFERQ_EXTBUF; 489 490 it->flag &= ~FWXFERQ_MODEMASK; 491 it->flag |= FWXFERQ_STREAM; 492 it->flag |= FWXFERQ_EXTBUF; 493 err = 0; 494 break; 495 case FW_GSTBUF: 496 ibufreq->rx.nchunk = sc->fc->ir[sub]->bnchunk; 497 ibufreq->rx.npacket = sc->fc->ir[sub]->bnpacket; 498 ibufreq->rx.psize = sc->fc->ir[sub]->psize; 499 500 ibufreq->tx.nchunk = sc->fc->it[sub]->bnchunk; 501 ibufreq->tx.npacket = sc->fc->it[sub]->bnpacket; 502 ibufreq->tx.psize = sc->fc->it[sub]->psize; 503 break; 504 case FW_ASYREQ: 505 xfer = fw_xfer_alloc_buf(M_FWXFER, asyreq->req.len, 506 PAGE_SIZE /* XXX */); 507 if(xfer == NULL){ 508 err = ENOMEM; 509 return err; 510 } 511 fp = &asyreq->pkt; 512 switch (asyreq->req.type) { 513 case FWASREQNODE: 514 xfer->dst = fp->mode.hdr.dst; 515 break; 516 case FWASREQEUI: 517 fwdev = fw_noderesolve_eui64(sc->fc, 518 &asyreq->req.dst.eui); 519 if (fwdev == NULL) { 520 device_printf(sc->fc->bdev, 521 "cannot find node\n"); 522 err = EINVAL; 523 goto error; 524 } 525 xfer->dst = FWLOCALBUS | fwdev->dst; 526 fp->mode.hdr.dst = xfer->dst; 527 break; 528 case FWASRESTL: 529 /* XXX what's this? */ 530 break; 531 case FWASREQSTREAM: 532 /* nothing to do */ 533 break; 534 } 535 xfer->spd = asyreq->req.sped; 536 bcopy(fp, xfer->send.buf, xfer->send.len); 537 xfer->act.hand = fw_asy_callback; 538 err = fw_asyreq(sc->fc, sub, xfer); 539 if(err){ 540 fw_xfer_free( xfer); 541 return err; 542 } 543 err = tsleep(xfer, FWPRI, "asyreq", hz); 544 if(err == 0){ 545 if(asyreq->req.len >= xfer->recv.len){ 546 asyreq->req.len = xfer->recv.len; 547 }else{ 548 err = EINVAL; 549 } 550 bcopy(xfer->recv.buf, fp, asyreq->req.len); 551 } 552 error: 553 fw_xfer_free( xfer); 554 break; 555 case FW_IBUSRST: 556 sc->fc->ibr(sc->fc); 557 break; 558 case FW_CBINDADDR: 559 fwb = fw_bindlookup(sc->fc, 560 bindreq->start.hi, bindreq->start.lo); 561 if(fwb == NULL){ 562 err = EINVAL; 563 break; 564 } 565 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 566 STAILQ_REMOVE(&sc->fc->ir[sub]->binds, fwb, fw_bind, chlist); 567 free(fwb, M_FW); 568 break; 569 case FW_SBINDADDR: 570 if(bindreq->len <= 0 ){ 571 err = EINVAL; 572 break; 573 } 574 if(bindreq->start.hi > 0xffff ){ 575 err = EINVAL; 576 break; 577 } 578 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); 579 if(fwb == NULL){ 580 err = ENOMEM; 581 break; 582 } 583 fwb->start_hi = bindreq->start.hi; 584 fwb->start_lo = bindreq->start.lo; 585 fwb->addrlen = bindreq->len; 586 fwb->sub = sub; 587 fwb->act_type = FWACT_CH; 588 589 xfer = fw_xfer_alloc(M_FWXFER); 590 if(xfer == NULL){ 591 err = ENOMEM; 592 return err; 593 } 594 xfer->fc = sc->fc; 595 596 s = splfw(); 597 /* XXX broken. need multiple xfer */ 598 STAILQ_INIT(&fwb->xferlist); 599 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 600 splx(s); 601 err = fw_bindadd(sc->fc, fwb); 602 break; 603 case FW_GDEVLST: 604 i = len = 1; 605 /* myself */ 606 devinfo = &fwdevlst->dev[0]; 607 devinfo->dst = sc->fc->nodeid; 608 devinfo->status = 0; /* XXX */ 609 devinfo->eui.hi = sc->fc->eui.hi; 610 devinfo->eui.lo = sc->fc->eui.lo; 611 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) { 612 if(len < FW_MAX_DEVLST){ 613 devinfo = &fwdevlst->dev[len++]; 614 devinfo->dst = fwdev->dst; 615 devinfo->status = 616 (fwdev->status == FWDEVINVAL)?0:1; 617 devinfo->eui.hi = fwdev->eui.hi; 618 devinfo->eui.lo = fwdev->eui.lo; 619 } 620 i++; 621 } 622 fwdevlst->n = i; 623 fwdevlst->info_len = len; 624 break; 625 case FW_GTPMAP: 626 bcopy(sc->fc->topology_map, data, 627 (sc->fc->topology_map->crc_len + 1) * 4); 628 break; 629 case FW_GCROM: 630 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) 631 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 632 break; 633 if (fwdev == NULL) { 634 err = FWNODE_INVAL; 635 break; 636 } 637 if (fwdev->rommax < CSRROMOFF) 638 len = 0; 639 else 640 len = fwdev->rommax - CSRROMOFF + 4; 641 if (crom_buf->len < len) 642 len = crom_buf->len; 643 else 644 crom_buf->len = len; 645 err = copyout(&fwdev->csrrom[0], crom_buf->ptr, len); 646 break; 647 default: 648 sc->fc->ioctl (dev, cmd, data, flag, td); 649 break; 650 } 651 return err; 652 } 653 int 654 fw_poll(dev_t dev, int events, fw_proc *td) 655 { 656 int revents; 657 int tmp; 658 int unit = DEV2UNIT(dev); 659 int sub = DEV2DMACH(dev); 660 struct firewire_softc *sc; 661 662 if (DEV_FWMEM(dev)) 663 return fwmem_poll(dev, events, td); 664 665 sc = devclass_get_softc(firewire_devclass, unit); 666 revents = 0; 667 tmp = POLLIN | POLLRDNORM; 668 if (events & tmp) { 669 if (STAILQ_FIRST(&sc->fc->ir[sub]->q) != NULL) 670 revents |= tmp; 671 else 672 selrecord(td, &sc->fc->ir[sub]->rsel); 673 } 674 tmp = POLLOUT | POLLWRNORM; 675 if (events & tmp) { 676 /* XXX should be fixed */ 677 revents |= tmp; 678 } 679 680 return revents; 681 } 682 683 static int 684 #if __FreeBSD_version < 500102 685 fw_mmap (dev_t dev, vm_offset_t offset, int nproto) 686 #else 687 fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) 688 #endif 689 { 690 struct firewire_softc *fc; 691 int unit = DEV2UNIT(dev); 692 693 if (DEV_FWMEM(dev)) 694 #if __FreeBSD_version < 500102 695 return fwmem_mmap(dev, offset, nproto); 696 #else 697 return fwmem_mmap(dev, offset, paddr, nproto); 698 #endif 699 700 fc = devclass_get_softc(firewire_devclass, unit); 701 702 return EINVAL; 703 } 704