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/fwmem.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: fwmem.c,v 1.19 2018/09/03 16:29:31 riastradh Exp $     */
    2 /*-
    3  * Copyright (c) 2002-2003
    4  *      Hidetoshi Shimokawa. 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 following acknowledgement:
   16  *
   17  *      This product includes software developed by Hidetoshi Shimokawa.
   18  *
   19  * 4. Neither the name of the author nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: fwmem.c,v 1.19 2018/09/03 16:29:31 riastradh Exp $");
   39 
   40 #include <sys/param.h>
   41 #include <sys/device.h>
   42 #include <sys/errno.h>
   43 #include <sys/buf.h>
   44 #include <sys/bus.h>
   45 #include <sys/conf.h>
   46 #include <sys/fcntl.h>
   47 #include <sys/malloc.h>
   48 #include <sys/sysctl.h>
   49 
   50 #include <dev/ieee1394/firewire.h>
   51 #include <dev/ieee1394/firewirereg.h>
   52 #include <dev/ieee1394/fwmem.h>
   53 
   54 #include "ioconf.h"
   55 
   56 static int fwmem_speed=2, fwmem_debug=0;
   57 static struct fw_eui64 fwmem_eui64;
   58 
   59 static int sysctl_fwmem_verify(SYSCTLFN_PROTO, int, int);
   60 static int sysctl_fwmem_verify_speed(SYSCTLFN_PROTO);
   61 
   62 static struct fw_xfer *fwmem_xfer_req(struct fw_device *, void *, int, int,
   63                                       int, void *);
   64 static void fwmem_biodone(struct fw_xfer *);
   65 
   66 /*
   67  * Setup sysctl(3) MIB, hw.fwmem.*
   68  *
   69  * TBD condition CTLFLAG_PERMANENT on being a module or not
   70  */
   71 SYSCTL_SETUP(sysctl_fwmem, "sysctl fwmem subtree setup")
   72 {
   73         int rc, fwmem_node_num;
   74         const struct sysctlnode *node;
   75 
   76         if ((rc = sysctl_createv(clog, 0, NULL, &node,
   77             CTLFLAG_PERMANENT, CTLTYPE_NODE, "fwmem",
   78             SYSCTL_DESCR("IEEE1394 Memory Access"),
   79             NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
   80                 goto err;
   81         }
   82         fwmem_node_num = node->sysctl_num;
   83 
   84         /* fwmem target EUI64 high/low */
   85         if ((rc = sysctl_createv(clog, 0, NULL, &node,
   86             CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT,
   87             "eui64_hi", SYSCTL_DESCR("Fwmem target EUI64 high"),
   88             NULL, 0, &fwmem_eui64.hi,
   89             0, CTL_HW, fwmem_node_num, CTL_CREATE, CTL_EOL)) != 0) {
   90                 goto err;
   91         }
   92         if ((rc = sysctl_createv(clog, 0, NULL, &node,
   93             CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT,
   94             "eui64_lo", SYSCTL_DESCR("Fwmem target EUI64 low"),
   95             NULL, 0, &fwmem_eui64.lo,
   96             0, CTL_HW, fwmem_node_num, CTL_CREATE, CTL_EOL)) != 0) {
   97                 goto err;
   98         }
   99 
  100         /* fwmem link speed */
  101         if ((rc = sysctl_createv(clog, 0, NULL, &node,
  102             CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT,
  103             "speed", SYSCTL_DESCR("Fwmem link speed"),
  104             sysctl_fwmem_verify_speed, 0, &fwmem_speed,
  105             0, CTL_HW, fwmem_node_num, CTL_CREATE, CTL_EOL)) != 0) {
  106                 goto err;
  107         }
  108 
  109         /* fwmem driver debug flag */
  110         if ((rc = sysctl_createv(clog, 0, NULL, &node,
  111             CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT,
  112             "fwmem_debug", SYSCTL_DESCR("Fwmem driver debug flag"),
  113             NULL, 0, &fwmem_debug,
  114             0, CTL_HW, fwmem_node_num, CTL_CREATE, CTL_EOL)) != 0) {
  115                 goto err;
  116         }
  117 
  118         return;
  119 
  120 err:
  121         printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
  122 }
  123 
  124 static int
  125 sysctl_fwmem_verify(SYSCTLFN_ARGS, int lower, int upper)
  126 {
  127         int error, t;
  128         struct sysctlnode node;
  129 
  130         node = *rnode;
  131         t = *(int*)rnode->sysctl_data;
  132         node.sysctl_data = &t;
  133         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  134         if (error || newp == NULL)
  135                 return error;
  136 
  137         if (t < lower || t > upper)
  138                 return EINVAL;
  139 
  140         *(int*)rnode->sysctl_data = t;
  141 
  142         return 0;
  143 }
  144 
  145 static int
  146 sysctl_fwmem_verify_speed(SYSCTLFN_ARGS)
  147 {
  148 
  149         return sysctl_fwmem_verify(SYSCTLFN_CALL(rnode), 0, FWSPD_S400);
  150 }
  151 
  152 #define MAXLEN (512 << fwmem_speed)
  153 
  154 struct fwmem_softc {
  155         struct fw_eui64 eui;
  156         struct firewire_softc *sc;
  157         int refcount;
  158         STAILQ_HEAD(, fw_xfer) xferlist;
  159 };
  160 
  161 
  162 int      
  163 fwmem_open(dev_t dev, int flags, int fmt, struct lwp *td)   
  164 {
  165         struct firewire_softc *sc;
  166         struct fwmem_softc *fms;
  167         struct fw_xfer *xfer;
  168 
  169         sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
  170         if (sc == NULL)
  171                 return ENXIO;
  172 
  173         if (sc->si_drv1 != NULL) {
  174                 if ((flags & FWRITE) != 0) {
  175                         return EBUSY;
  176                 }
  177                 fms = (struct fwmem_softc *)sc->si_drv1;
  178                 fms->refcount++;
  179         } else {
  180                 sc->si_drv1 = (void *)-1;
  181                 sc->si_drv1 = malloc(sizeof(struct fwmem_softc),
  182                     M_FW, M_WAITOK);
  183                 if (sc->si_drv1 == NULL)
  184                         return ENOMEM;
  185                 fms = (struct fwmem_softc *)sc->si_drv1;
  186                 memcpy(&fms->eui, &fwmem_eui64, sizeof(struct fw_eui64));
  187                 fms->sc = sc;
  188                 fms->refcount = 1;
  189                 STAILQ_INIT(&fms->xferlist);
  190                 xfer = fw_xfer_alloc(M_FW);
  191                 STAILQ_INSERT_TAIL(&fms->xferlist, xfer, link);
  192         }
  193         if (fwmem_debug)
  194                 printf("%s: refcount=%d\n", __func__, fms->refcount);
  195 
  196         return 0;
  197 }
  198 
  199 int
  200 fwmem_close(dev_t dev, int flags, int fmt, struct lwp *td)
  201 {
  202         struct firewire_softc *sc;
  203         struct fwmem_softc *fms;
  204         struct fw_xfer *xfer;
  205 
  206         sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
  207         if (sc == NULL)
  208                 return ENXIO;
  209 
  210         fms = (struct fwmem_softc *)sc->si_drv1;
  211 
  212         fms->refcount--;
  213         if (fwmem_debug)
  214                 printf("%s: refcount=%d\n", __func__, fms->refcount);
  215         if (fms->refcount < 1) {
  216                 while ((xfer = STAILQ_FIRST(&fms->xferlist)) != NULL) {
  217                         STAILQ_REMOVE_HEAD(&fms->xferlist, link);
  218                         fw_xfer_free(xfer);
  219                 }
  220                 free(sc->si_drv1, M_FW);
  221                 sc->si_drv1 = NULL;
  222         }
  223 
  224         return 0;
  225 }
  226 
  227 void
  228 fwmem_strategy(struct bio *bp)
  229 {
  230         struct firewire_softc *sc;
  231         struct fwmem_softc *fms;
  232         struct fw_device *fwdev;
  233         struct fw_xfer *xfer;
  234         dev_t dev = bp->bio_dev;
  235         int iolen, err = 0, s;
  236 
  237         sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
  238         if (sc == NULL)
  239                 return;
  240 
  241         /* XXX check request length */
  242 
  243         s = splvm();
  244         fms = (struct fwmem_softc *)sc->si_drv1;
  245         fwdev = fw_noderesolve_eui64(fms->sc->fc, &fms->eui);
  246         if (fwdev == NULL) {
  247                 if (fwmem_debug)
  248                         printf("fwmem: no such device ID:%08x%08x\n",
  249                                         fms->eui.hi, fms->eui.lo);
  250                 err = EINVAL;
  251                 goto error;
  252         }
  253 
  254         iolen = MIN(bp->bio_bcount, MAXLEN);
  255         if ((bp->bio_cmd & BIO_READ) == BIO_READ) {
  256                 if (iolen == 4 && (bp->bio_offset & 3) == 0)
  257                         xfer = fwmem_read_quad(fwdev, (void *) bp, fwmem_speed,
  258                             bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
  259                             bp->bio_data, fwmem_biodone);
  260                 else
  261                         xfer = fwmem_read_block(fwdev, (void *) bp, fwmem_speed,
  262                             bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
  263                             iolen, bp->bio_data, fwmem_biodone);
  264         } else {
  265                 if (iolen == 4 && (bp->bio_offset & 3) == 0)
  266                         xfer = fwmem_write_quad(fwdev, (void *)bp, fwmem_speed,
  267                             bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
  268                             bp->bio_data, fwmem_biodone);
  269                 else
  270                         xfer = fwmem_write_block(fwdev, (void *)bp, fwmem_speed,
  271                             bp->bio_offset >> 32, bp->bio_offset & 0xffffffff,
  272                             iolen, bp->bio_data, fwmem_biodone);
  273         }
  274         if (xfer == NULL) {
  275                 err = EIO;
  276                 goto error;
  277         }
  278         /* XXX */
  279         bp->bio_resid = bp->bio_bcount - iolen;
  280 error:
  281         splx(s);
  282         if (err != 0) {
  283                 if (fwmem_debug)
  284                         printf("%s: err=%d\n", __func__, err);
  285                 bp->bio_error = err;
  286                 bp->bio_resid = bp->bio_bcount;
  287                 biodone(bp);
  288         }
  289 }
  290 
  291 int
  292 fwmem_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *td)
  293 {
  294         struct firewire_softc *sc;
  295         struct fwmem_softc *fms;
  296         int err = 0;
  297 
  298         sc = device_lookup_private(&ieee1394if_cd, DEV2UNIT(dev));
  299         if (sc == NULL)
  300                 return ENXIO;
  301 
  302         fms = (struct fwmem_softc *)sc->si_drv1;
  303         switch (cmd) {
  304         case FW_SDEUI64:
  305                 memcpy(&fms->eui, data, sizeof(struct fw_eui64));
  306                 break;
  307 
  308         case FW_GDEUI64:
  309                 memcpy(data, &fms->eui, sizeof(struct fw_eui64));
  310                 break;
  311 
  312         default:
  313                 err = EINVAL;
  314         }
  315         return err;
  316 }
  317 
  318 
  319 struct fw_xfer *
  320 fwmem_read_quad(struct fw_device *fwdev, void * sc, uint8_t spd,
  321                 uint16_t dst_hi, uint32_t dst_lo, void *data,
  322                 void (*hand)(struct fw_xfer *))
  323 {
  324         struct fw_xfer *xfer;
  325         struct fw_pkt *fp;
  326 
  327         xfer = fwmem_xfer_req(fwdev, (void *)sc, spd, 0, 4, hand);
  328         if (xfer == NULL)
  329                 return NULL;
  330 
  331         fp = &xfer->send.hdr;
  332         fp->mode.rreqq.tcode = FWTCODE_RREQQ;
  333         fp->mode.rreqq.dest_hi = dst_hi;
  334         fp->mode.rreqq.dest_lo = dst_lo;
  335 
  336         xfer->send.payload = NULL;
  337         xfer->recv.payload = (uint32_t *)data;
  338 
  339         if (fwmem_debug)
  340                 aprint_error("fwmem_read_quad: %d %04x:%08x\n",
  341                     fwdev->dst, dst_hi, dst_lo);
  342 
  343         if (fw_asyreq(xfer->fc, -1, xfer) == 0)
  344                 return xfer;
  345 
  346         fw_xfer_free(xfer);
  347         return NULL;
  348 }
  349 
  350 struct fw_xfer *
  351 fwmem_write_quad(struct fw_device *fwdev, void *sc, uint8_t spd,
  352                  uint16_t dst_hi, uint32_t dst_lo, void *data,
  353                  void (*hand)(struct fw_xfer *))
  354 {
  355         struct fw_xfer *xfer;
  356         struct fw_pkt *fp;
  357 
  358         xfer = fwmem_xfer_req(fwdev, sc, spd, 0, 0, hand);
  359         if (xfer == NULL)
  360                 return NULL;
  361 
  362         fp = &xfer->send.hdr;
  363         fp->mode.wreqq.tcode = FWTCODE_WREQQ;
  364         fp->mode.wreqq.dest_hi = dst_hi;
  365         fp->mode.wreqq.dest_lo = dst_lo;
  366         fp->mode.wreqq.data = *(uint32_t *)data;
  367 
  368         xfer->send.payload = xfer->recv.payload = NULL;
  369 
  370         if (fwmem_debug)
  371                 aprint_error("fwmem_write_quad: %d %04x:%08x %08x\n",
  372                     fwdev->dst, dst_hi, dst_lo, *(uint32_t *)data);
  373 
  374         if (fw_asyreq(xfer->fc, -1, xfer) == 0)
  375                 return xfer;
  376 
  377         fw_xfer_free(xfer);
  378         return NULL;
  379 }
  380 
  381 struct fw_xfer *
  382 fwmem_read_block(struct fw_device *fwdev, void *sc, uint8_t spd,
  383                  uint16_t dst_hi, uint32_t dst_lo, int len, void *data,
  384                  void (*hand)(struct fw_xfer *))
  385 {
  386         struct fw_xfer *xfer;
  387         struct fw_pkt *fp;
  388 
  389         xfer = fwmem_xfer_req(fwdev, sc, spd, 0, roundup2(len, 4), hand);
  390         if (xfer == NULL)
  391                 return NULL;
  392 
  393         fp = &xfer->send.hdr;
  394         fp->mode.rreqb.tcode = FWTCODE_RREQB;
  395         fp->mode.rreqb.dest_hi = dst_hi;
  396         fp->mode.rreqb.dest_lo = dst_lo;
  397         fp->mode.rreqb.len = len;
  398         fp->mode.rreqb.extcode = 0;
  399 
  400         xfer->send.payload = NULL;
  401         xfer->recv.payload = data;
  402 
  403         if (fwmem_debug)
  404                 aprint_error("fwmem_read_block: %d %04x:%08x %d\n",
  405                     fwdev->dst, dst_hi, dst_lo, len);
  406         if (fw_asyreq(xfer->fc, -1, xfer) == 0)
  407                 return xfer;
  408 
  409         fw_xfer_free(xfer);
  410         return NULL;
  411 }
  412 
  413 struct fw_xfer *
  414 fwmem_write_block(struct fw_device *fwdev, void *sc, uint8_t spd,
  415                   uint16_t dst_hi, uint32_t dst_lo, int len, void *data,
  416                   void (*hand)(struct fw_xfer *))
  417 {
  418         struct fw_xfer *xfer;
  419         struct fw_pkt *fp;
  420 
  421         xfer = fwmem_xfer_req(fwdev, sc, spd, len, 0, hand);
  422         if (xfer == NULL)
  423                 return NULL;
  424 
  425         fp = &xfer->send.hdr;
  426         fp->mode.wreqb.tcode = FWTCODE_WREQB;
  427         fp->mode.wreqb.dest_hi = dst_hi;
  428         fp->mode.wreqb.dest_lo = dst_lo;
  429         fp->mode.wreqb.len = len;
  430         fp->mode.wreqb.extcode = 0;
  431 
  432         xfer->send.payload = data;
  433         xfer->recv.payload = NULL;
  434 
  435         if (fwmem_debug)
  436                 aprint_error("fwmem_write_block: %d %04x:%08x %d\n",
  437                     fwdev->dst, dst_hi, dst_lo, len);
  438         if (fw_asyreq(xfer->fc, -1, xfer) == 0)
  439                 return xfer;
  440 
  441         fw_xfer_free(xfer);
  442         return NULL;
  443 }
  444 
  445 
  446 static struct fw_xfer *
  447 fwmem_xfer_req(struct fw_device *fwdev, void *sc, int spd, int slen, int rlen,
  448                void *hand)
  449 {
  450         struct fw_xfer *xfer;
  451 
  452         xfer = fw_xfer_alloc(M_FW);
  453         if (xfer == NULL)
  454                 return NULL;
  455 
  456         xfer->fc = fwdev->fc;
  457         xfer->send.hdr.mode.hdr.dst = FWLOCALBUS | fwdev->dst;
  458         if (spd < 0)
  459                 xfer->send.spd = fwdev->speed;
  460         else
  461                 xfer->send.spd = uimin(spd, fwdev->speed);
  462         xfer->hand = hand;
  463         xfer->sc = sc;
  464         xfer->send.pay_len = slen;
  465         xfer->recv.pay_len = rlen;
  466 
  467         return xfer;
  468 }
  469 
  470 static void
  471 fwmem_biodone(struct fw_xfer *xfer)
  472 {
  473         struct bio *bp;
  474 
  475         bp = (struct bio *)xfer->sc;
  476         bp->bio_error = xfer->resp;
  477 
  478         if (bp->bio_error != 0) {
  479                 if (fwmem_debug)
  480                         printf("%s: err=%d\n", __func__, bp->bio_error);
  481                 bp->bio_resid = bp->bio_bcount;
  482         }
  483 
  484         fw_xfer_free(xfer);
  485         biodone(bp);
  486 }

Cache object: 452d42d96defca806e61294d6e7da824


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