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/adb/adb_bus.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) 2008 Nathan Whitehorn
    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 ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  *
   25  * $FreeBSD: releng/11.1/sys/dev/adb/adb_bus.c 199888 2009-11-28 17:48:25Z nwhitehorn $
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/module.h>
   32 #include <sys/bus.h>
   33 #include <sys/conf.h>
   34 #include <sys/kernel.h>
   35 
   36 #include <machine/bus.h>
   37 
   38 #include <vm/vm.h>
   39 #include <vm/pmap.h>
   40 
   41 #include "adb.h"
   42 #include "adbvar.h"
   43 
   44 static int adb_bus_probe(device_t dev);
   45 static int adb_bus_attach(device_t dev);
   46 static int adb_bus_detach(device_t dev);
   47 static void adb_bus_enumerate(void *xdev);
   48 static void adb_probe_nomatch(device_t dev, device_t child);
   49 static int adb_print_child(device_t dev, device_t child);
   50 
   51 static int adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, uint8_t reg, int len, u_char *data, u_char *reply);
   52 
   53 static char *adb_device_string[] = {
   54         "HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc"
   55 };
   56 
   57 static device_method_t adb_bus_methods[] = {
   58         /* Device interface */
   59         DEVMETHOD(device_probe,         adb_bus_probe),
   60         DEVMETHOD(device_attach,        adb_bus_attach),
   61         DEVMETHOD(device_detach,        adb_bus_detach),
   62         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
   63         DEVMETHOD(device_suspend,       bus_generic_suspend),
   64         DEVMETHOD(device_resume,        bus_generic_resume),
   65 
   66         /* Bus Interface */
   67         DEVMETHOD(bus_probe_nomatch,    adb_probe_nomatch),
   68         DEVMETHOD(bus_print_child,      adb_print_child),
   69 
   70         { 0, 0 },
   71 };
   72 
   73 driver_t adb_driver = {
   74         "adb",
   75         adb_bus_methods,
   76         sizeof(struct adb_softc),
   77 };
   78 
   79 devclass_t adb_devclass;
   80 
   81 static int
   82 adb_bus_probe(device_t dev)
   83 {
   84         device_set_desc(dev, "Apple Desktop Bus");
   85         return (0);
   86 }
   87 
   88 static int
   89 adb_bus_attach(device_t dev)
   90 {
   91         struct adb_softc *sc = device_get_softc(dev);
   92         sc->enum_hook.ich_func = adb_bus_enumerate;
   93         sc->enum_hook.ich_arg = dev;
   94 
   95         /*
   96          * We should wait until interrupts are enabled to try to probe
   97          * the bus. Enumerating the ADB involves receiving packets,
   98          * which works best with interrupts enabled.
   99          */
  100         
  101         if (config_intrhook_establish(&sc->enum_hook) != 0)
  102                 return (ENOMEM);
  103 
  104         return (0);
  105 }
  106         
  107 static void
  108 adb_bus_enumerate(void *xdev)
  109 {
  110         device_t dev = (device_t)xdev;
  111 
  112         struct adb_softc *sc = device_get_softc(dev);
  113         uint8_t i, next_free;
  114         uint16_t r3;
  115 
  116         sc->sc_dev = dev;
  117         sc->parent = device_get_parent(dev);
  118 
  119         sc->packet_reply = 0;
  120         sc->autopoll_mask = 0;
  121         sc->sync_packet = 0xffff;
  122 
  123         /* Initialize devinfo */
  124         for (i = 0; i < 16; i++) {
  125                 sc->devinfo[i].address = i;
  126                 sc->devinfo[i].default_address = 0;
  127         }
  128         
  129         /* Reset ADB bus */
  130         adb_send_raw_packet_sync(dev,0,ADB_COMMAND_BUS_RESET,0,0,NULL,NULL);
  131         DELAY(1500);
  132 
  133         /* Enumerate bus */
  134         next_free = 8;
  135 
  136         for (i = 1; i <= 7; i++) {
  137             int8_t first_relocated = -1;
  138             int reply = 0;
  139 
  140             do {
  141                 reply = adb_send_raw_packet_sync(dev,i,
  142                             ADB_COMMAND_TALK,3,0,NULL,NULL);
  143         
  144                 if (reply) {
  145                         /* If we got a response, relocate to next_free */
  146                         r3 = sc->devinfo[i].register3;
  147                         r3 &= 0xf000;
  148                         r3 |= ((uint16_t)(next_free) & 0x000f) << 8;
  149                         r3 |= 0x00fe;
  150 
  151                         adb_send_raw_packet_sync(dev,i, ADB_COMMAND_LISTEN,3,
  152                             sizeof(uint16_t),(u_char *)(&r3),NULL);
  153 
  154                         adb_send_raw_packet_sync(dev,next_free,
  155                             ADB_COMMAND_TALK,3,0,NULL,NULL);
  156 
  157                         sc->devinfo[next_free].default_address = i;
  158                         if (first_relocated < 0)
  159                                 first_relocated = next_free;
  160 
  161                         next_free++;
  162                 } else if (first_relocated > 0) {
  163                         /* Collisions removed, relocate first device back */
  164 
  165                         r3 = sc->devinfo[i].register3;
  166                         r3 &= 0xf000;
  167                         r3 |= ((uint16_t)(i) & 0x000f) << 8;
  168                         
  169                         adb_send_raw_packet_sync(dev,first_relocated,
  170                             ADB_COMMAND_LISTEN,3,
  171                             sizeof(uint16_t),(u_char *)(&r3),NULL);
  172                         adb_send_raw_packet_sync(dev,i,
  173                             ADB_COMMAND_TALK,3,0,NULL,NULL);
  174 
  175                         sc->devinfo[i].default_address = i;
  176                         sc->devinfo[(int)(first_relocated)].default_address = 0;
  177                         break;
  178                 }
  179             } while (reply);
  180         }
  181 
  182         for (i = 0; i < 16; i++) {
  183                 if (sc->devinfo[i].default_address) {
  184                         sc->children[i] = device_add_child(dev, NULL, -1);
  185                         device_set_ivars(sc->children[i], &sc->devinfo[i]);
  186                 }
  187         }
  188 
  189         bus_generic_attach(dev);
  190 
  191         config_intrhook_disestablish(&sc->enum_hook);
  192 }
  193 
  194 static int adb_bus_detach(device_t dev)
  195 {
  196         return (bus_generic_detach(dev));
  197 }
  198         
  199 
  200 static void
  201 adb_probe_nomatch(device_t dev, device_t child)
  202 {
  203         struct adb_devinfo *dinfo;
  204 
  205         if (bootverbose) {
  206                 dinfo = device_get_ivars(child);
  207 
  208                 device_printf(dev,"ADB %s at device %d (no driver attached)\n",
  209                     adb_device_string[dinfo->default_address],dinfo->address);
  210         }
  211 }
  212 
  213 u_int
  214 adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len, 
  215     u_char *data) 
  216 {
  217         struct adb_softc *sc = device_get_softc(dev);
  218         u_char addr = command >> 4;
  219 
  220         if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) {
  221                 memcpy(&sc->devinfo[addr].register3,data,2);
  222                 sc->devinfo[addr].handler_id = data[1];
  223         }
  224 
  225         if (sc->sync_packet == command)  {
  226                 memcpy(sc->syncreg,data,(len > 8) ? 8 : len);
  227                 atomic_store_rel_int(&sc->packet_reply,len + 1);
  228                 wakeup(sc);
  229         }
  230 
  231         if (sc->children[addr] != NULL) {
  232                 ADB_RECEIVE_PACKET(sc->children[addr],status,
  233                         (command & 0x0f) >> 2,command & 0x03,len,data);
  234         }
  235         
  236         return (0);
  237 }
  238 
  239 static int
  240 adb_print_child(device_t dev, device_t child)
  241 {
  242         struct adb_devinfo *dinfo;
  243         int retval = 0;
  244         
  245         dinfo = device_get_ivars(child);
  246         
  247         retval += bus_print_child_header(dev,child);
  248         printf(" at device %d",dinfo->address);
  249         retval += bus_print_child_footer(dev, child);
  250 
  251         return (retval);
  252 }
  253 
  254 u_int 
  255 adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data)
  256 {
  257         u_char command_byte = 0;
  258         struct adb_devinfo *dinfo;
  259         struct adb_softc *sc;
  260 
  261         sc = device_get_softc(device_get_parent(dev));
  262         dinfo = device_get_ivars(dev);
  263         
  264         command_byte |= dinfo->address << 4;
  265         command_byte |= command << 2;
  266         command_byte |= reg;
  267 
  268         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
  269 
  270         return (0);
  271 }
  272 
  273 u_int
  274 adb_set_autopoll(device_t dev, u_char enable) 
  275 {
  276         struct adb_devinfo *dinfo;
  277         struct adb_softc *sc;
  278         uint16_t mod = 0;
  279 
  280         sc = device_get_softc(device_get_parent(dev));
  281         dinfo = device_get_ivars(dev);
  282         
  283         mod = enable << dinfo->address;
  284         if (enable) {
  285                 sc->autopoll_mask |= mod;
  286         } else {
  287                 mod = ~mod;
  288                 sc->autopoll_mask &= mod;
  289         }
  290 
  291         ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask);
  292 
  293         return (0);
  294 }
  295 
  296 uint8_t 
  297 adb_get_device_type(device_t dev) 
  298 {
  299         struct adb_devinfo *dinfo;
  300 
  301         dinfo = device_get_ivars(dev);
  302         return (dinfo->default_address);
  303 }
  304 
  305 uint8_t 
  306 adb_get_device_handler(device_t dev) 
  307 {
  308         struct adb_devinfo *dinfo;
  309 
  310         dinfo = device_get_ivars(dev);
  311         return (dinfo->handler_id);
  312 }
  313 
  314 static int 
  315 adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, 
  316     uint8_t reg, int len, u_char *data, u_char *reply) 
  317 {
  318         u_char command_byte = 0;
  319         struct adb_softc *sc;
  320         int result = -1;
  321         int i = 1;
  322 
  323         sc = device_get_softc(dev);
  324         
  325         command_byte |= to << 4;
  326         command_byte |= command << 2;
  327         command_byte |= reg;
  328 
  329         /* Wait if someone else has a synchronous request pending */
  330         while (!atomic_cmpset_int(&sc->sync_packet, 0xffff, command_byte))
  331                 tsleep(sc, 0, "ADB sync", hz/10);
  332 
  333         sc->packet_reply = 0;
  334         sc->sync_packet = command_byte;
  335 
  336         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
  337 
  338         while (!atomic_fetchadd_int(&sc->packet_reply,0)) {
  339                 /*
  340                  * Maybe the command got lost? Try resending and polling the 
  341                  * controller.
  342                  */
  343                 if (i % 40 == 0)
  344                         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, 
  345                             len, data, 1);
  346 
  347                 tsleep(sc, 0, "ADB sync", hz/10);
  348                 i++;
  349         }
  350 
  351         result = sc->packet_reply - 1;
  352 
  353         if (reply != NULL && result > 0)
  354                 memcpy(reply,sc->syncreg,result);
  355 
  356         /* Clear packet sync */
  357         sc->packet_reply = 0;
  358 
  359         /*
  360          * We can't match a value beyond 8 bits, so set sync_packet to 
  361          * 0xffff to avoid collisions.
  362          */
  363         atomic_set_int(&sc->sync_packet, 0xffff); 
  364 
  365         return (result);
  366 }
  367 
  368 uint8_t 
  369 adb_set_device_handler(device_t dev, uint8_t newhandler) 
  370 {
  371         struct adb_softc *sc;
  372         struct adb_devinfo *dinfo;
  373         uint16_t newr3;
  374 
  375         dinfo = device_get_ivars(dev);
  376         sc = device_get_softc(device_get_parent(dev));
  377 
  378         newr3 = dinfo->register3 & 0xff00;
  379         newr3 |= (uint16_t)(newhandler);
  380 
  381         adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, ADB_COMMAND_LISTEN, 
  382             3, sizeof(uint16_t), (u_char *)(&newr3), NULL);
  383         adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 
  384             ADB_COMMAND_TALK, 3, 0, NULL, NULL);
  385 
  386         return (dinfo->handler_id);
  387 }
  388 
  389 size_t 
  390 adb_read_register(device_t dev, u_char reg, void *data) 
  391 {
  392         struct adb_softc *sc;
  393         struct adb_devinfo *dinfo;
  394         size_t result;
  395 
  396         dinfo = device_get_ivars(dev);
  397         sc = device_get_softc(device_get_parent(dev));
  398 
  399         result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
  400                    ADB_COMMAND_TALK, reg, 0, NULL, data);
  401 
  402         return (result);
  403 }
  404 
  405 size_t 
  406 adb_write_register(device_t dev, u_char reg, size_t len, void *data) 
  407 {
  408         struct adb_softc *sc;
  409         struct adb_devinfo *dinfo;
  410         size_t result;
  411         
  412         dinfo = device_get_ivars(dev);
  413         sc = device_get_softc(device_get_parent(dev));
  414         
  415         result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
  416                    ADB_COMMAND_LISTEN, reg, len, (u_char *)data, NULL);
  417         
  418         result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
  419                    ADB_COMMAND_TALK, reg, 0, NULL, NULL);
  420 
  421         return (result);
  422 }

Cache object: b04c28346381835462a5670065fde229


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