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