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/ic/spic.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: spic.c,v 1.15 2008/05/04 16:13:35 xtraeme Exp $        */
    2 
    3 /*
    4  * Copyright (c) 2002 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Lennart Augustsson (lennart@augustsson.net) at
    9  * Carlstedt Research & Technology.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   30  * POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 /*
   34  * The SPIC is used on some Sony Vaios to handle the jog dial and other
   35  * peripherals.
   36  * The protocol used by the SPIC seems to vary wildly among the different
   37  * models, and I've found no documentation.
   38  * This file handles the jog dial on the SRX77 model, and perhaps nothing
   39  * else.
   40  *
   41  * The general way of talking to the SPIC was gleaned from the Linux and
   42  * FreeBSD drivers.  The hex numbers were taken from these drivers (they
   43  * come from reverese engineering.)
   44  *
   45  * TODO:
   46  *   Make it handle more models.
   47  *   Figure out why the interrupt mode doesn't work.
   48  */
   49 
   50 
   51 #include <sys/cdefs.h>
   52 __KERNEL_RCSID(0, "$NetBSD: spic.c,v 1.15 2008/05/04 16:13:35 xtraeme Exp $");
   53 
   54 #include <sys/param.h>
   55 #include <sys/systm.h>
   56 #include <sys/device.h>
   57 #include <sys/proc.h>
   58 #include <sys/kernel.h>
   59 #include <sys/callout.h>
   60 
   61 #include <sys/bus.h>
   62 
   63 #include <dev/sysmon/sysmonvar.h>
   64 
   65 #include <dev/ic/spicvar.h>
   66 
   67 #include <dev/wscons/wsconsio.h>
   68 #include <dev/wscons/wsmousevar.h>
   69 
   70 #define SPIC_EVENT_BRIGHTNESS_DOWN      0x15
   71 #define SPIC_EVENT_BRIGHTNESS_UP        0x16
   72 
   73 #define POLLRATE (hz/30)
   74 
   75 /* Some hardware constants */
   76 #define SPIC_PORT1 0
   77 #define SPIC_PORT2 4
   78 
   79 #ifdef SPIC_DEBUG
   80 int spicdebug = 0;
   81 #endif
   82 
   83 static int spicerror = 0;
   84 
   85 static int      spic_enable(void *);
   86 static void     spic_disable(void *);
   87 static int      spic_ioctl(void *, u_long, void *, int, struct lwp *);
   88 
   89 static const struct wsmouse_accessops spic_accessops = {
   90         spic_enable,
   91         spic_ioctl,
   92         spic_disable,
   93 };
   94 
   95 #define SPIC_COMMAND(quiet, command) do { \
   96         unsigned int n = 10000; \
   97         while (--n && (command)) \
   98                 delay(1); \
   99         if (n == 0 && !(quiet)) { \
  100                 printf("spic0: command failed at line %d\n", __LINE__); \
  101                 spicerror++; \
  102         } \
  103 } while (0)
  104 
  105 #if 0
  106 #define INB(sc, p) (delay(100), printf("inb(%x)=%x\n", (uint)sc->sc_ioh+p, bus_space_read_1(sc->sc_iot, sc->sc_ioh, p)), delay(100), bus_space_read_1(sc->sc_iot, sc->sc_ioh, (p)))
  107 #define OUTB(sc, v, p) do { delay(100); bus_space_write_1(sc->sc_iot, sc->sc_ioh, (p), (v)); printf("outb(%x, %x)\n", (uint)sc->sc_ioh+p, v); } while(0)
  108 #else
  109 #define INB(sc, p) (delay(100), bus_space_read_1(sc->sc_iot, sc->sc_ioh, (p)))
  110 #define OUTB(sc, v, p) do { delay(100); bus_space_write_1(sc->sc_iot, sc->sc_ioh, (p), (v)); } while(0)
  111 #endif
  112 
  113 static u_int8_t
  114 spic_call1(struct spic_softc *sc, u_int8_t dev)
  115 {
  116         u_int8_t v1, v2;
  117 
  118         SPIC_COMMAND(0, INB(sc, SPIC_PORT2) & 2);
  119         OUTB(sc, dev, SPIC_PORT2);
  120         v1 = INB(sc, SPIC_PORT2);
  121         v2 = INB(sc, SPIC_PORT1);
  122         return v2;
  123 }
  124 
  125 static u_int8_t
  126 spic_call2(struct spic_softc *sc, u_int8_t dev, u_int8_t fn)
  127 {
  128         u_int8_t v1;
  129 
  130         SPIC_COMMAND(0, INB(sc, SPIC_PORT2) & 2);
  131         OUTB(sc, dev, SPIC_PORT2);
  132         SPIC_COMMAND(0, INB(sc, SPIC_PORT2) & 2);
  133         OUTB(sc, fn, SPIC_PORT1);
  134         v1 = INB(sc, SPIC_PORT1);
  135         return v1;
  136 }
  137 
  138 /* Interrupt handler: some event is available */
  139 int
  140 spic_intr(void *v) {
  141         struct spic_softc *sc = v;
  142         u_int8_t v1, v2;
  143         int dz, buttons;
  144 
  145         v1 = INB(sc, SPIC_PORT1);
  146         v2 = INB(sc, SPIC_PORT2);
  147 
  148         /* Handle lid switch */
  149         if (v2 == 0x30) {
  150                 switch (v1) {
  151                 case 0x50:      /* opened */
  152                         sysmon_pswitch_event(&sc->sc_smpsw[SPIC_PSWITCH_LID],
  153                             PSWITCH_EVENT_RELEASED);
  154                         goto skip;
  155                         break;
  156                 case 0x51:      /* closed */
  157                         sysmon_pswitch_event(&sc->sc_smpsw[SPIC_PSWITCH_LID],
  158                             PSWITCH_EVENT_PRESSED);
  159                         goto skip;
  160                         break;
  161                 default:
  162                         aprint_debug_dev(sc->sc_dev, "unknown lid event 0x%02x\n", v1);
  163                         goto skip;
  164                         break;
  165                 }
  166         }
  167 
  168         /* Handle suspend/hibernate buttons */
  169         if (v2 == 0x20) {
  170                 switch (v1) {
  171                 case 0x10:      /* suspend */
  172                         sysmon_pswitch_event(
  173                             &sc->sc_smpsw[SPIC_PSWITCH_SUSPEND],
  174                             PSWITCH_EVENT_PRESSED);
  175                         goto skip;
  176                         break;
  177                 case 0x1c:      /* hibernate */
  178                         sysmon_pswitch_event(
  179                             &sc->sc_smpsw[SPIC_PSWITCH_HIBERNATE],
  180                             PSWITCH_EVENT_PRESSED);
  181                         goto skip;
  182                         break;
  183                 }
  184         }
  185 
  186         buttons = 0;
  187         if (v1 & 0x40)
  188                 buttons |= 1 << 1;
  189         if (v1 & 0x20)
  190                 buttons |= 1 << 5;
  191         dz = v1 & 0x1f;
  192         switch (dz) {
  193         case 0:
  194         case 1:
  195         case 2:
  196         case 3:
  197                 break;
  198         case 0x1f:
  199         case 0x1e:
  200         case 0x1d:
  201                 dz -= 0x20;
  202                 break;
  203         case SPIC_EVENT_BRIGHTNESS_UP:
  204                 pmf_event_inject(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_UP);
  205                 break;
  206         case SPIC_EVENT_BRIGHTNESS_DOWN:
  207                 pmf_event_inject(sc->sc_dev, PMFE_DISPLAY_BRIGHTNESS_DOWN);
  208                 break;
  209         default:
  210                 printf("spic0: v1=0x%02x v2=0x%02x\n", v1, v2);
  211                 goto skip;
  212         }
  213 
  214         if (!sc->sc_enabled) {
  215                 /*printf("spic: not enabled\n");*/
  216                 goto skip;
  217         }
  218 
  219         if (dz != 0 || buttons != sc->sc_buttons) {
  220 #ifdef SPIC_DEBUG
  221                 if (spicdebug)
  222                         printf("spic: but=0x%x dz=%d v1=0x%02x v2=0x%02x\n",
  223                                buttons, dz, v1, v2);
  224 #endif
  225                 sc->sc_buttons = buttons;
  226                 if (sc->sc_wsmousedev != NULL) {
  227                         wsmouse_input(sc->sc_wsmousedev, buttons, 0, 0, dz, 0,
  228                                       WSMOUSE_INPUT_DELTA);
  229                 }
  230         }
  231 
  232 skip:
  233         spic_call2(sc, 0x81, 0xff); /* Clear event */
  234         return (1);
  235 }
  236 
  237 static void
  238 spictimeout(void *v)
  239 {
  240         struct spic_softc *sc = v;
  241         int s;
  242 
  243         if (spicerror >= 3)
  244                 return;
  245 
  246         s = spltty();
  247         spic_intr(v);
  248         splx(s);
  249         callout_reset(&sc->sc_poll, POLLRATE, spictimeout, sc);
  250 }
  251 
  252 void
  253 spic_attach(struct spic_softc *sc)
  254 {
  255         struct wsmousedev_attach_args a;
  256         int i, rv;
  257 
  258 #ifdef SPIC_DEBUG
  259         if (spicdebug)
  260                 printf("spic_attach %x %x\n", sc->sc_iot, (uint)sc->sc_ioh);
  261 #endif
  262 
  263         callout_init(&sc->sc_poll, 0);
  264 
  265         spic_call1(sc, 0x82);
  266         spic_call2(sc, 0x81, 0xff);
  267         spic_call1(sc, 0x92);   /* or 0x82 */
  268 
  269         a.accessops = &spic_accessops;
  270         a.accesscookie = sc;
  271         sc->sc_wsmousedev = config_found(sc->sc_dev, &a, wsmousedevprint);
  272 
  273         sc->sc_smpsw[SPIC_PSWITCH_LID].smpsw_name = "spiclid0";
  274         sc->sc_smpsw[SPIC_PSWITCH_LID].smpsw_type = PSWITCH_TYPE_LID;
  275         sc->sc_smpsw[SPIC_PSWITCH_SUSPEND].smpsw_name = "spicsuspend0";
  276         sc->sc_smpsw[SPIC_PSWITCH_SUSPEND].smpsw_type = PSWITCH_TYPE_SLEEP;
  277         sc->sc_smpsw[SPIC_PSWITCH_HIBERNATE].smpsw_name = "spichibernate0";
  278         sc->sc_smpsw[SPIC_PSWITCH_HIBERNATE].smpsw_type = PSWITCH_TYPE_SLEEP;
  279 
  280         for (i = 0; i < SPIC_NPSWITCH; i++) {
  281                 rv = sysmon_pswitch_register(&sc->sc_smpsw[i]);
  282                 if (rv != 0)
  283                         aprint_error_dev(sc->sc_dev, "unable to register %s with sysmon\n",
  284                             sc->sc_smpsw[i].smpsw_name);
  285         }
  286 
  287         callout_reset(&sc->sc_poll, POLLRATE, spictimeout, sc);
  288 
  289         return;
  290 }
  291 
  292 bool
  293 spic_suspend(device_t dev PMF_FN_ARGS)
  294 {
  295         struct spic_softc *sc = device_private(dev);
  296 
  297         callout_stop(&sc->sc_poll);
  298 
  299         return true;
  300 }
  301 
  302 bool
  303 spic_resume(device_t dev PMF_FN_ARGS)
  304 {
  305         struct spic_softc *sc = device_private(dev);
  306 
  307         spic_call1(sc, 0x82);
  308         spic_call2(sc, 0x81, 0xff);
  309         spic_call1(sc, 0x92);   /* or 0x82 */
  310 
  311         callout_reset(&sc->sc_poll, POLLRATE, spictimeout, sc);
  312         return true;
  313 }
  314 
  315 static int
  316 spic_enable(void *v)
  317 {
  318         struct spic_softc *sc = v;
  319 
  320         if (sc->sc_enabled)
  321                 return (EBUSY);
  322 
  323         sc->sc_enabled = 1;
  324         sc->sc_buttons = 0;
  325 
  326 #ifdef SPIC_DEBUG
  327         if (spicdebug)
  328                 printf("spic_enable\n");
  329 #endif
  330 
  331         return (0);
  332 }
  333 
  334 static void
  335 spic_disable(void *v)
  336 {
  337         struct spic_softc *sc = v;
  338 
  339 #ifdef DIAGNOSTIC
  340         if (!sc->sc_enabled) {
  341                 printf("spic_disable: not enabled\n");
  342                 return;
  343         }
  344 #endif
  345 
  346         sc->sc_enabled = 0;
  347 
  348 #ifdef SPIC_DEBUG
  349         if (spicdebug)
  350                 printf("spic_disable\n");
  351 #endif
  352 }
  353 
  354 static int
  355 spic_ioctl(void *v, u_long cmd, void *data,
  356     int flag, struct lwp *l)
  357 {
  358         switch (cmd) {
  359         case WSMOUSEIO_GTYPE:
  360                 /* XXX this is not really correct */
  361                 *(u_int *)data = WSMOUSE_TYPE_PS2;
  362                 return (0);
  363         }
  364 
  365         return (-1);
  366 }

Cache object: 7285c1a2bbf37baf5ac4ab3156273b0b


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