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

Cache object: 6b69852072067dc41ca17cd22611e192


[ 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.