fwdev.c revision 121466
10Sduke/* 22362Sohair * Copyright (c) 2003 Hidetoshi Shimokawa 30Sduke * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 40Sduke * All rights reserved. 50Sduke * 60Sduke * Redistribution and use in source and binary forms, with or without 70Sduke * modification, are permitted provided that the following conditions 80Sduke * are met: 90Sduke * 1. Redistributions of source code must retain the above copyright 100Sduke * notice, this list of conditions and the following disclaimer. 110Sduke * 2. Redistributions in binary form must reproduce the above copyright 120Sduke * notice, this list of conditions and the following disclaimer in the 130Sduke * documentation and/or other materials provided with the distribution. 140Sduke * 3. All advertising materials mentioning features or use of this software 150Sduke * must display the acknowledgement as bellow: 160Sduke * 170Sduke * This product includes software developed by K. Kobayashi and H. Shimokawa 180Sduke * 192362Sohair * 4. The name of the author may not be used to endorse or promote products 202362Sohair * derived from this software without specific prior written permission. 212362Sohair * 220Sduke * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 230Sduke * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 240Sduke * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 250Sduke * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 260Sduke * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 270Sduke * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 280Sduke * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 290Sduke * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 300Sduke * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 310Sduke * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 320Sduke * POSSIBILITY OF SUCH DAMAGE. 330Sduke * 340Sduke * $FreeBSD: head/sys/dev/firewire/fwdev.c 121466 2003-10-24 13:55:51Z simokawa $ 350Sduke * 360Sduke */ 370Sduke 380Sduke#include <sys/param.h> 390Sduke#include <sys/systm.h> 400Sduke#include <sys/types.h> 410Sduke#include <sys/mbuf.h> 420Sduke#if __FreeBSD_version < 500000 430Sduke#include <sys/buf.h> 440Sduke#else 450Sduke#include <sys/bio.h> 460Sduke#endif 470Sduke 480Sduke#include <sys/kernel.h> 490Sduke#include <sys/malloc.h> 500Sduke#include <sys/conf.h> 510Sduke#include <sys/poll.h> 520Sduke 530Sduke#include <sys/bus.h> 540Sduke#include <sys/ctype.h> 550Sduke#include <machine/bus.h> 560Sduke 570Sduke#include <sys/ioccom.h> 580Sduke 590Sduke#include <dev/firewire/firewire.h> 600Sduke#include <dev/firewire/firewirereg.h> 610Sduke#include <dev/firewire/fwdma.h> 620Sduke#include <dev/firewire/fwmem.h> 630Sduke#include <dev/firewire/iec68113.h> 640Sduke 650Sduke#define CDEV_MAJOR 127 660Sduke#define FWNODE_INVAL 0xffff 670Sduke 680Sdukestatic d_open_t fw_open; 690Sdukestatic d_close_t fw_close; 700Sdukestatic d_ioctl_t fw_ioctl; 710Sdukestatic d_poll_t fw_poll; 720Sdukestatic d_read_t fw_read; /* for Isochronous packet */ 730Sdukestatic d_write_t fw_write; 740Sdukestatic d_mmap_t fw_mmap; 750Sdukestatic d_strategy_t fw_strategy; 760Sduke 770Sdukestruct cdevsw firewire_cdevsw = 780Sduke{ 790Sduke#if __FreeBSD_version >= 500104 800Sduke .d_open = fw_open, 810Sduke .d_close = fw_close, 820Sduke .d_read = fw_read, 830Sduke .d_write = fw_write, 840Sduke .d_ioctl = fw_ioctl, 850Sduke .d_poll = fw_poll, 860Sduke .d_mmap = fw_mmap, 870Sduke .d_strategy = fw_strategy, 880Sduke .d_name = "fw", 890Sduke .d_maj = CDEV_MAJOR, 900Sduke .d_flags = D_MEM 910Sduke#else 920Sduke fw_open, fw_close, fw_read, fw_write, fw_ioctl, 930Sduke fw_poll, fw_mmap, fw_strategy, "fw", CDEV_MAJOR, 940Sduke nodump, nopsize, D_MEM, -1 950Sduke#endif 960Sduke}; 970Sduke 980Sdukestruct fw_drv1 { 990Sduke struct fw_xferq *ir; 1000Sduke struct fw_xferq *it; 1010Sduke struct fw_isobufreq bufreq; 1020Sduke}; 1030Sduke 1040Sdukestatic int 1050Sdukefwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q, 1060Sduke struct fw_bufspec *b) 1070Sduke{ 1080Sduke int i; 1090Sduke 1100Sduke if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF)) 1110Sduke return(EBUSY); 1120Sduke 1130Sduke q->bulkxfer = (struct fw_bulkxfer *) malloc( 1140Sduke sizeof(struct fw_bulkxfer) * b->nchunk, 1150Sduke M_FW, M_WAITOK); 1160Sduke if (q->bulkxfer == NULL) 1170Sduke return(ENOMEM); 1180Sduke 1190Sduke b->psize = roundup2(b->psize, sizeof(u_int32_t)); 1200Sduke q->buf = fwdma_malloc_multiseg(fc, sizeof(u_int32_t), 1210Sduke b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK); 1220Sduke 1230Sduke if (q->buf == NULL) { 1240Sduke free(q->bulkxfer, M_FW); 1250Sduke q->bulkxfer = NULL; 1260Sduke return(ENOMEM); 1270Sduke } 1280Sduke q->bnchunk = b->nchunk; 1290Sduke q->bnpacket = b->npacket; 1300Sduke q->psize = (b->psize + 3) & ~3; 1310Sduke q->queued = 0; 1320Sduke 1330Sduke STAILQ_INIT(&q->stvalid); 1340Sduke STAILQ_INIT(&q->stfree); 1350Sduke STAILQ_INIT(&q->stdma); 1360Sduke q->stproc = NULL; 1370Sduke 1380Sduke for(i = 0 ; i < q->bnchunk; i++){ 1390Sduke q->bulkxfer[i].poffset = i * q->bnpacket; 1400Sduke q->bulkxfer[i].mbuf = NULL; 1410Sduke STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link); 1420Sduke } 1430Sduke 1440Sduke q->flag &= ~FWXFERQ_MODEMASK; 1450Sduke q->flag |= FWXFERQ_STREAM; 1460Sduke q->flag |= FWXFERQ_EXTBUF; 1470Sduke 1480Sduke return (0); 1490Sduke} 1500Sduke 1510Sdukestatic int 1520Sdukefwdev_freebuf(struct fw_xferq *q) 1530Sduke{ 1540Sduke if (q->flag & FWXFERQ_EXTBUF) { 1550Sduke if (q->buf != NULL) 1560Sduke fwdma_free_multiseg(q->buf); 1570Sduke q->buf = NULL; 1580Sduke free(q->bulkxfer, M_FW); 1590Sduke q->bulkxfer = NULL; 1600Sduke q->flag &= ~FWXFERQ_EXTBUF; 1610Sduke q->psize = 0; 1620Sduke q->maxq = FWMAXQUEUE; 1630Sduke } 1640Sduke return (0); 1650Sduke} 1660Sduke 1670Sduke 1680Sdukestatic int 1690Sdukefw_open (dev_t dev, int flags, int fmt, fw_proc *td) 1700Sduke{ 1710Sduke int err = 0; 1720Sduke 1730Sduke if (dev->si_drv1 != NULL) 1740Sduke return (EBUSY); 1750Sduke 1760Sduke if (DEV_FWMEM(dev)) 1770Sduke return fwmem_open(dev, flags, fmt, td); 1780Sduke 1790Sduke#if __FreeBSD_version >= 500000 1800Sduke if ((dev->si_flags & SI_NAMED) == 0) { 1810Sduke int unit = DEV2UNIT(dev); 1820Sduke int sub = DEV2SUB(dev); 1830Sduke 1840Sduke make_dev(&firewire_cdevsw, minor(dev), 1850Sduke UID_ROOT, GID_OPERATOR, 0660, 1860Sduke "fw%d.%d", unit, sub); 1870Sduke } 1880Sduke#endif 1890Sduke 1900Sduke dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO); 1910Sduke 1920Sduke return err; 1930Sduke} 1940Sduke 1950Sdukestatic int 1960Sdukefw_close (dev_t dev, int flags, int fmt, fw_proc *td) 1970Sduke{ 1980Sduke struct firewire_softc *sc; 1990Sduke struct firewire_comm *fc; 2000Sduke struct fw_drv1 *d; 2010Sduke int unit = DEV2UNIT(dev); 2020Sduke struct fw_xfer *xfer; 2030Sduke struct fw_bind *fwb; 2040Sduke int err = 0; 2050Sduke 2060Sduke if (DEV_FWMEM(dev)) 2070Sduke return fwmem_close(dev, flags, fmt, td); 2080Sduke 2090Sduke sc = devclass_get_softc(firewire_devclass, unit); 2100Sduke fc = sc->fc; 2110Sduke d = (struct fw_drv1 *)dev->si_drv1; 2120Sduke 2130Sduke if (d->ir != NULL) { 2140Sduke struct fw_xferq *ir = d->ir; 2150Sduke 2160Sduke if ((ir->flag & FWXFERQ_OPEN) == 0) 2170Sduke return (EINVAL); 2180Sduke if (ir->flag & FWXFERQ_RUNNING) { 2190Sduke ir->flag &= ~FWXFERQ_RUNNING; 2200Sduke fc->irx_disable(fc, ir->dmach); 2210Sduke } 2220Sduke /* free extbuf */ 2230Sduke fwdev_freebuf(ir); 2240Sduke /* drain receiving buffer */ 2250Sduke for (xfer = STAILQ_FIRST(&ir->q); 2260Sduke xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) { 2270Sduke ir->queued --; 2280Sduke STAILQ_REMOVE_HEAD(&ir->q, link); 2290Sduke 2300Sduke xfer->resp = 0; 2310Sduke fw_xfer_done(xfer); 2320Sduke } 2330Sduke /* remove binding */ 2340Sduke for (fwb = STAILQ_FIRST(&ir->binds); fwb != NULL; 2350Sduke fwb = STAILQ_FIRST(&ir->binds)) { 2360Sduke STAILQ_REMOVE(&fc->binds, fwb, fw_bind, fclist); 2370Sduke STAILQ_REMOVE_HEAD(&ir->binds, chlist); 2380Sduke free(fwb, M_FW); 2390Sduke } 2400Sduke ir->flag &= ~(FWXFERQ_OPEN | 2410Sduke FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 2420Sduke d->ir = NULL; 2430Sduke 2440Sduke } 2450Sduke if (d->it != NULL) { 2460Sduke struct fw_xferq *it = d->it; 2470Sduke 2480Sduke if ((it->flag & FWXFERQ_OPEN) == 0) 2490Sduke return (EINVAL); 2500Sduke if (it->flag & FWXFERQ_RUNNING) { 2510Sduke it->flag &= ~FWXFERQ_RUNNING; 2520Sduke fc->itx_disable(fc, it->dmach); 2530Sduke } 2540Sduke /* free extbuf */ 2550Sduke fwdev_freebuf(it); 2560Sduke it->flag &= ~(FWXFERQ_OPEN | 2570Sduke FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK); 2580Sduke d->it = NULL; 2590Sduke } 2600Sduke free(dev->si_drv1, M_FW); 2610Sduke dev->si_drv1 = NULL; 2620Sduke 2630Sduke return err; 2640Sduke} 2650Sduke 2660Sduke/* 2670Sduke * read request. 2680Sduke */ 2690Sdukestatic int 2700Sdukefw_read (dev_t dev, struct uio *uio, int ioflag) 2710Sduke{ 2720Sduke struct firewire_softc *sc; 2730Sduke struct fw_xferq *ir; 2740Sduke struct fw_xfer *xfer; 2750Sduke int err = 0, s, slept = 0; 2760Sduke int unit = DEV2UNIT(dev); 2770Sduke struct fw_pkt *fp; 2780Sduke 2790Sduke if (DEV_FWMEM(dev)) 2800Sduke return physio(dev, uio, ioflag); 2810Sduke 2820Sduke sc = devclass_get_softc(firewire_devclass, unit); 2830Sduke 2840Sduke ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 2850Sduke if (ir == NULL || ir->buf == NULL) 2860Sduke return (EIO); 2870Sduke 2880Sdukereadloop: 2890Sduke xfer = STAILQ_FIRST(&ir->q); 2900Sduke if (ir->stproc == NULL) { 2910Sduke /* iso bulkxfer */ 2920Sduke ir->stproc = STAILQ_FIRST(&ir->stvalid); 2930Sduke if (ir->stproc != NULL) { 2940Sduke s = splfw(); 2950Sduke STAILQ_REMOVE_HEAD(&ir->stvalid, link); 2960Sduke splx(s); 2970Sduke ir->queued = 0; 2980Sduke } 2990Sduke } 3000Sduke if (xfer == NULL && ir->stproc == NULL) { 3010Sduke /* no data avaliable */ 3020Sduke if (slept == 0) { 3030Sduke slept = 1; 3040Sduke ir->flag |= FWXFERQ_WAKEUP; 3050Sduke err = tsleep(ir, FWPRI, "fw_read", hz); 3060Sduke ir->flag &= ~FWXFERQ_WAKEUP; 3070Sduke if (err == 0) 3080Sduke goto readloop; 3090Sduke } else if (slept == 1) 3100Sduke err = EIO; 3110Sduke return err; 3120Sduke } else if(xfer != NULL) { 3130Sduke#if 0 /* XXX broken */ 3140Sduke /* per packet mode or FWACT_CH bind?*/ 3150Sduke s = splfw(); 3160Sduke ir->queued --; 3170Sduke STAILQ_REMOVE_HEAD(&ir->q, link); 3180Sduke splx(s); 3190Sduke fp = &xfer->recv.hdr; 3200Sduke if (sc->fc->irx_post != NULL) 3210Sduke sc->fc->irx_post(sc->fc, fp->mode.ld); 3220Sduke err = uiomove((void *)fp, 1 /* XXX header size */, uio); 3230Sduke /* XXX copy payload too */ 3240Sduke /* XXX we should recycle this xfer */ 3250Sduke#endif 3260Sduke fw_xfer_free( xfer); 3270Sduke } else if(ir->stproc != NULL) { 3280Sduke /* iso bulkxfer */ 3290Sduke fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 3300Sduke ir->stproc->poffset + ir->queued); 3310Sduke if(sc->fc->irx_post != NULL) 3320Sduke sc->fc->irx_post(sc->fc, fp->mode.ld); 3330Sduke if(fp->mode.stream.len == 0){ 334 err = EIO; 335 return err; 336 } 337 err = uiomove((caddr_t)fp, 338 fp->mode.stream.len + sizeof(u_int32_t), uio); 339 ir->queued ++; 340 if(ir->queued >= ir->bnpacket){ 341 s = splfw(); 342 STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link); 343 splx(s); 344 sc->fc->irx_enable(sc->fc, ir->dmach); 345 ir->stproc = NULL; 346 } 347 if (uio->uio_resid >= ir->psize) { 348 slept = -1; 349 goto readloop; 350 } 351 } 352 return err; 353} 354 355static int 356fw_write (dev_t dev, struct uio *uio, int ioflag) 357{ 358 int err = 0; 359 struct firewire_softc *sc; 360 int unit = DEV2UNIT(dev); 361 int s, slept = 0; 362 struct fw_pkt *fp; 363 struct firewire_comm *fc; 364 struct fw_xferq *it; 365 366 if (DEV_FWMEM(dev)) 367 return physio(dev, uio, ioflag); 368 369 sc = devclass_get_softc(firewire_devclass, unit); 370 fc = sc->fc; 371 it = ((struct fw_drv1 *)dev->si_drv1)->it; 372 if (it == NULL || it->buf == NULL) 373 return (EIO); 374isoloop: 375 if (it->stproc == NULL) { 376 it->stproc = STAILQ_FIRST(&it->stfree); 377 if (it->stproc != NULL) { 378 s = splfw(); 379 STAILQ_REMOVE_HEAD(&it->stfree, link); 380 splx(s); 381 it->queued = 0; 382 } else if (slept == 0) { 383 slept = 1; 384 err = sc->fc->itx_enable(sc->fc, it->dmach); 385 if (err) 386 return err; 387 err = tsleep(it, FWPRI, "fw_write", hz); 388 if (err) 389 return err; 390 goto isoloop; 391 } else { 392 err = EIO; 393 return err; 394 } 395 } 396 fp = (struct fw_pkt *)fwdma_v_addr(it->buf, 397 it->stproc->poffset + it->queued); 398 err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio); 399 err = uiomove((caddr_t)fp->mode.stream.payload, 400 fp->mode.stream.len, uio); 401 it->queued ++; 402 if (it->queued >= it->bnpacket) { 403 s = splfw(); 404 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link); 405 splx(s); 406 it->stproc = NULL; 407 err = sc->fc->itx_enable(sc->fc, it->dmach); 408 } 409 if (uio->uio_resid >= sizeof(struct fw_isohdr)) { 410 slept = 0; 411 goto isoloop; 412 } 413 return err; 414} 415/* 416 * ioctl support. 417 */ 418int 419fw_ioctl (dev_t dev, u_long cmd, caddr_t data, int flag, fw_proc *td) 420{ 421 struct firewire_softc *sc; 422 struct firewire_comm *fc; 423 struct fw_drv1 *d; 424 int unit = DEV2UNIT(dev); 425 int s, i, len, err = 0; 426 struct fw_device *fwdev; 427 struct fw_bind *fwb; 428 struct fw_xferq *ir, *it; 429 struct fw_xfer *xfer; 430 struct fw_pkt *fp; 431 struct fw_devinfo *devinfo; 432 void *ptr; 433 434 struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data; 435 struct fw_asyreq *asyreq = (struct fw_asyreq *)data; 436 struct fw_isochreq *ichreq = (struct fw_isochreq *)data; 437 struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data; 438 struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data; 439 struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data; 440 441 if (DEV_FWMEM(dev)) 442 return fwmem_ioctl(dev, cmd, data, flag, td); 443 444 if (!data) 445 return(EINVAL); 446 447 sc = devclass_get_softc(firewire_devclass, unit); 448 fc = sc->fc; 449 d = (struct fw_drv1 *)dev->si_drv1; 450 ir = d->ir; 451 it = d->it; 452 453 switch (cmd) { 454 case FW_STSTREAM: 455 if (it == NULL) { 456 for (i = 0; i < fc->nisodma; i ++) { 457 it = fc->it[i]; 458 if ((it->flag & FWXFERQ_OPEN) == 0) 459 break; 460 } 461 if (i >= fc->nisodma) { 462 err = EBUSY; 463 break; 464 } 465 err = fwdev_allocbuf(fc, it, &d->bufreq.tx); 466 if (err) 467 break; 468 it->flag |= FWXFERQ_OPEN; 469 } 470 it->flag &= ~0xff; 471 it->flag |= (0x3f & ichreq->ch); 472 it->flag |= ((0x3 & ichreq->tag) << 6); 473 d->it = it; 474 break; 475 case FW_GTSTREAM: 476 if (it != NULL) { 477 ichreq->ch = it->flag & 0x3f; 478 ichreq->tag = it->flag >> 2 & 0x3; 479 } else 480 err = EINVAL; 481 break; 482 case FW_SRSTREAM: 483 if (ir == NULL) { 484 for (i = 0; i < fc->nisodma; i ++) { 485 ir = fc->ir[i]; 486 if ((ir->flag & FWXFERQ_OPEN) == 0) 487 break; 488 } 489 if (i >= fc->nisodma) { 490 err = EBUSY; 491 break; 492 } 493 err = fwdev_allocbuf(fc, ir, &d->bufreq.rx); 494 if (err) 495 break; 496 ir->flag |= FWXFERQ_OPEN; 497 } 498 ir->flag &= ~0xff; 499 ir->flag |= (0x3f & ichreq->ch); 500 ir->flag |= ((0x3 & ichreq->tag) << 6); 501 d->ir = ir; 502 err = fc->irx_enable(fc, ir->dmach); 503 break; 504 case FW_GRSTREAM: 505 if (d->ir != NULL) { 506 ichreq->ch = ir->flag & 0x3f; 507 ichreq->tag = ir->flag >> 2 & 0x3; 508 } else 509 err = EINVAL; 510 break; 511 case FW_SSTBUF: 512 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq)); 513 break; 514 case FW_GSTBUF: 515 bzero(&ibufreq->rx, sizeof(ibufreq->rx)); 516 if (ir != NULL) { 517 ibufreq->rx.nchunk = ir->bnchunk; 518 ibufreq->rx.npacket = ir->bnpacket; 519 ibufreq->rx.psize = ir->psize; 520 } 521 bzero(&ibufreq->tx, sizeof(ibufreq->tx)); 522 if (it != NULL) { 523 ibufreq->tx.nchunk = it->bnchunk; 524 ibufreq->tx.npacket = it->bnpacket; 525 ibufreq->tx.psize = it->psize; 526 } 527 break; 528 case FW_ASYREQ: 529 { 530 struct tcode_info *tinfo; 531 int pay_len = 0; 532 533 fp = &asyreq->pkt; 534 tinfo = &sc->fc->tcode[fp->mode.hdr.tcode]; 535 536 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0) 537 pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len); 538 539 xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/); 540 if (xfer == NULL) 541 return (ENOMEM); 542 543 switch (asyreq->req.type) { 544 case FWASREQNODE: 545 break; 546 case FWASREQEUI: 547 fwdev = fw_noderesolve_eui64(sc->fc, 548 &asyreq->req.dst.eui); 549 if (fwdev == NULL) { 550 device_printf(sc->fc->bdev, 551 "cannot find node\n"); 552 err = EINVAL; 553 goto out; 554 } 555 fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst; 556 break; 557 case FWASRESTL: 558 /* XXX what's this? */ 559 break; 560 case FWASREQSTREAM: 561 /* nothing to do */ 562 break; 563 } 564 565 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len); 566 if (pay_len > 0) 567 bcopy((char *)fp + tinfo->hdr_len, 568 (void *)&xfer->send.payload, pay_len); 569 xfer->send.spd = asyreq->req.sped; 570 xfer->act.hand = fw_asy_callback; 571 572 if ((err = fw_asyreq(sc->fc, -1, xfer)) != 0) 573 goto out; 574 if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0) 575 goto out; 576 if (xfer->resp != 0) { 577 err = EIO; 578 goto out; 579 } 580 if ((tinfo->flag & FWTI_TLABEL) == 0) 581 goto out; 582 583 /* copy response */ 584 tinfo = &sc->fc->tcode[xfer->recv.hdr.mode.hdr.tcode]; 585 if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) 586 asyreq->req.len = xfer->recv.pay_len; 587 else 588 err = EINVAL; 589 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len); 590 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, 591 MAX(0, asyreq->req.len - tinfo->hdr_len)); 592out: 593 fw_xfer_free_buf(xfer); 594 break; 595 } 596 case FW_IBUSRST: 597 sc->fc->ibr(sc->fc); 598 break; 599 case FW_CBINDADDR: 600 fwb = fw_bindlookup(sc->fc, 601 bindreq->start.hi, bindreq->start.lo); 602 if(fwb == NULL){ 603 err = EINVAL; 604 break; 605 } 606 STAILQ_REMOVE(&sc->fc->binds, fwb, fw_bind, fclist); 607 STAILQ_REMOVE(&ir->binds, fwb, fw_bind, chlist); 608 free(fwb, M_FW); 609 break; 610 case FW_SBINDADDR: 611 if(bindreq->len <= 0 ){ 612 err = EINVAL; 613 break; 614 } 615 if(bindreq->start.hi > 0xffff ){ 616 err = EINVAL; 617 break; 618 } 619 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT); 620 if(fwb == NULL){ 621 err = ENOMEM; 622 break; 623 } 624 fwb->start = ((u_int64_t)bindreq->start.hi << 32) | 625 bindreq->start.lo; 626 fwb->end = fwb->start + bindreq->len; 627 /* XXX */ 628 fwb->sub = ir->dmach; 629 fwb->act_type = FWACT_CH; 630 631 /* XXX alloc buf */ 632 xfer = fw_xfer_alloc(M_FWXFER); 633 if(xfer == NULL){ 634 err = ENOMEM; 635 return err; 636 } 637 xfer->fc = sc->fc; 638 639 s = splfw(); 640 /* XXX broken. need multiple xfer */ 641 STAILQ_INIT(&fwb->xferlist); 642 STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link); 643 splx(s); 644 err = fw_bindadd(sc->fc, fwb); 645 break; 646 case FW_GDEVLST: 647 i = len = 1; 648 /* myself */ 649 devinfo = &fwdevlst->dev[0]; 650 devinfo->dst = sc->fc->nodeid; 651 devinfo->status = 0; /* XXX */ 652 devinfo->eui.hi = sc->fc->eui.hi; 653 devinfo->eui.lo = sc->fc->eui.lo; 654 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) { 655 if(len < FW_MAX_DEVLST){ 656 devinfo = &fwdevlst->dev[len++]; 657 devinfo->dst = fwdev->dst; 658 devinfo->status = 659 (fwdev->status == FWDEVINVAL)?0:1; 660 devinfo->eui.hi = fwdev->eui.hi; 661 devinfo->eui.lo = fwdev->eui.lo; 662 } 663 i++; 664 } 665 fwdevlst->n = i; 666 fwdevlst->info_len = len; 667 break; 668 case FW_GTPMAP: 669 bcopy(sc->fc->topology_map, data, 670 (sc->fc->topology_map->crc_len + 1) * 4); 671 break; 672 case FW_GCROM: 673 STAILQ_FOREACH(fwdev, &sc->fc->devices, link) 674 if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui)) 675 break; 676 if (fwdev == NULL) { 677 if (!FW_EUI64_EQUAL(sc->fc->eui, crom_buf->eui)) { 678 err = FWNODE_INVAL; 679 break; 680 } 681 /* myself */ 682 ptr = malloc(CROMSIZE, M_FW, M_WAITOK); 683 len = CROMSIZE; 684 for (i = 0; i < CROMSIZE/4; i++) 685 ((u_int32_t *)ptr)[i] 686 = ntohl(sc->fc->config_rom[i]); 687 } else { 688 /* found */ 689 ptr = (void *)&fwdev->csrrom[0]; 690 if (fwdev->rommax < CSRROMOFF) 691 len = 0; 692 else 693 len = fwdev->rommax - CSRROMOFF + 4; 694 } 695 if (crom_buf->len < len) 696 len = crom_buf->len; 697 else 698 crom_buf->len = len; 699 err = copyout(ptr, crom_buf->ptr, len); 700 if (fwdev == NULL) 701 /* myself */ 702 free(ptr, M_FW); 703 break; 704 default: 705 sc->fc->ioctl (dev, cmd, data, flag, td); 706 break; 707 } 708 return err; 709} 710int 711fw_poll(dev_t dev, int events, fw_proc *td) 712{ 713 struct firewire_softc *sc; 714 struct fw_xferq *ir; 715 int revents; 716 int tmp; 717 int unit = DEV2UNIT(dev); 718 719 if (DEV_FWMEM(dev)) 720 return fwmem_poll(dev, events, td); 721 722 sc = devclass_get_softc(firewire_devclass, unit); 723 ir = ((struct fw_drv1 *)dev->si_drv1)->ir; 724 revents = 0; 725 tmp = POLLIN | POLLRDNORM; 726 if (events & tmp) { 727 if (STAILQ_FIRST(&ir->q) != NULL) 728 revents |= tmp; 729 else 730 selrecord(td, &ir->rsel); 731 } 732 tmp = POLLOUT | POLLWRNORM; 733 if (events & tmp) { 734 /* XXX should be fixed */ 735 revents |= tmp; 736 } 737 738 return revents; 739} 740 741static int 742#if __FreeBSD_version < 500102 743fw_mmap (dev_t dev, vm_offset_t offset, int nproto) 744#else 745fw_mmap (dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nproto) 746#endif 747{ 748 struct firewire_softc *sc; 749 int unit = DEV2UNIT(dev); 750 751 if (DEV_FWMEM(dev)) 752#if __FreeBSD_version < 500102 753 return fwmem_mmap(dev, offset, nproto); 754#else 755 return fwmem_mmap(dev, offset, paddr, nproto); 756#endif 757 758 sc = devclass_get_softc(firewire_devclass, unit); 759 760 return EINVAL; 761} 762 763static void 764fw_strategy(struct bio *bp) 765{ 766 dev_t dev; 767 768 dev = bp->bio_dev; 769 if (DEV_FWMEM(dev)) { 770 fwmem_strategy(bp); 771 return; 772 } 773 774 bp->bio_error = EOPNOTSUPP; 775 bp->bio_flags |= BIO_ERROR; 776 bp->bio_resid = bp->bio_bcount; 777 biodone(bp); 778} 779 780int 781fwdev_makedev(struct firewire_softc *sc) 782{ 783 int err = 0; 784 785#if __FreeBSD_version >= 500000 786 dev_t d; 787 int unit; 788 789 unit = device_get_unit(sc->fc->bdev); 790 sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0), 791 UID_ROOT, GID_OPERATOR, 0660, 792 "fw%d.%d", unit, 0); 793 d = make_dev(&firewire_cdevsw, 794 MAKEMINOR(FWMEM_FLAG, unit, 0), 795 UID_ROOT, GID_OPERATOR, 0660, 796 "fwmem%d.%d", unit, 0); 797 dev_depends(sc->dev, d); 798 make_dev_alias(sc->dev, "fw%d", unit); 799 make_dev_alias(d, "fwmem%d", unit); 800#else 801 cdevsw_add(&firewire_cdevsw); 802#endif 803 804 return (err); 805} 806 807int 808fwdev_destroydev(struct firewire_softc *sc) 809{ 810 int err = 0; 811 812#if __FreeBSD_version >= 500000 813 destroy_dev(sc->dev); 814#else 815 cdevsw_remove(&firewire_cdevsw); 816#endif 817 return (err); 818} 819 820#if __FreeBSD_version >= 500000 821#define NDEVTYPE 2 822void 823fwdev_clone(void *arg, char *name, int namelen, dev_t *dev) 824{ 825 struct firewire_softc *sc; 826 char *devnames[NDEVTYPE] = {"fw", "fwmem"}; 827 char *subp = NULL; 828 int devflag[NDEVTYPE] = {0, FWMEM_FLAG}; 829 int i, unit = 0, sub = 0; 830 831 if (*dev != NODEV) 832 return; 833 834 for (i = 0; i < NDEVTYPE; i++) 835 if (dev_stdclone(name, &subp, devnames[i], &unit) == 2) 836 goto found; 837 /* not match */ 838 return; 839found: 840 841 if (subp == NULL || *subp++ != '.') 842 return; 843 844 /* /dev/fwU.S */ 845 while (isdigit(*subp)) { 846 sub *= 10; 847 sub += *subp++ - '0'; 848 } 849 if (*subp != '\0') 850 return; 851 852 sc = devclass_get_softc(firewire_devclass, unit); 853 if (sc == NULL) 854 return; 855 *dev = make_dev(&firewire_cdevsw, MAKEMINOR(devflag[i], unit, sub), 856 UID_ROOT, GID_OPERATOR, 0660, 857 "%s%d.%d", devnames[i], unit, sub); 858 (*dev)->si_flags |= SI_CHEAPCLONE; 859 dev_depends(sc->dev, *dev); 860 return; 861} 862#endif 863