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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (C) 2008 Nathan Whitehorn
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  *
   27  * $FreeBSD$
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/module.h>
   34 #include <sys/bus.h>
   35 #include <sys/conf.h>
   36 #include <sys/kernel.h>
   37 
   38 #include <machine/bus.h>
   39 
   40 #include <vm/vm.h>
   41 #include <vm/pmap.h>
   42 
   43 #include "adb.h"
   44 #include "adbvar.h"
   45 
   46 static int adb_bus_probe(device_t dev);
   47 static int adb_bus_attach(device_t dev);
   48 static int adb_bus_detach(device_t dev);
   49 static void adb_bus_enumerate(void *xdev);
   50 static void adb_probe_nomatch(device_t dev, device_t child);
   51 static int adb_print_child(device_t dev, device_t child);
   52 
   53 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);
   54 
   55 static char *adb_device_string[] = {
   56         "HOST", "dongle", "keyboard", "mouse", "tablet", "modem", "RESERVED", "misc"
   57 };
   58 
   59 static device_method_t adb_bus_methods[] = {
   60         /* Device interface */
   61         DEVMETHOD(device_probe,         adb_bus_probe),
   62         DEVMETHOD(device_attach,        adb_bus_attach),
   63         DEVMETHOD(device_detach,        adb_bus_detach),
   64         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
   65         DEVMETHOD(device_suspend,       bus_generic_suspend),
   66         DEVMETHOD(device_resume,        bus_generic_resume),
   67 
   68         /* Bus Interface */
   69         DEVMETHOD(bus_probe_nomatch,    adb_probe_nomatch),
   70         DEVMETHOD(bus_print_child,      adb_print_child),
   71 
   72         { 0, 0 },
   73 };
   74 
   75 driver_t adb_driver = {
   76         "adb",
   77         adb_bus_methods,
   78         sizeof(struct adb_softc),
   79 };
   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 static void
  200 adb_probe_nomatch(device_t dev, device_t child)
  201 {
  202         struct adb_devinfo *dinfo;
  203 
  204         if (bootverbose) {
  205                 dinfo = device_get_ivars(child);
  206 
  207                 device_printf(dev,"ADB %s at device %d (no driver attached)\n",
  208                     adb_device_string[dinfo->default_address],dinfo->address);
  209         }
  210 }
  211 
  212 u_int
  213 adb_receive_raw_packet(device_t dev, u_char status, u_char command, int len, 
  214     u_char *data) 
  215 {
  216         struct adb_softc *sc = device_get_softc(dev);
  217         u_char addr = command >> 4;
  218 
  219         if (len > 0 && (command & 0x0f) == ((ADB_COMMAND_TALK << 2) | 3)) {
  220                 memcpy(&sc->devinfo[addr].register3,data,2);
  221                 sc->devinfo[addr].handler_id = data[1];
  222         }
  223 
  224         if (sc->sync_packet == command)  {
  225                 memcpy(sc->syncreg,data,(len > 8) ? 8 : len);
  226                 atomic_store_rel_int(&sc->packet_reply,len + 1);
  227                 wakeup(sc);
  228         }
  229 
  230         if (sc->children[addr] != NULL) {
  231                 ADB_RECEIVE_PACKET(sc->children[addr],status,
  232                         (command & 0x0f) >> 2,command & 0x03,len,data);
  233         }
  234 
  235         return (0);
  236 }
  237 
  238 static int
  239 adb_print_child(device_t dev, device_t child)
  240 {
  241         struct adb_devinfo *dinfo;
  242         int retval = 0;
  243 
  244         dinfo = device_get_ivars(child);
  245 
  246         retval += bus_print_child_header(dev,child);
  247         printf(" at device %d",dinfo->address);
  248         retval += bus_print_child_footer(dev, child);
  249 
  250         return (retval);
  251 }
  252 
  253 u_int 
  254 adb_send_packet(device_t dev, u_char command, u_char reg, int len, u_char *data)
  255 {
  256         u_char command_byte = 0;
  257         struct adb_devinfo *dinfo;
  258         struct adb_softc *sc;
  259 
  260         sc = device_get_softc(device_get_parent(dev));
  261         dinfo = device_get_ivars(dev);
  262 
  263         command_byte |= dinfo->address << 4;
  264         command_byte |= command << 2;
  265         command_byte |= reg;
  266 
  267         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
  268 
  269         return (0);
  270 }
  271 
  272 u_int
  273 adb_set_autopoll(device_t dev, u_char enable) 
  274 {
  275         struct adb_devinfo *dinfo;
  276         struct adb_softc *sc;
  277         uint16_t mod = 0;
  278 
  279         sc = device_get_softc(device_get_parent(dev));
  280         dinfo = device_get_ivars(dev);
  281 
  282         mod = enable << dinfo->address;
  283         if (enable) {
  284                 sc->autopoll_mask |= mod;
  285         } else {
  286                 mod = ~mod;
  287                 sc->autopoll_mask &= mod;
  288         }
  289 
  290         ADB_HB_SET_AUTOPOLL_MASK(sc->parent,sc->autopoll_mask);
  291 
  292         return (0);
  293 }
  294 
  295 uint8_t 
  296 adb_get_device_type(device_t dev) 
  297 {
  298         struct adb_devinfo *dinfo;
  299 
  300         dinfo = device_get_ivars(dev);
  301         return (dinfo->default_address);
  302 }
  303 
  304 uint8_t 
  305 adb_get_device_handler(device_t dev) 
  306 {
  307         struct adb_devinfo *dinfo;
  308 
  309         dinfo = device_get_ivars(dev);
  310         return (dinfo->handler_id);
  311 }
  312 
  313 static int 
  314 adb_send_raw_packet_sync(device_t dev, uint8_t to, uint8_t command, 
  315     uint8_t reg, int len, u_char *data, u_char *reply) 
  316 {
  317         u_char command_byte = 0;
  318         struct adb_softc *sc;
  319         int result = -1;
  320         int i = 1;
  321 
  322         sc = device_get_softc(dev);
  323 
  324         command_byte |= to << 4;
  325         command_byte |= command << 2;
  326         command_byte |= reg;
  327 
  328         /* Wait if someone else has a synchronous request pending */
  329         while (!atomic_cmpset_int(&sc->sync_packet, 0xffff, command_byte))
  330                 tsleep(sc, 0, "ADB sync", hz/10);
  331 
  332         sc->packet_reply = 0;
  333         sc->sync_packet = command_byte;
  334 
  335         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, len, data, 1);
  336 
  337         while (!atomic_fetchadd_int(&sc->packet_reply,0)) {
  338                 /*
  339                  * Maybe the command got lost? Try resending and polling the 
  340                  * controller.
  341                  */
  342                 if (i % 40 == 0)
  343                         ADB_HB_SEND_RAW_PACKET(sc->parent, command_byte, 
  344                             len, data, 1);
  345 
  346                 tsleep(sc, 0, "ADB sync", hz/10);
  347                 i++;
  348         }
  349 
  350         result = sc->packet_reply - 1;
  351 
  352         if (reply != NULL && result > 0)
  353                 memcpy(reply,sc->syncreg,result);
  354 
  355         /* Clear packet sync */
  356         sc->packet_reply = 0;
  357 
  358         /*
  359          * We can't match a value beyond 8 bits, so set sync_packet to 
  360          * 0xffff to avoid collisions.
  361          */
  362         atomic_set_int(&sc->sync_packet, 0xffff); 
  363 
  364         return (result);
  365 }
  366 
  367 uint8_t 
  368 adb_set_device_handler(device_t dev, uint8_t newhandler) 
  369 {
  370         struct adb_softc *sc;
  371         struct adb_devinfo *dinfo;
  372         uint16_t newr3;
  373 
  374         dinfo = device_get_ivars(dev);
  375         sc = device_get_softc(device_get_parent(dev));
  376 
  377         newr3 = dinfo->register3 & 0xff00;
  378         newr3 |= (uint16_t)(newhandler);
  379 
  380         adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, ADB_COMMAND_LISTEN, 
  381             3, sizeof(uint16_t), (u_char *)(&newr3), NULL);
  382         adb_send_raw_packet_sync(sc->sc_dev,dinfo->address, 
  383             ADB_COMMAND_TALK, 3, 0, NULL, NULL);
  384 
  385         return (dinfo->handler_id);
  386 }
  387 
  388 size_t 
  389 adb_read_register(device_t dev, u_char reg, void *data) 
  390 {
  391         struct adb_softc *sc;
  392         struct adb_devinfo *dinfo;
  393         size_t result;
  394 
  395         dinfo = device_get_ivars(dev);
  396         sc = device_get_softc(device_get_parent(dev));
  397 
  398         result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
  399                    ADB_COMMAND_TALK, reg, 0, NULL, data);
  400 
  401         return (result);
  402 }
  403 
  404 size_t 
  405 adb_write_register(device_t dev, u_char reg, size_t len, void *data) 
  406 {
  407         struct adb_softc *sc;
  408         struct adb_devinfo *dinfo;
  409         size_t result;
  410 
  411         dinfo = device_get_ivars(dev);
  412         sc = device_get_softc(device_get_parent(dev));
  413 
  414         result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
  415                    ADB_COMMAND_LISTEN, reg, len, (u_char *)data, NULL);
  416 
  417         result = adb_send_raw_packet_sync(sc->sc_dev,dinfo->address,
  418                    ADB_COMMAND_TALK, reg, 0, NULL, NULL);
  419 
  420         return (result);
  421 }

Cache object: 007656114b37e68e3b035911ac647133


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