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