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/ppbus/lpbb.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, Marc Bouget
    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  * $FreeBSD$
   27  *
   28  */
   29 
   30 /*
   31  * I2C Bit-Banging over parallel port
   32  *
   33  * See the Official Philips interface description in lpbb(4)
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/kernel.h>
   38 #include <sys/systm.h>
   39 #include <sys/module.h>
   40 #include <sys/bus.h>
   41 #include <sys/conf.h>
   42 #include <sys/buf.h>
   43 #include <sys/uio.h>
   44 #include <sys/malloc.h>
   45 
   46 #include <machine/clock.h>
   47 
   48 #include <dev/ppbus/ppbconf.h>
   49 
   50 #include <dev/iicbus/iiconf.h>
   51 #include <dev/iicbus/iicbus.h>
   52 
   53 #include "iicbb_if.h"
   54 
   55 /* iicbus softc */
   56 struct lpbb_softc {
   57 
   58         struct ppb_device lpbb_dev;
   59 };
   60 
   61 static int lpbb_detect(struct lpbb_softc *);
   62 
   63 static int lpbb_probe(device_t);
   64 static int lpbb_attach(device_t);
   65 static void lpbb_print_child(device_t, device_t);
   66 
   67 static int lpbb_callback(device_t, int, caddr_t *);
   68 static void lpbb_setlines(device_t, int, int);
   69 static int lpbb_getdataline(device_t);
   70 static int lpbb_reset(device_t, u_char, u_char, u_char *);
   71 
   72 static devclass_t lpbb_devclass;
   73 
   74 static device_method_t lpbb_methods[] = {
   75         /* device interface */
   76         DEVMETHOD(device_probe,         lpbb_probe),
   77         DEVMETHOD(device_attach,        lpbb_attach),
   78 
   79         /* bus interface */
   80         DEVMETHOD(bus_print_child,      lpbb_print_child),
   81 
   82         /* iicbb interface */
   83         DEVMETHOD(iicbb_callback,       lpbb_callback),
   84         DEVMETHOD(iicbb_setlines,       lpbb_setlines),
   85         DEVMETHOD(iicbb_getdataline,    lpbb_getdataline),
   86         DEVMETHOD(iicbb_reset,          lpbb_reset),
   87 
   88         { 0, 0 }
   89 };
   90 
   91 static driver_t lpbb_driver = {
   92         "lpbb",
   93         lpbb_methods,
   94         DRIVER_TYPE_MISC,
   95         sizeof(struct lpbb_softc),
   96 };
   97 
   98 /*
   99  * Make ourselves visible as a ppbus driver
  100  */
  101 static struct ppb_device        *lpbb_ppb_probe(struct ppb_data *ppb);
  102 static int                      lpbb_ppb_attach(struct ppb_device *dev);
  103 
  104 #define MAXLPBB 8                       /* XXX not much better! */
  105 static struct lpbb_softc *lpbbdata[MAXLPBB];
  106 static int nlpbb = 0;
  107 
  108 #ifdef KERNEL
  109 
  110 static struct ppb_driver lpbbdriver = {
  111     lpbb_ppb_probe, lpbb_ppb_attach, "lpbb"
  112 };
  113 DATA_SET(ppbdriver_set, lpbbdriver);
  114 
  115 #endif /* KERNEL */
  116 
  117 static int
  118 lpbb_probe(device_t dev)
  119 {
  120         struct lpbb_softc *sc = lpbbdata[device_get_unit(dev)];
  121         struct lpbb_softc *scdst = (struct lpbb_softc *)device_get_softc(dev);
  122 
  123         /* XXX copy softc. Yet, ppbus device is sc->lpbb_dev, but will be
  124          * dev->parent when ppbus will be ported to the new bus architecture */
  125         bcopy(sc, scdst, sizeof(struct lpbb_softc));
  126 
  127         device_set_desc(dev, "parallel I2C bit-banging interface");
  128 
  129         /* probe done by ppbus initialization */
  130         return (0);
  131 }
  132 
  133 static int
  134 lpbb_attach(device_t dev)
  135 {
  136         device_t bitbang, iicbus;
  137         
  138         /* add generic bit-banging code */
  139         bitbang = device_add_child(dev, "iicbb", -1, NULL);
  140 
  141         /* add the iicbus to the tree */
  142         iicbus = iicbus_alloc_bus(bitbang);
  143 
  144         device_probe_and_attach(bitbang);
  145 
  146         /* XXX should be in iicbb_attach! */
  147         device_probe_and_attach(iicbus);
  148 
  149         return (0);
  150 }
  151 
  152 /*
  153  * lppbb_ppb_probe()
  154  */
  155 static struct ppb_device *
  156 lpbb_ppb_probe(struct ppb_data *ppb)
  157 {
  158         struct lpbb_softc *sc;
  159 
  160         sc = (struct lpbb_softc *) malloc(sizeof(struct lpbb_softc),
  161                                                         M_TEMP, M_NOWAIT);
  162         if (!sc) {
  163                 printf("lpbb: cannot malloc!\n");
  164                 return (0);
  165         }
  166         bzero(sc, sizeof(struct lpbb_softc));
  167 
  168         lpbbdata[nlpbb] = sc;
  169 
  170         /*
  171          * ppbus dependent initialisation.
  172          */
  173         sc->lpbb_dev.id_unit = nlpbb;
  174         sc->lpbb_dev.name = lpbbdriver.name;
  175         sc->lpbb_dev.ppb = ppb;
  176         sc->lpbb_dev.intr = 0;
  177 
  178         if (!lpbb_detect(sc)) {
  179                 free(sc, M_TEMP);
  180                 return (NULL);
  181         }
  182 
  183         /* Ok, go to next device on next probe */
  184         nlpbb ++;
  185 
  186         /* XXX wrong according to new bus architecture. ppbus needs to be
  187          * ported
  188          */
  189         return (&sc->lpbb_dev);
  190 }
  191 
  192 static int
  193 lpbb_ppb_attach(struct ppb_device *dev)
  194 {
  195         /* add the parallel port I2C interface to the bus tree */
  196         if (!device_add_child(root_bus, "lpbb", dev->id_unit, NULL))
  197                 return (0);
  198 
  199         return (1);
  200 }
  201 
  202 static int
  203 lpbb_callback(device_t dev, int index, caddr_t *data)
  204 {
  205         struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev);
  206         int error = 0;
  207         int how;
  208 
  209         switch (index) {
  210         case IIC_REQUEST_BUS:
  211                 /* request the ppbus */
  212                 how = *(int *)data;
  213                 error = ppb_request_bus(&sc->lpbb_dev, how);
  214                 break;
  215 
  216         case IIC_RELEASE_BUS:
  217                 /* release the ppbus */
  218                 error = ppb_release_bus(&sc->lpbb_dev);
  219                 break;
  220 
  221         default:
  222                 error = EINVAL;
  223         }
  224 
  225         return (error);
  226 }
  227 
  228 #define SDA_out 0x80
  229 #define SCL_out 0x08
  230 #define SDA_in  0x80
  231 #define SCL_in  0x08
  232 #define ALIM    0x20
  233 #define I2CKEY  0x50
  234 
  235 static int getSDA(struct lpbb_softc *sc)
  236 {
  237 if((ppb_rstr(&sc->lpbb_dev)&SDA_in)==SDA_in)
  238         return 1;                   
  239 else                                
  240         return 0;                   
  241 }
  242 
  243 static void setSDA(struct lpbb_softc *sc, char val)
  244 {
  245 if(val==0)
  246         ppb_wdtr(&sc->lpbb_dev, (u_char)SDA_out);
  247 else                            
  248         ppb_wdtr(&sc->lpbb_dev, (u_char)~SDA_out);
  249 }
  250 
  251 static void setSCL(struct lpbb_softc *sc, unsigned char val)
  252 {
  253 if(val==0)
  254         ppb_wctr(&sc->lpbb_dev, (u_char)(ppb_rctr(&sc->lpbb_dev)&~SCL_out));
  255 else                                               
  256         ppb_wctr(&sc->lpbb_dev, (u_char)(ppb_rctr(&sc->lpbb_dev)|SCL_out)); 
  257 }
  258 
  259 static int lpbb_detect(struct lpbb_softc *sc)
  260 {
  261         if (ppb_request_bus(&sc->lpbb_dev, PPB_DONTWAIT)) {
  262                 printf("lpbb: can't allocate ppbus\n");
  263                 return (0);
  264         }
  265 
  266         /* reset bus */
  267         setSDA(sc, 1);
  268         setSCL(sc, 1);
  269 
  270         if ((ppb_rstr(&sc->lpbb_dev) & I2CKEY) ||
  271                 ((ppb_rstr(&sc->lpbb_dev) & ALIM) != ALIM)) {
  272 
  273                 ppb_release_bus(&sc->lpbb_dev);
  274                 return (0);
  275         }
  276 
  277         ppb_release_bus(&sc->lpbb_dev);
  278 
  279         return (1);
  280 }
  281 
  282 static int
  283 lpbb_reset(device_t dev, u_char speed, u_char addr, u_char * oldaddr)
  284 {
  285         struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev);
  286 
  287         /* reset bus */
  288         setSDA(sc, 1);
  289         setSCL(sc, 1);
  290 
  291         return (IIC_ENOADDR);
  292 }
  293 
  294 static void
  295 lpbb_setlines(device_t dev, int ctrl, int data)
  296 {
  297         struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev);
  298 
  299         setSCL(sc, ctrl);
  300         setSDA(sc, data);
  301 }
  302 
  303 static int
  304 lpbb_getdataline(device_t dev)
  305 {
  306         struct lpbb_softc *sc = (struct lpbb_softc *)device_get_softc(dev);
  307 
  308         return (getSDA(sc));
  309 }
  310 
  311 static void
  312 lpbb_print_child(device_t bus, device_t dev)
  313 {
  314         printf(" on %s%d", device_get_name(bus), device_get_unit(bus));
  315 
  316         return;
  317 }
  318 
  319 DRIVER_MODULE(lpbb, root, lpbb_driver, lpbb_devclass, 0, 0);

Cache object: 8d2702d776fcb1c2e85838d330ffa052


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