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

Cache object: 82472a51114472cebb4bb0c34a2d9c17


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