root/drivers/input/serio/hp_sdc_mlc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hp_sdc_mlc_isr
  2. hp_sdc_mlc_in
  3. hp_sdc_mlc_cts
  4. hp_sdc_mlc_out
  5. hp_sdc_mlc_init
  6. hp_sdc_mlc_exit

   1 /*
   2  * Access to HP-HIL MLC through HP System Device Controller.
   3  *
   4  * Copyright (c) 2001 Brian S. Julin
   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  *    without modification.
  13  * 2. The name of the author may not be used to endorse or promote products
  14  *    derived from this software without specific prior written permission.
  15  *
  16  * Alternatively, this software may be distributed under the terms of the
  17  * GNU General Public License ("GPL").
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
  23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28  *
  29  * References:
  30  * HP-HIL Technical Reference Manual.  Hewlett Packard Product No. 45918A
  31  * System Device Controller Microprocessor Firmware Theory of Operation
  32  *      for Part Number 1820-4784 Revision B.  Dwg No. A-1820-4784-2
  33  *
  34  */
  35 
  36 #include <linux/hil_mlc.h>
  37 #include <linux/hp_sdc.h>
  38 #include <linux/errno.h>
  39 #include <linux/kernel.h>
  40 #include <linux/module.h>
  41 #include <linux/init.h>
  42 #include <linux/string.h>
  43 #include <linux/semaphore.h>
  44 
  45 #define PREFIX "HP SDC MLC: "
  46 
  47 static hil_mlc hp_sdc_mlc;
  48 
  49 MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
  50 MODULE_DESCRIPTION("Glue for onboard HIL MLC in HP-PARISC machines");
  51 MODULE_LICENSE("Dual BSD/GPL");
  52 
  53 static struct hp_sdc_mlc_priv_s {
  54         int emtestmode;
  55         hp_sdc_transaction trans;
  56         u8 tseq[16];
  57         int got5x;
  58 } hp_sdc_mlc_priv;
  59 
  60 /************************* Interrupt context ******************************/
  61 static void hp_sdc_mlc_isr (int irq, void *dev_id,
  62                             uint8_t status, uint8_t data)
  63 {
  64         int idx;
  65         hil_mlc *mlc = &hp_sdc_mlc;
  66 
  67         write_lock(&mlc->lock);
  68         if (mlc->icount < 0) {
  69                 printk(KERN_WARNING PREFIX "HIL Overflow!\n");
  70                 up(&mlc->isem);
  71                 goto out;
  72         }
  73         idx = 15 - mlc->icount;
  74         if ((status & HP_SDC_STATUS_IRQMASK) == HP_SDC_STATUS_HILDATA) {
  75                 mlc->ipacket[idx] |= data | HIL_ERR_INT;
  76                 mlc->icount--;
  77                 if (hp_sdc_mlc_priv.got5x || !idx)
  78                         goto check;
  79                 if ((mlc->ipacket[idx - 1] & HIL_PKT_ADDR_MASK) !=
  80                     (mlc->ipacket[idx] & HIL_PKT_ADDR_MASK)) {
  81                         mlc->ipacket[idx] &= ~HIL_PKT_ADDR_MASK;
  82                         mlc->ipacket[idx] |= (mlc->ipacket[idx - 1]
  83                                                 & HIL_PKT_ADDR_MASK);
  84                 }
  85                 goto check;
  86         }
  87         /* We know status is 5X */
  88         if (data & HP_SDC_HIL_ISERR)
  89                 goto err;
  90         mlc->ipacket[idx] =
  91                 (data & HP_SDC_HIL_R1MASK) << HIL_PKT_ADDR_SHIFT;
  92         hp_sdc_mlc_priv.got5x = 1;
  93         goto out;
  94 
  95  check:
  96         hp_sdc_mlc_priv.got5x = 0;
  97         if (mlc->imatch == 0)
  98                 goto done;
  99         if ((mlc->imatch == (HIL_ERR_INT | HIL_PKT_CMD | HIL_CMD_POL))
 100             && (mlc->ipacket[idx] == (mlc->imatch | idx)))
 101                 goto done;
 102         if (mlc->ipacket[idx] == mlc->imatch)
 103                 goto done;
 104         goto out;
 105 
 106  err:
 107         printk(KERN_DEBUG PREFIX "err code %x\n", data);
 108 
 109         switch (data) {
 110         case HP_SDC_HIL_RC_DONE:
 111                 printk(KERN_WARNING PREFIX "Bastard SDC reconfigured loop!\n");
 112                 break;
 113 
 114         case HP_SDC_HIL_ERR:
 115                 mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_PERR |
 116                                         HIL_ERR_FERR | HIL_ERR_FOF;
 117                 break;
 118 
 119         case HP_SDC_HIL_TO:
 120                 mlc->ipacket[idx] |= HIL_ERR_INT | HIL_ERR_LERR;
 121                 break;
 122 
 123         case HP_SDC_HIL_RC:
 124                 printk(KERN_WARNING PREFIX "Bastard SDC decided to reconfigure loop!\n");
 125                 break;
 126 
 127         default:
 128                 printk(KERN_WARNING PREFIX "Unknown HIL Error status (%x)!\n", data);
 129                 break;
 130         }
 131 
 132         /* No more data will be coming due to an error. */
 133  done:
 134         tasklet_schedule(mlc->tasklet);
 135         up(&mlc->isem);
 136  out:
 137         write_unlock(&mlc->lock);
 138 }
 139 
 140 
 141 /******************** Tasklet or userspace context functions ****************/
 142 
 143 static int hp_sdc_mlc_in(hil_mlc *mlc, suseconds_t timeout)
 144 {
 145         struct hp_sdc_mlc_priv_s *priv;
 146         int rc = 2;
 147 
 148         priv = mlc->priv;
 149 
 150         /* Try to down the semaphore */
 151         if (down_trylock(&mlc->isem)) {
 152                 if (priv->emtestmode) {
 153                         mlc->ipacket[0] =
 154                                 HIL_ERR_INT | (mlc->opacket &
 155                                                (HIL_PKT_CMD |
 156                                                 HIL_PKT_ADDR_MASK |
 157                                                 HIL_PKT_DATA_MASK));
 158                         mlc->icount = 14;
 159                         /* printk(KERN_DEBUG PREFIX ">[%x]\n", mlc->ipacket[0]); */
 160                         goto wasup;
 161                 }
 162                 if (time_after(jiffies, mlc->instart + mlc->intimeout)) {
 163                         /*      printk("!%i %i",
 164                                 tv.tv_usec - mlc->instart.tv_usec,
 165                                 mlc->intimeout);
 166                          */
 167                         rc = 1;
 168                         up(&mlc->isem);
 169                 }
 170                 goto done;
 171         }
 172  wasup:
 173         up(&mlc->isem);
 174         rc = 0;
 175  done:
 176         return rc;
 177 }
 178 
 179 static int hp_sdc_mlc_cts(hil_mlc *mlc)
 180 {
 181         struct hp_sdc_mlc_priv_s *priv;
 182 
 183         priv = mlc->priv;
 184 
 185         /* Try to down the semaphores -- they should be up. */
 186         BUG_ON(down_trylock(&mlc->isem));
 187         BUG_ON(down_trylock(&mlc->osem));
 188 
 189         up(&mlc->isem);
 190         up(&mlc->osem);
 191 
 192         if (down_trylock(&mlc->csem)) {
 193                 if (priv->trans.act.semaphore != &mlc->csem)
 194                         goto poll;
 195                 else
 196                         goto busy;
 197         }
 198 
 199         if (!(priv->tseq[4] & HP_SDC_USE_LOOP))
 200                 goto done;
 201 
 202  poll:
 203         priv->trans.act.semaphore = &mlc->csem;
 204         priv->trans.actidx = 0;
 205         priv->trans.idx = 1;
 206         priv->trans.endidx = 5;
 207         priv->tseq[0] =
 208                 HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
 209         priv->tseq[1] = HP_SDC_CMD_READ_USE;
 210         priv->tseq[2] = 1;
 211         priv->tseq[3] = 0;
 212         priv->tseq[4] = 0;
 213         __hp_sdc_enqueue_transaction(&priv->trans);
 214  busy:
 215         return 1;
 216  done:
 217         priv->trans.act.semaphore = &mlc->osem;
 218         up(&mlc->csem);
 219         return 0;
 220 }
 221 
 222 static void hp_sdc_mlc_out(hil_mlc *mlc)
 223 {
 224         struct hp_sdc_mlc_priv_s *priv;
 225 
 226         priv = mlc->priv;
 227 
 228         /* Try to down the semaphore -- it should be up. */
 229         BUG_ON(down_trylock(&mlc->osem));
 230 
 231         if (mlc->opacket & HIL_DO_ALTER_CTRL)
 232                 goto do_control;
 233 
 234  do_data:
 235         if (priv->emtestmode) {
 236                 up(&mlc->osem);
 237                 return;
 238         }
 239         /* Shouldn't be sending commands when loop may be busy */
 240         BUG_ON(down_trylock(&mlc->csem));
 241         up(&mlc->csem);
 242 
 243         priv->trans.actidx = 0;
 244         priv->trans.idx = 1;
 245         priv->trans.act.semaphore = &mlc->osem;
 246         priv->trans.endidx = 6;
 247         priv->tseq[0] =
 248                 HP_SDC_ACT_DATAREG | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_SEMAPHORE;
 249         priv->tseq[1] = 0x7;
 250         priv->tseq[2] =
 251                 (mlc->opacket &
 252                  (HIL_PKT_ADDR_MASK | HIL_PKT_CMD))
 253                    >> HIL_PKT_ADDR_SHIFT;
 254         priv->tseq[3] =
 255                 (mlc->opacket & HIL_PKT_DATA_MASK)
 256                   >> HIL_PKT_DATA_SHIFT;
 257         priv->tseq[4] = 0;  /* No timeout */
 258         if (priv->tseq[3] == HIL_CMD_DHR)
 259                 priv->tseq[4] = 1;
 260         priv->tseq[5] = HP_SDC_CMD_DO_HIL;
 261         goto enqueue;
 262 
 263  do_control:
 264         priv->emtestmode = mlc->opacket & HIL_CTRL_TEST;
 265 
 266         /* we cannot emulate this, it should not be used. */
 267         BUG_ON((mlc->opacket & (HIL_CTRL_APE | HIL_CTRL_IPF)) == HIL_CTRL_APE);
 268 
 269         if ((mlc->opacket & HIL_CTRL_ONLY) == HIL_CTRL_ONLY)
 270                 goto control_only;
 271 
 272         /* Should not send command/data after engaging APE */
 273         BUG_ON(mlc->opacket & HIL_CTRL_APE);
 274 
 275         /* Disengaging APE this way would not be valid either since
 276          * the loop must be allowed to idle.
 277          *
 278          * So, it works out that we really never actually send control
 279          * and data when using SDC, we just send the data.
 280          */
 281         goto do_data;
 282 
 283  control_only:
 284         priv->trans.actidx = 0;
 285         priv->trans.idx = 1;
 286         priv->trans.act.semaphore = &mlc->osem;
 287         priv->trans.endidx = 4;
 288         priv->tseq[0] =
 289           HP_SDC_ACT_PRECMD | HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
 290         priv->tseq[1] = HP_SDC_CMD_SET_LPC;
 291         priv->tseq[2] = 1;
 292         /* priv->tseq[3] = (mlc->ddc + 1) | HP_SDC_LPS_ACSUCC; */
 293         priv->tseq[3] = 0;
 294         if (mlc->opacket & HIL_CTRL_APE) {
 295                 priv->tseq[3] |= HP_SDC_LPC_APE_IPF;
 296                 BUG_ON(down_trylock(&mlc->csem));
 297         }
 298  enqueue:
 299         hp_sdc_enqueue_transaction(&priv->trans);
 300 }
 301 
 302 static int __init hp_sdc_mlc_init(void)
 303 {
 304         hil_mlc *mlc = &hp_sdc_mlc;
 305         int err;
 306 
 307 #ifdef __mc68000__
 308         if (!MACH_IS_HP300)
 309                 return -ENODEV;
 310 #endif
 311 
 312         printk(KERN_INFO PREFIX "Registering the System Domain Controller's HIL MLC.\n");
 313 
 314         hp_sdc_mlc_priv.emtestmode = 0;
 315         hp_sdc_mlc_priv.trans.seq = hp_sdc_mlc_priv.tseq;
 316         hp_sdc_mlc_priv.trans.act.semaphore = &mlc->osem;
 317         hp_sdc_mlc_priv.got5x = 0;
 318 
 319         mlc->cts = &hp_sdc_mlc_cts;
 320         mlc->in = &hp_sdc_mlc_in;
 321         mlc->out = &hp_sdc_mlc_out;
 322         mlc->priv = &hp_sdc_mlc_priv;
 323 
 324         err = hil_mlc_register(mlc);
 325         if (err) {
 326                 printk(KERN_WARNING PREFIX "Failed to register MLC structure with hil_mlc\n");
 327                 return err;
 328         }
 329 
 330         if (hp_sdc_request_hil_irq(&hp_sdc_mlc_isr)) {
 331                 printk(KERN_WARNING PREFIX "Request for raw HIL ISR hook denied\n");
 332                 if (hil_mlc_unregister(mlc))
 333                         printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
 334                                 "This is bad.  Could cause an oops.\n");
 335                 return -EBUSY;
 336         }
 337 
 338         return 0;
 339 }
 340 
 341 static void __exit hp_sdc_mlc_exit(void)
 342 {
 343         hil_mlc *mlc = &hp_sdc_mlc;
 344 
 345         if (hp_sdc_release_hil_irq(&hp_sdc_mlc_isr))
 346                 printk(KERN_ERR PREFIX "Failed to release the raw HIL ISR hook.\n"
 347                         "This is bad.  Could cause an oops.\n");
 348 
 349         if (hil_mlc_unregister(mlc))
 350                 printk(KERN_ERR PREFIX "Failed to unregister MLC structure with hil_mlc.\n"
 351                         "This is bad.  Could cause an oops.\n");
 352 }
 353 
 354 module_init(hp_sdc_mlc_init);
 355 module_exit(hp_sdc_mlc_exit);

/* [<][>][^][v][top][bottom][index][help] */