The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ieee1394/fwdev.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: fwdev.c,v 1.8 2006/11/16 16:10:43 jdolecek Exp $       */
    2 /*-
    3  * Copyright (c) 2003 Hidetoshi Shimokawa
    4  * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the acknowledgement as bellow:
   17  *
   18  *    This product includes software developed by K. Kobayashi and H. Shimokawa
   19  *
   20  * 4. The name of the author may not be used to endorse or promote products
   21  *    derived from this software without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   26  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   27  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   29  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   31  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   33  * POSSIBILITY OF SUCH DAMAGE.
   34  * 
   35  * $FreeBSD: /repoman/r/ncvs/src/sys/dev/firewire/fwdev.c,v 1.46 2005/03/31 12:19:42 phk Exp $
   36  *
   37  */
   38 
   39 #if defined(__FreeBSD__)
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/types.h>
   43 #include <sys/mbuf.h>
   44 #if defined(__DragonFly__) || __FreeBSD_version < 500000
   45 #include <sys/buf.h>
   46 #else
   47 #include <sys/bio.h>
   48 #endif
   49 
   50 #include <sys/kernel.h>
   51 #include <sys/malloc.h>
   52 #include <sys/conf.h>
   53 #include <sys/poll.h>
   54 
   55 #include <sys/bus.h>
   56 #include <sys/ctype.h>
   57 #include <machine/bus.h>
   58 
   59 #include <sys/ioccom.h>
   60 
   61 #ifdef __DragonFly__
   62 #include "fw_port.h"
   63 #include "firewire.h"
   64 #include "firewirereg.h"
   65 #include "fwdma.h"
   66 #include "fwmem.h"
   67 #include "iec68113.h"
   68 #else
   69 #include <dev/firewire/fw_port.h>
   70 #include <dev/firewire/firewire.h>
   71 #include <dev/firewire/firewirereg.h>
   72 #include <dev/firewire/fwdma.h>
   73 #include <dev/firewire/fwmem.h>
   74 #include <dev/firewire/iec68113.h>
   75 #endif
   76 #elif defined(__NetBSD__)
   77 #include <sys/param.h>
   78 #include <sys/device.h>
   79 #include <sys/errno.h>
   80 #include <sys/buf.h>
   81 #include <sys/conf.h>
   82 #include <sys/kernel.h>
   83 #include <sys/malloc.h>
   84 #include <sys/mbuf.h>
   85 #include <sys/poll.h>
   86 #include <sys/proc.h>
   87 
   88 #include <machine/bus.h>
   89 
   90 #include <dev/ieee1394/fw_port.h>
   91 #include <dev/ieee1394/firewire.h>
   92 #include <dev/ieee1394/firewirereg.h>
   93 #include <dev/ieee1394/fwdma.h>
   94 #include <dev/ieee1394/fwmem.h>
   95 #include <dev/ieee1394/iec68113.h>
   96 #endif
   97 
   98 #define FWNODE_INVAL 0xffff
   99 
  100 #if defined(__FreeBSD__)
  101 static  d_open_t        fw_open;
  102 static  d_close_t       fw_close;
  103 static  d_ioctl_t       fw_ioctl;
  104 static  d_poll_t        fw_poll;
  105 static  d_read_t        fw_read;        /* for Isochronous packet */
  106 static  d_write_t       fw_write;
  107 static  d_mmap_t        fw_mmap;
  108 static  d_strategy_t    fw_strategy;
  109 
  110 struct cdevsw firewire_cdevsw = {
  111 #ifdef __DragonFly__
  112 #define CDEV_MAJOR 127
  113         "fw", CDEV_MAJOR, D_MEM, NULL, 0,
  114         fw_open, fw_close, fw_read, fw_write, fw_ioctl,
  115         fw_poll, fw_mmap, fw_strategy, nodump, nopsize,
  116 #elif __FreeBSD_version >= 500104
  117         .d_version =    D_VERSION,
  118         .d_open =       fw_open,
  119         .d_close =      fw_close,
  120         .d_read =       fw_read,
  121         .d_write =      fw_write,
  122         .d_ioctl =      fw_ioctl,
  123         .d_poll =       fw_poll,
  124         .d_mmap =       fw_mmap,
  125         .d_strategy =   fw_strategy,
  126         .d_name =       "fw",
  127         .d_flags =      D_MEM | D_NEEDGIANT
  128 #else
  129 #define CDEV_MAJOR 127
  130         fw_open, fw_close, fw_read, fw_write, fw_ioctl,
  131         fw_poll, fw_mmap, fw_strategy, "fw", CDEV_MAJOR,
  132         nodump, nopsize, D_MEM, -1
  133 #endif
  134 };
  135 #elif defined(__NetBSD__)
  136 dev_type_open(fw_open);
  137 dev_type_close(fw_close);
  138 dev_type_read(fw_read);
  139 dev_type_write(fw_write);
  140 dev_type_ioctl(fw_ioctl);
  141 dev_type_poll(fw_poll);
  142 dev_type_mmap(fw_mmap);
  143 dev_type_strategy(fw_strategy);
  144 
  145 const struct bdevsw fw_bdevsw = {
  146         fw_open, fw_close, fw_strategy, fw_ioctl, nodump, nosize, D_OTHER,
  147 };
  148 
  149 const struct cdevsw fw_cdevsw = {
  150         fw_open, fw_close, fw_read, fw_write, fw_ioctl,
  151         nostop, notty, fw_poll, fw_mmap, nokqfilter, D_OTHER,
  152 };
  153 #endif
  154 
  155 struct fw_drv1 {
  156         struct firewire_comm *fc;
  157         struct fw_xferq *ir;
  158         struct fw_xferq *it;
  159         struct fw_isobufreq bufreq;
  160         STAILQ_HEAD(, fw_bind) binds;
  161         STAILQ_HEAD(, fw_xfer) rq;
  162 };
  163 
  164 static int
  165 fwdev_allocbuf(struct firewire_comm *fc, struct fw_xferq *q,
  166         struct fw_bufspec *b)
  167 {
  168         int i;
  169 
  170         if (q->flag & (FWXFERQ_RUNNING | FWXFERQ_EXTBUF))
  171                 return(EBUSY);
  172 
  173         q->bulkxfer = (struct fw_bulkxfer *) malloc(
  174                 sizeof(struct fw_bulkxfer) * b->nchunk,
  175                 M_FW, M_WAITOK);
  176         if (q->bulkxfer == NULL)
  177                 return(ENOMEM);
  178 
  179         b->psize = roundup2(b->psize, sizeof(uint32_t));
  180         q->buf = fwdma_malloc_multiseg(fc, sizeof(uint32_t),
  181                         b->psize, b->nchunk * b->npacket, BUS_DMA_WAITOK);
  182 
  183         if (q->buf == NULL) {
  184                 free(q->bulkxfer, M_FW);
  185                 q->bulkxfer = NULL;
  186                 return(ENOMEM);
  187         }
  188         q->bnchunk = b->nchunk;
  189         q->bnpacket = b->npacket;
  190         q->psize = (b->psize + 3) & ~3;
  191         q->queued = 0;
  192 
  193         STAILQ_INIT(&q->stvalid);
  194         STAILQ_INIT(&q->stfree);
  195         STAILQ_INIT(&q->stdma);
  196         q->stproc = NULL;
  197 
  198         for(i = 0 ; i < q->bnchunk; i++){
  199                 q->bulkxfer[i].poffset = i * q->bnpacket;
  200                 q->bulkxfer[i].mbuf = NULL;
  201                 STAILQ_INSERT_TAIL(&q->stfree, &q->bulkxfer[i], link);
  202         }
  203 
  204         q->flag &= ~FWXFERQ_MODEMASK;
  205         q->flag |= FWXFERQ_STREAM;
  206         q->flag |= FWXFERQ_EXTBUF;
  207 
  208         return (0);
  209 }
  210 
  211 static int
  212 fwdev_freebuf(struct fw_xferq *q)
  213 {
  214         if (q->flag & FWXFERQ_EXTBUF) {
  215                 if (q->buf != NULL)
  216                         fwdma_free_multiseg(q->buf);
  217                 q->buf = NULL;
  218                 free(q->bulkxfer, M_FW);
  219                 q->bulkxfer = NULL;
  220                 q->flag &= ~FWXFERQ_EXTBUF;
  221                 q->psize = 0;
  222                 q->maxq = FWMAXQUEUE;
  223         }
  224         return (0);
  225 }
  226 
  227 
  228 FW_OPEN(fw)
  229 {
  230         int err = 0;
  231         struct fw_drv1 *d;
  232         FW_OPEN_START;
  233 
  234         FWDEV_OPEN_START;
  235 
  236         if (dev->si_drv1 != NULL)
  237                 return (EBUSY);
  238 
  239 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
  240         if ((dev->si_flags & SI_NAMED) == 0) {
  241                 int unit = DEV2UNIT(dev);
  242                 int sub = DEV2SUB(dev);
  243 
  244                 make_dev(&firewire_cdevsw, minor(dev),
  245                         UID_ROOT, GID_OPERATOR, 0660,
  246                         "fw%d.%d", unit, sub);
  247         }
  248 #endif
  249 
  250         dev->si_drv1 = malloc(sizeof(struct fw_drv1), M_FW, M_WAITOK | M_ZERO);
  251         if (dev->si_drv1 == NULL)
  252                 return (ENOMEM);
  253 
  254         d = (struct fw_drv1 *)dev->si_drv1;
  255         d->fc = sc->fc;
  256         STAILQ_INIT(&d->binds);
  257         STAILQ_INIT(&d->rq);
  258 
  259         return err;
  260 }
  261 
  262 FW_CLOSE(fw)
  263 {
  264         struct firewire_comm *fc;
  265         struct fw_drv1 *d;
  266         struct fw_xfer *xfer;
  267         struct fw_bind *fwb;
  268         int err = 0;
  269         FW_CLOSE_START;
  270 
  271         FWDEV_CLOSE_START;
  272 
  273         d = (struct fw_drv1 *)dev->si_drv1;
  274         fc = d->fc;
  275 
  276         /* remove binding */
  277         for (fwb = STAILQ_FIRST(&d->binds); fwb != NULL;
  278                         fwb = STAILQ_FIRST(&d->binds)) {
  279                 fw_bindremove(fc, fwb);
  280                 STAILQ_REMOVE_HEAD(&d->binds, chlist);
  281                 fw_xferlist_remove(&fwb->xferlist);
  282                 free(fwb, M_FW);
  283         }
  284         if (d->ir != NULL) {
  285                 struct fw_xferq *ir = d->ir;
  286 
  287                 if ((ir->flag & FWXFERQ_OPEN) == 0)
  288                         return (EINVAL);
  289                 if (ir->flag & FWXFERQ_RUNNING) {
  290                         ir->flag &= ~FWXFERQ_RUNNING;
  291                         fc->irx_disable(fc, ir->dmach);
  292                 }
  293                 /* free extbuf */
  294                 fwdev_freebuf(ir);
  295                 /* drain receiving buffer */
  296                 for (xfer = STAILQ_FIRST(&ir->q);
  297                         xfer != NULL; xfer = STAILQ_FIRST(&ir->q)) {
  298                         ir->queued --;
  299                         STAILQ_REMOVE_HEAD(&ir->q, link);
  300 
  301                         xfer->resp = 0;
  302                         fw_xfer_done(xfer);
  303                 }
  304                 ir->flag &= ~(FWXFERQ_OPEN |
  305                         FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
  306                 d->ir = NULL;
  307 
  308         }
  309         if (d->it != NULL) {
  310                 struct fw_xferq *it = d->it;
  311 
  312                 if ((it->flag & FWXFERQ_OPEN) == 0)
  313                         return (EINVAL);
  314                 if (it->flag & FWXFERQ_RUNNING) {
  315                         it->flag &= ~FWXFERQ_RUNNING;
  316                         fc->itx_disable(fc, it->dmach);
  317                 }
  318                 /* free extbuf */
  319                 fwdev_freebuf(it);
  320                 it->flag &= ~(FWXFERQ_OPEN |
  321                         FWXFERQ_MODEMASK | FWXFERQ_CHTAGMASK);
  322                 d->it = NULL;
  323         }
  324         free(dev->si_drv1, M_FW);
  325         dev->si_drv1 = NULL;
  326 
  327         return err;
  328 }
  329 
  330 static int
  331 fw_read_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
  332 {
  333         int err = 0, s;
  334         struct fw_xfer *xfer;
  335         struct fw_bind *fwb;
  336         struct fw_pkt *fp;
  337         const struct tcode_info *tinfo;
  338 
  339         while ((xfer = STAILQ_FIRST(&d->rq)) == NULL && err == 0)
  340                 err = tsleep(&d->rq, FWPRI, "fwra", 0);
  341 
  342         if (err != 0)
  343                 return (err);
  344 
  345         s = splfw();
  346         STAILQ_REMOVE_HEAD(&d->rq, link);
  347         splx(s);
  348         fp = &xfer->recv.hdr;
  349 #if 0 /* for GASP ?? */
  350         if (fc->irx_post != NULL)
  351                 fc->irx_post(fc, fp->mode.ld);
  352 #endif
  353         tinfo = &xfer->fc->tcode[fp->mode.hdr.tcode];
  354         err = uiomove((void *)fp, tinfo->hdr_len, uio);
  355         if (err)
  356                 goto out;
  357         err = uiomove((void *)xfer->recv.payload, xfer->recv.pay_len, uio);
  358 
  359 out:
  360         /* recycle this xfer */
  361         fwb = (struct fw_bind *)xfer->sc;
  362         fw_xfer_unload(xfer);
  363         xfer->recv.pay_len = PAGE_SIZE;
  364         STAILQ_INSERT_TAIL(&fwb->xferlist, xfer, link);
  365         return (err);
  366 }
  367 
  368 /*
  369  * read request.
  370  */
  371 FW_READ(fw)
  372 {
  373         FW_READ_START;
  374         struct fw_drv1 *d;
  375         struct fw_xferq *ir;
  376         struct firewire_comm *fc;
  377         int err = 0, s, slept = 0;
  378         struct fw_pkt *fp;
  379 
  380         FWDEV_READ_START;
  381 
  382         d = (struct fw_drv1 *)dev->si_drv1;
  383         fc = d->fc;
  384         ir = d->ir;
  385 
  386         if (ir == NULL)
  387                 return (fw_read_async(d, uio, ioflag));
  388 
  389         if (ir->buf == NULL)
  390                 return (EIO);
  391 
  392 readloop:
  393         if (ir->stproc == NULL) {
  394                 /* iso bulkxfer */
  395                 ir->stproc = STAILQ_FIRST(&ir->stvalid);
  396                 if (ir->stproc != NULL) {
  397                         s = splfw();
  398                         STAILQ_REMOVE_HEAD(&ir->stvalid, link);
  399                         splx(s);
  400                         ir->queued = 0;
  401                 }
  402         }
  403         if (ir->stproc == NULL) {
  404                 /* no data avaliable */
  405                 if (slept == 0) {
  406                         slept = 1;
  407                         ir->flag |= FWXFERQ_WAKEUP;
  408                         err = tsleep(ir, FWPRI, "fw_read", hz);
  409                         ir->flag &= ~FWXFERQ_WAKEUP;
  410                         if (err == 0)
  411                                 goto readloop;
  412                 } else if (slept == 1)
  413                         err = EIO;
  414                 return err;
  415         } else if(ir->stproc != NULL) {
  416                 /* iso bulkxfer */
  417                 fp = (struct fw_pkt *)fwdma_v_addr(ir->buf, 
  418                                 ir->stproc->poffset + ir->queued);
  419                 if(fc->irx_post != NULL)
  420                         fc->irx_post(fc, fp->mode.ld);
  421                 if(fp->mode.stream.len == 0){
  422                         err = EIO;
  423                         return err;
  424                 }
  425                 err = uiomove((caddr_t)fp,
  426                         fp->mode.stream.len + sizeof(uint32_t), uio);
  427                 ir->queued ++;
  428                 if(ir->queued >= ir->bnpacket){
  429                         s = splfw();
  430                         STAILQ_INSERT_TAIL(&ir->stfree, ir->stproc, link);
  431                         splx(s);
  432                         fc->irx_enable(fc, ir->dmach);
  433                         ir->stproc = NULL;
  434                 }
  435                 if (uio->uio_resid >= ir->psize) {
  436                         slept = -1;
  437                         goto readloop;
  438                 }
  439         }
  440         return err;
  441 }
  442 
  443 static int
  444 fw_write_async(struct fw_drv1 *d, struct uio *uio, int ioflag)
  445 {
  446         struct fw_xfer *xfer;
  447         struct fw_pkt pkt;
  448         const struct tcode_info *tinfo;
  449         int err;
  450 
  451         bzero(&pkt, sizeof(struct fw_pkt));
  452         if ((err = uiomove((caddr_t)&pkt, sizeof(uint32_t), uio)))
  453                 return (err);
  454         tinfo = &d->fc->tcode[pkt.mode.hdr.tcode];
  455         if ((err = uiomove((caddr_t)&pkt + sizeof(uint32_t),
  456             tinfo->hdr_len - sizeof(uint32_t), uio)))
  457                 return (err);
  458 
  459         if ((xfer = fw_xfer_alloc_buf(M_FWXFER, uio->uio_resid,
  460             PAGE_SIZE/*XXX*/)) == NULL)
  461                 return (ENOMEM);
  462 
  463         bcopy(&pkt, &xfer->send.hdr, sizeof(struct fw_pkt));
  464         xfer->send.pay_len = uio->uio_resid;
  465         if (uio->uio_resid > 0) {
  466                 if ((err = uiomove((caddr_t)&xfer->send.payload[0],
  467                     uio->uio_resid, uio)))
  468                         goto out;
  469         }
  470 
  471         xfer->fc = d->fc;
  472         xfer->sc = NULL;
  473         xfer->hand = fw_asy_callback;
  474         xfer->send.spd = 2 /* XXX */;
  475 
  476         if ((err = fw_asyreq(xfer->fc, -1, xfer)))
  477                 goto out;
  478 
  479         if ((err = tsleep(xfer, FWPRI, "fwwa", 0)))
  480                 goto out;
  481 
  482         if (xfer->resp != 0) {
  483                 err = xfer->resp;
  484                 goto out;
  485         }
  486 
  487         if (xfer->state == FWXF_RCVD) {
  488                 STAILQ_INSERT_TAIL(&d->rq, xfer, link);
  489                 return (0);
  490         }
  491 
  492 out:
  493         fw_xfer_free(xfer);
  494         return (err);
  495 }
  496 
  497 FW_WRITE(fw)
  498 {
  499         FW_WRITE_START;
  500         int err = 0;
  501         int s, slept = 0;
  502         struct fw_drv1 *d;
  503         struct fw_pkt *fp;
  504         struct firewire_comm *fc;
  505         struct fw_xferq *it;
  506 
  507         FWDEV_WRITE_START;
  508         d = (struct fw_drv1 *)dev->si_drv1;
  509         fc = d->fc;
  510         it = d->it;
  511 
  512         if (it == NULL)
  513                 return (fw_write_async(d, uio, ioflag));
  514 
  515         if (it->buf == NULL)
  516                 return (EIO);
  517 isoloop:
  518         if (it->stproc == NULL) {
  519                 it->stproc = STAILQ_FIRST(&it->stfree);
  520                 if (it->stproc != NULL) {
  521                         s = splfw();
  522                         STAILQ_REMOVE_HEAD(&it->stfree, link);
  523                         splx(s);
  524                         it->queued = 0;
  525                 } else if (slept == 0) {
  526                         slept = 1;
  527                         err = fc->itx_enable(fc, it->dmach);
  528                         if (err)
  529                                 return err;
  530                         err = tsleep(it, FWPRI, "fw_write", hz);
  531                         if (err)
  532                                 return err;
  533                         goto isoloop;
  534                 } else {
  535                         err = EIO;
  536                         return err;
  537                 }
  538         }
  539         fp = (struct fw_pkt *)fwdma_v_addr(it->buf,
  540                         it->stproc->poffset + it->queued);
  541         err = uiomove((caddr_t)fp, sizeof(struct fw_isohdr), uio);
  542         err = uiomove((caddr_t)fp->mode.stream.payload,
  543                                 fp->mode.stream.len, uio);
  544         it->queued ++;
  545         if (it->queued >= it->bnpacket) {
  546                 s = splfw();
  547                 STAILQ_INSERT_TAIL(&it->stvalid, it->stproc, link);
  548                 splx(s);
  549                 it->stproc = NULL;
  550                 err = fc->itx_enable(fc, it->dmach);
  551         }
  552         if (uio->uio_resid >= sizeof(struct fw_isohdr)) {
  553                 slept = 0;
  554                 goto isoloop;
  555         }
  556         return err;
  557 }
  558 
  559 static void
  560 fw_hand(struct fw_xfer *xfer)
  561 {
  562         struct fw_bind *fwb;
  563         struct fw_drv1 *d;
  564 
  565         fwb = (struct fw_bind *)xfer->sc;
  566         d = (struct fw_drv1 *)fwb->sc;
  567         STAILQ_INSERT_TAIL(&d->rq, xfer, link);
  568         wakeup(&d->rq);
  569 }
  570 
  571 /*
  572  * ioctl support.
  573  */
  574 FW_IOCTL(fw)
  575 {
  576         FW_IOCTL_START;
  577         struct firewire_comm *fc;
  578         struct fw_drv1 *d;
  579         int i, len, err = 0;
  580         struct fw_device *fwdev;
  581         struct fw_bind *fwb;
  582         struct fw_xferq *ir, *it;
  583         struct fw_xfer *xfer;
  584         struct fw_pkt *fp;
  585         struct fw_devinfo *devinfo;
  586         void *ptr;
  587 
  588         struct fw_devlstreq *fwdevlst = (struct fw_devlstreq *)data;
  589         struct fw_asyreq *asyreq = (struct fw_asyreq *)data;
  590         struct fw_isochreq *ichreq = (struct fw_isochreq *)data;
  591         struct fw_isobufreq *ibufreq = (struct fw_isobufreq *)data;
  592         struct fw_asybindreq *bindreq = (struct fw_asybindreq *)data;
  593         struct fw_crom_buf *crom_buf = (struct fw_crom_buf *)data;
  594 
  595         FWDEV_IOCTL_START;
  596 
  597         if (!data)
  598                 return(EINVAL);
  599 
  600         d = (struct fw_drv1 *)dev->si_drv1;
  601         fc = d->fc;
  602         ir = d->ir;
  603         it = d->it;
  604 
  605         switch (cmd) {
  606         case FW_STSTREAM:
  607                 if (it == NULL) {
  608                         for (i = 0; i < fc->nisodma; i ++) {
  609                                 it = fc->it[i];
  610                                 if ((it->flag & FWXFERQ_OPEN) == 0)
  611                                          break;
  612                         }       
  613                         if (i >= fc->nisodma) {
  614                                 err = EBUSY;
  615                                 break;
  616                         }
  617                         err = fwdev_allocbuf(fc, it, &d->bufreq.tx);
  618                         if (err)
  619                                 break;
  620                         it->flag |=  FWXFERQ_OPEN;
  621                 }
  622                 it->flag &= ~0xff;
  623                 it->flag |= (0x3f & ichreq->ch);
  624                 it->flag |= ((0x3 & ichreq->tag) << 6);
  625                 d->it = it;
  626                 break;
  627         case FW_GTSTREAM:
  628                 if (it != NULL) {
  629                         ichreq->ch = it->flag & 0x3f;
  630                         ichreq->tag = it->flag >> 2 & 0x3;
  631                 } else
  632                         err = EINVAL;
  633                 break;
  634         case FW_SRSTREAM:
  635                 if (ir == NULL) {
  636                         for (i = 0; i < fc->nisodma; i ++) {
  637                                 ir = fc->ir[i];
  638                                 if ((ir->flag & FWXFERQ_OPEN) == 0)
  639                                         break;
  640                         }       
  641                         if (i >= fc->nisodma) {
  642                                 err = EBUSY;
  643                                 break;
  644                         }
  645                         err = fwdev_allocbuf(fc, ir, &d->bufreq.rx);
  646                         if (err)
  647                                 break;
  648                         ir->flag |=  FWXFERQ_OPEN;
  649                 }
  650                 ir->flag &= ~0xff;
  651                 ir->flag |= (0x3f & ichreq->ch);
  652                 ir->flag |= ((0x3 & ichreq->tag) << 6);
  653                 d->ir = ir;
  654                 err = fc->irx_enable(fc, ir->dmach);
  655                 break;
  656         case FW_GRSTREAM:
  657                 if (d->ir != NULL) {
  658                         ichreq->ch = ir->flag & 0x3f;
  659                         ichreq->tag = ir->flag >> 2 & 0x3;
  660                 } else
  661                         err = EINVAL;
  662                 break;
  663         case FW_SSTBUF:
  664                 bcopy(ibufreq, &d->bufreq, sizeof(d->bufreq));
  665                 break;
  666         case FW_GSTBUF:
  667                 bzero(&ibufreq->rx, sizeof(ibufreq->rx));
  668                 if (ir != NULL) {
  669                         ibufreq->rx.nchunk = ir->bnchunk;
  670                         ibufreq->rx.npacket = ir->bnpacket;
  671                         ibufreq->rx.psize = ir->psize;
  672                 }
  673                 bzero(&ibufreq->tx, sizeof(ibufreq->tx));
  674                 if (it != NULL) {
  675                         ibufreq->tx.nchunk = it->bnchunk;
  676                         ibufreq->tx.npacket = it->bnpacket;
  677                         ibufreq->tx.psize = it->psize;
  678                 }
  679                 break;
  680         case FW_ASYREQ:
  681         {
  682                 const struct tcode_info *tinfo;
  683                 int pay_len = 0;
  684 
  685                 fp = &asyreq->pkt;
  686                 tinfo = &fc->tcode[fp->mode.hdr.tcode];
  687 
  688                 if ((tinfo->flag & FWTI_BLOCK_ASY) != 0)
  689                         pay_len = MAX(0, asyreq->req.len - tinfo->hdr_len);
  690 
  691                 xfer = fw_xfer_alloc_buf(M_FWXFER, pay_len, PAGE_SIZE/*XXX*/);
  692                 if (xfer == NULL)
  693                         return (ENOMEM);
  694 
  695                 switch (asyreq->req.type) {
  696                 case FWASREQNODE:
  697                         break;
  698                 case FWASREQEUI:
  699                         fwdev = fw_noderesolve_eui64(fc,
  700                                                 &asyreq->req.dst.eui);
  701                         if (fwdev == NULL) {
  702                                 device_printf(fc->bdev,
  703                                         "cannot find node\n");
  704                                 err = EINVAL;
  705                                 goto out;
  706                         }
  707                         fp->mode.hdr.dst = FWLOCALBUS | fwdev->dst;
  708                         break;
  709                 case FWASRESTL:
  710                         /* XXX what's this? */
  711                         break;
  712                 case FWASREQSTREAM:
  713                         /* nothing to do */
  714                         break;
  715                 }
  716 
  717                 bcopy(fp, (void *)&xfer->send.hdr, tinfo->hdr_len);
  718                 if (pay_len > 0)
  719                         bcopy((char *)fp + tinfo->hdr_len,
  720                             (void *)xfer->send.payload, pay_len);
  721                 xfer->send.spd = asyreq->req.sped;
  722                 xfer->hand = fw_asy_callback;
  723 
  724                 if ((err = fw_asyreq(fc, -1, xfer)) != 0)
  725                         goto out;
  726                 if ((err = tsleep(xfer, FWPRI, "asyreq", hz)) != 0)
  727                         goto out;
  728                 if (xfer->resp != 0) {
  729                         err = EIO;
  730                         goto out;
  731                 }
  732                 if ((tinfo->flag & FWTI_TLABEL) == 0)
  733                         goto out;
  734 
  735                 /* copy response */
  736                 tinfo = &fc->tcode[xfer->recv.hdr.mode.hdr.tcode];
  737                 if (xfer->recv.hdr.mode.hdr.tcode == FWTCODE_RRESB ||
  738                     xfer->recv.hdr.mode.hdr.tcode == FWTCODE_LRES) {
  739                         pay_len = xfer->recv.pay_len;
  740                         if (asyreq->req.len >= xfer->recv.pay_len + tinfo->hdr_len) {
  741                                 asyreq->req.len = xfer->recv.pay_len +
  742                                         tinfo->hdr_len;
  743                         } else {
  744                                 err = EINVAL;
  745                                 pay_len = 0;
  746                         }
  747                 } else {
  748                         pay_len = 0;
  749                 }
  750                 bcopy(&xfer->recv.hdr, fp, tinfo->hdr_len);
  751                 bcopy(xfer->recv.payload, (char *)fp + tinfo->hdr_len, pay_len);
  752 out:
  753                 fw_xfer_free_buf(xfer);
  754                 break;
  755         }
  756         case FW_IBUSRST:
  757                 fc->ibr(fc);
  758                 break;
  759         case FW_CBINDADDR:
  760                 fwb = fw_bindlookup(fc,
  761                                 bindreq->start.hi, bindreq->start.lo);
  762                 if(fwb == NULL){
  763                         err = EINVAL;
  764                         break;
  765                 }
  766                 fw_bindremove(fc, fwb);
  767                 STAILQ_REMOVE(&d->binds, fwb, fw_bind, chlist);
  768                 fw_xferlist_remove(&fwb->xferlist);
  769                 free(fwb, M_FW);
  770                 break;
  771         case FW_SBINDADDR:
  772                 if(bindreq->len <= 0 ){
  773                         err = EINVAL;
  774                         break;
  775                 }
  776                 if(bindreq->start.hi > 0xffff ){
  777                         err = EINVAL;
  778                         break;
  779                 }
  780                 fwb = (struct fw_bind *)malloc(sizeof (struct fw_bind), M_FW, M_NOWAIT);
  781                 if(fwb == NULL){
  782                         err = ENOMEM;
  783                         break;
  784                 }
  785                 fwb->start = ((u_int64_t)bindreq->start.hi << 32) |
  786                     bindreq->start.lo;
  787                 fwb->end = fwb->start +  bindreq->len;
  788                 fwb->sc = (void *)d;
  789                 STAILQ_INIT(&fwb->xferlist);
  790                 err = fw_bindadd(fc, fwb);
  791                 if (err == 0) {
  792                         fw_xferlist_add(&fwb->xferlist, M_FWXFER,
  793                             /* XXX */
  794                             PAGE_SIZE, PAGE_SIZE, 5,
  795                             fc, (void *)fwb, fw_hand);
  796                         STAILQ_INSERT_TAIL(&d->binds, fwb, chlist);
  797                 }
  798                 break;
  799         case FW_GDEVLST:
  800                 i = len = 1;
  801                 /* myself */
  802                 devinfo = &fwdevlst->dev[0];
  803                 devinfo->dst = fc->nodeid;
  804                 devinfo->status = 0;    /* XXX */
  805                 devinfo->eui.hi = fc->eui.hi;
  806                 devinfo->eui.lo = fc->eui.lo;
  807                 STAILQ_FOREACH(fwdev, &fc->devices, link) {
  808                         if(len < FW_MAX_DEVLST){
  809                                 devinfo = &fwdevlst->dev[len++];
  810                                 devinfo->dst = fwdev->dst;
  811                                 devinfo->status = 
  812                                         (fwdev->status == FWDEVINVAL)?0:1;
  813                                 devinfo->eui.hi = fwdev->eui.hi;
  814                                 devinfo->eui.lo = fwdev->eui.lo;
  815                         }
  816                         i++;
  817                 }
  818                 fwdevlst->n = i;
  819                 fwdevlst->info_len = len;
  820                 break;
  821         case FW_GTPMAP:
  822                 bcopy(fc->topology_map, data,
  823                                 (fc->topology_map->crc_len + 1) * 4);
  824                 break;
  825         case FW_GCROM:
  826                 STAILQ_FOREACH(fwdev, &fc->devices, link)
  827                         if (FW_EUI64_EQUAL(fwdev->eui, crom_buf->eui))
  828                                 break;
  829                 if (fwdev == NULL) {
  830                         if (!FW_EUI64_EQUAL(fc->eui, crom_buf->eui)) {
  831                                 err = FWNODE_INVAL;
  832                                 break;
  833                         }
  834                         /* myself */
  835                         ptr = malloc(CROMSIZE, M_FW, M_WAITOK);
  836                         len = CROMSIZE;
  837                         for (i = 0; i < CROMSIZE/4; i++)
  838                                 ((uint32_t *)ptr)[i]
  839                                         = ntohl(fc->config_rom[i]);
  840                 } else {
  841                         /* found */
  842                         ptr = (void *)&fwdev->csrrom[0];
  843                         if (fwdev->rommax < CSRROMOFF)
  844                                 len = 0;
  845                         else
  846                                 len = fwdev->rommax - CSRROMOFF + 4;
  847                 }
  848                 if (crom_buf->len < len)
  849                         len = crom_buf->len;
  850                 else
  851                         crom_buf->len = len;
  852                 err = copyout(ptr, crom_buf->ptr, len);
  853                 if (fwdev == NULL)
  854                         /* myself */
  855                         free(ptr, M_FW);
  856                 break;
  857         default:
  858                 FWDEV_IOCTL_REDIRECT;
  859                 break;
  860         }
  861         return err;
  862 }
  863 
  864 FW_POLL(fw)
  865 {
  866         FW_POLL_START;
  867         struct fw_xferq *ir;
  868         int revents;
  869         int tmp;
  870 
  871         FWDEV_POLL_START;
  872 
  873         ir = ((struct fw_drv1 *)dev->si_drv1)->ir;
  874         revents = 0;
  875         tmp = POLLIN | POLLRDNORM;
  876         if (events & tmp) {
  877                 if (STAILQ_FIRST(&ir->q) != NULL)
  878                         revents |= tmp;
  879                 else
  880                         selrecord(td, &ir->rsel);
  881         }
  882         tmp = POLLOUT | POLLWRNORM;
  883         if (events & tmp) {
  884                 /* XXX should be fixed */       
  885                 revents |= tmp;
  886         }
  887 
  888         return revents;
  889 }
  890 
  891 FW_MMAP(fw)
  892 {  
  893         FW_MMAP_START;
  894 
  895         FWDEV_MMAP_START;
  896 
  897         return EINVAL;
  898 }
  899 
  900 void
  901 fw_strategy(struct bio *bp)
  902 {
  903         FW_STRATEGY_START;
  904 
  905         FWDEV_STRATEGY_START;
  906 
  907         bp->bio_error = EOPNOTSUPP;
  908         bp->bio_flags |= BIO_ERROR;
  909         bp->bio_resid = bp->bio_bcount;
  910         biodone(bp);
  911 }
  912 
  913 #if defined(__FreeBSD__)
  914 int
  915 fwdev_makedev(struct firewire_softc *sc)
  916 {
  917         int err = 0;
  918 
  919 #if defined(__DragonFly__)
  920         int unit;
  921 
  922         unit = device_get_unit(sc->fc->bdev);
  923         cdevsw_add(&firewire_cdevsw, FW_UNITMASK, FW_UNIT(unit));
  924 #elif __FreeBSD_version < 500000
  925         cdevsw_add(&firewire_cdevsw);
  926 #else
  927         DEV_T d;
  928         int unit;
  929 
  930         unit = device_get_unit(sc->fc->bdev);
  931         sc->dev = make_dev(&firewire_cdevsw, MAKEMINOR(0, unit, 0),
  932                         UID_ROOT, GID_OPERATOR, 0660,
  933                         "fw%d.%d", unit, 0);
  934         d = make_dev(&firewire_cdevsw,
  935                         MAKEMINOR(FWMEM_FLAG, unit, 0),
  936                         UID_ROOT, GID_OPERATOR, 0660,
  937                         "fwmem%d.%d", unit, 0);
  938         dev_depends(sc->dev, d);
  939         make_dev_alias(sc->dev, "fw%d", unit);
  940         make_dev_alias(d, "fwmem%d", unit);
  941 #endif
  942 
  943         return (err);
  944 }
  945 
  946 int
  947 fwdev_destroydev(struct firewire_softc *sc)
  948 {
  949         int err = 0;
  950 
  951 #if defined(__DragonFly__)
  952         int unit;
  953 
  954         unit = device_get_unit(sc->fc->bdev);
  955         cdevsw_remove(&firewire_cdevsw, FW_UNITMASK, FW_UNIT(unit));
  956 #elif __FreeBSD_version < 500000
  957         cdevsw_remove(&firewire_cdevsw);
  958 #else
  959         destroy_dev(sc->dev);
  960 #endif
  961         return (err);
  962 }
  963 
  964 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
  965 #define NDEVTYPE 2
  966 void
  967 fwdev_clone(void *arg, char *name, int namelen, DEV_T *dev)
  968 {
  969         struct firewire_softc *sc;
  970         char *devnames[NDEVTYPE] = {"fw", "fwmem"};
  971         char *subp = NULL;
  972         int devflag[NDEVTYPE] = {0, FWMEM_FLAG};
  973         int i, unit = 0, sub = 0;
  974 
  975         if (*dev != NULL)
  976                 return;
  977 
  978         for (i = 0; i < NDEVTYPE; i++)
  979                 if (dev_stdclone(name, &subp, devnames[i], &unit) == 2)
  980                         goto found;
  981         /* not match */
  982         return;
  983 found:
  984 
  985         if (subp == NULL || *subp++ != '.')
  986                 return;
  987 
  988         /* /dev/fwU.S */
  989         while (isdigit(*subp)) {
  990                 sub *= 10;
  991                 sub += *subp++ - '';
  992         }
  993         if (*subp != '\0')
  994                 return;
  995 
  996         sc = devclass_get_softc(firewire_devclass, unit);
  997         if (sc == NULL)
  998                 return;
  999         *dev = make_dev(&firewire_cdevsw, MAKEMINOR(devflag[i], unit, sub),
 1000                        UID_ROOT, GID_OPERATOR, 0660,
 1001                        "%s%d.%d", devnames[i], unit, sub);
 1002         dev_ref(*dev);
 1003         (*dev)->si_flags |= SI_CHEAPCLONE;
 1004         dev_depends(sc->dev, *dev);
 1005         return;
 1006 }
 1007 #endif
 1008 #endif

Cache object: 65bbfa7985ad5366f8906e7d5069785c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.