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/iicbus/iiconf.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) 1998 Nicolas Souchu
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/lock.h>
   33 #include <sys/malloc.h>
   34 #include <sys/module.h>
   35 #include <sys/mutex.h>
   36 #include <sys/bus.h>
   37 
   38 #include <dev/iicbus/iiconf.h>
   39 #include <dev/iicbus/iicbus.h>
   40 #include "iicbus_if.h"
   41 
   42 /*
   43  * iicbus_intr()
   44  */
   45 void
   46 iicbus_intr(device_t bus, int event, char *buf)
   47 {
   48         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
   49 
   50         /* call owner's intr routine */
   51         if (sc->owner)
   52                 IICBUS_INTR(sc->owner, event, buf);
   53 
   54         return;
   55 }
   56 
   57 static int
   58 iicbus_poll(struct iicbus_softc *sc, int how)
   59 {
   60         int error;
   61 
   62         IICBUS_ASSERT_LOCKED(sc);
   63         switch (how) {
   64         case IIC_WAIT | IIC_INTR:
   65                 error = mtx_sleep(sc, &sc->lock, IICPRI|PCATCH, "iicreq", 0);
   66                 break;
   67 
   68         case IIC_WAIT | IIC_NOINTR:
   69                 error = mtx_sleep(sc, &sc->lock, IICPRI, "iicreq", 0);
   70                 break;
   71 
   72         default:
   73                 return (EWOULDBLOCK);
   74                 break;
   75         }
   76 
   77         return (error);
   78 }
   79 
   80 /*
   81  * iicbus_request_bus()
   82  *
   83  * Allocate the device to perform transfers.
   84  *
   85  * how  : IIC_WAIT or IIC_DONTWAIT
   86  */
   87 int
   88 iicbus_request_bus(device_t bus, device_t dev, int how)
   89 {
   90         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
   91         int error = 0;
   92 
   93         /* first, ask the underlying layers if the request is ok */
   94         IICBUS_LOCK(sc);
   95         do {
   96                 error = IICBUS_CALLBACK(device_get_parent(bus),
   97                                                 IIC_REQUEST_BUS, (caddr_t)&how);
   98                 if (error)
   99                         error = iicbus_poll(sc, how);
  100         } while (error == EWOULDBLOCK);
  101 
  102         while (!error) {
  103                 if (sc->owner && sc->owner != dev) {
  104 
  105                         error = iicbus_poll(sc, how);
  106                 } else {
  107                         sc->owner = dev;
  108 
  109                         IICBUS_UNLOCK(sc);
  110                         return (0);
  111                 }
  112 
  113                 /* free any allocated resource */
  114                 if (error)
  115                         IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS,
  116                                         (caddr_t)&how);
  117         }
  118         IICBUS_UNLOCK(sc);
  119 
  120         return (error);
  121 }
  122 
  123 /*
  124  * iicbus_release_bus()
  125  *
  126  * Release the device allocated with iicbus_request_dev()
  127  */
  128 int
  129 iicbus_release_bus(device_t bus, device_t dev)
  130 {
  131         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
  132         int error;
  133 
  134         /* first, ask the underlying layers if the release is ok */
  135         error = IICBUS_CALLBACK(device_get_parent(bus), IIC_RELEASE_BUS, NULL);
  136 
  137         if (error)
  138                 return (error);
  139 
  140         IICBUS_LOCK(sc);
  141 
  142         if (sc->owner != dev) {
  143                 IICBUS_UNLOCK(sc);
  144                 return (EACCES);
  145         }
  146 
  147         sc->owner = NULL;
  148 
  149         /* wakeup waiting processes */
  150         wakeup(sc);
  151         IICBUS_UNLOCK(sc);
  152 
  153         return (0);
  154 }
  155 
  156 /*
  157  * iicbus_started()
  158  *
  159  * Test if the iicbus is started by the controller
  160  */
  161 int
  162 iicbus_started(device_t bus)
  163 {
  164         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
  165 
  166         return (sc->started);
  167 }
  168 
  169 /*
  170  * iicbus_start()
  171  *
  172  * Send start condition to the slave addressed by 'slave'
  173  */
  174 int
  175 iicbus_start(device_t bus, u_char slave, int timeout)
  176 {
  177         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
  178         int error = 0;
  179 
  180         if (sc->started)
  181                 return (EINVAL);                /* bus already started */
  182 
  183         if (!(error = IICBUS_START(device_get_parent(bus), slave, timeout)))
  184                 sc->started = slave;
  185         else
  186                 sc->started = 0;
  187 
  188         return (error);
  189 }
  190 
  191 /*
  192  * iicbus_repeated_start()
  193  *
  194  * Send start condition to the slave addressed by 'slave'
  195  */
  196 int
  197 iicbus_repeated_start(device_t bus, u_char slave, int timeout)
  198 {
  199         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
  200         int error = 0;
  201 
  202         if (!sc->started)
  203                 return (EINVAL);     /* bus should have been already started */
  204 
  205         if (!(error = IICBUS_REPEATED_START(device_get_parent(bus), slave, timeout)))
  206                 sc->started = slave;
  207         else
  208                 sc->started = 0;
  209 
  210         return (error);
  211 }
  212 
  213 /*
  214  * iicbus_stop()
  215  *
  216  * Send stop condition to the bus
  217  */
  218 int
  219 iicbus_stop(device_t bus)
  220 {
  221         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
  222         int error = 0;
  223 
  224         if (!sc->started)
  225                 return (EINVAL);                /* bus not started */
  226 
  227         error = IICBUS_STOP(device_get_parent(bus));
  228 
  229         /* refuse any further access */
  230         sc->started = 0;
  231 
  232         return (error);
  233 }
  234 
  235 /*
  236  * iicbus_write()
  237  *
  238  * Write a block of data to the slave previously started by
  239  * iicbus_start() call
  240  */
  241 int
  242 iicbus_write(device_t bus, const char *buf, int len, int *sent, int timeout)
  243 {
  244         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
  245         
  246         /* a slave must have been started with the appropriate address */
  247         if (!sc->started || (sc->started & LSB))
  248                 return (EINVAL);
  249 
  250         return (IICBUS_WRITE(device_get_parent(bus), buf, len, sent, timeout));
  251 }
  252 
  253 /*
  254  * iicbus_read()
  255  *
  256  * Read a block of data from the slave previously started by
  257  * iicbus_read() call
  258  */
  259 int 
  260 iicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay)
  261 {
  262         struct iicbus_softc *sc = (struct iicbus_softc *)device_get_softc(bus);
  263         
  264         /* a slave must have been started with the appropriate address */
  265         if (!sc->started || !(sc->started & LSB))
  266                 return (EINVAL);
  267 
  268         return (IICBUS_READ(device_get_parent(bus), buf, len, read, last, delay));
  269 }
  270 
  271 /*
  272  * iicbus_write_byte()
  273  *
  274  * Write a byte to the slave previously started by iicbus_start() call
  275  */
  276 int
  277 iicbus_write_byte(device_t bus, char byte, int timeout)
  278 {
  279         char data = byte;
  280         int sent;
  281 
  282         return (iicbus_write(bus, &data, 1, &sent, timeout));
  283 }
  284 
  285 /*
  286  * iicbus_read_byte()
  287  *
  288  * Read a byte from the slave previously started by iicbus_start() call
  289  */
  290 int
  291 iicbus_read_byte(device_t bus, char *byte, int timeout)
  292 {
  293         int read;
  294 
  295         return (iicbus_read(bus, byte, 1, &read, IIC_LAST_READ, timeout));
  296 }
  297 
  298 /*
  299  * iicbus_block_write()
  300  *
  301  * Write a block of data to slave ; start/stop protocol managed
  302  */
  303 int
  304 iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent)
  305 {
  306         u_char addr = slave & ~LSB;
  307         int error;
  308 
  309         if ((error = iicbus_start(bus, addr, 0)))
  310                 return (error);
  311 
  312         error = iicbus_write(bus, buf, len, sent, 0);
  313 
  314         iicbus_stop(bus);
  315 
  316         return (error);
  317 }
  318 
  319 /*
  320  * iicbus_block_read()
  321  *
  322  * Read a block of data from slave ; start/stop protocol managed
  323  */
  324 int
  325 iicbus_block_read(device_t bus, u_char slave, char *buf, int len, int *read)
  326 {
  327         u_char addr = slave | LSB;
  328         int error;
  329 
  330         if ((error = iicbus_start(bus, addr, 0)))
  331                 return (error);
  332 
  333         error = iicbus_read(bus, buf, len, read, IIC_LAST_READ, 0);
  334 
  335         iicbus_stop(bus);
  336 
  337         return (error);
  338 }
  339 
  340 /*
  341  * iicbus_transfer()
  342  *
  343  * Do an aribtrary number of transfers on the iicbus.  We pass these
  344  * raw requests to the bridge driver.  If the bridge driver supports
  345  * them directly, then it manages all the details.  If not, it can use
  346  * the helper function iicbus_transfer_gen() which will do the
  347  * transfers at a low level.
  348  *
  349  * Pointers passed in as part of iic_msg must be kernel pointers.
  350  * Callers that have user addresses to manage must do so on their own.
  351  */
  352 int
  353 iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
  354 {
  355         return (IICBUS_TRANSFER(device_get_parent(bus), msgs, nmsgs));
  356 }
  357 
  358 /*
  359  * Generic version of iicbus_transfer that calls the appropriate
  360  * routines to accomplish this.  See note above about acceptable
  361  * buffer addresses.
  362  */
  363 int
  364 iicbus_transfer_gen(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
  365 {
  366         int i, error, lenread, lenwrote, nkid, rpstart, addr;
  367         device_t *children, bus;
  368 
  369         if ((error = device_get_children(dev, &children, &nkid)) != 0)
  370                 return (error);
  371         if (nkid != 1) {
  372                 free(children, M_TEMP);
  373                 return (EIO);
  374         }
  375         bus = children[0];
  376         rpstart = 0;
  377         free(children, M_TEMP);
  378         for (i = 0, error = 0; i < nmsgs && error == 0; i++) {
  379                 addr = msgs[i].slave;
  380                 if (msgs[i].flags & IIC_M_RD)
  381                         addr |= LSB;
  382                 else
  383                         addr &= ~LSB;
  384 
  385                 if (!(msgs[i].flags & IIC_M_NOSTART)) {
  386                         if (rpstart)
  387                                 error = iicbus_repeated_start(bus, addr, 0);
  388                         else
  389                                 error = iicbus_start(bus, addr, 0);
  390                 }
  391 
  392                 if (error)
  393                         break;
  394 
  395                 if (msgs[i].flags & IIC_M_RD)
  396                         error = iicbus_read(bus, msgs[i].buf, msgs[i].len,
  397                             &lenread, IIC_LAST_READ, 0);
  398                 else
  399                         error = iicbus_write(bus, msgs[i].buf, msgs[i].len,
  400                             &lenwrote, 0);
  401 
  402                 if (!(msgs[i].flags & IIC_M_NOSTOP)) {
  403                         rpstart = 0;
  404                         iicbus_stop(bus);
  405                 } else {
  406                         rpstart = 1;    /* Next message gets repeated start */
  407                 }
  408         }
  409         return (error);
  410 }

Cache object: 959b557edf72999ea9e2c87c95bac185


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