root/drivers/input/serio/hil_mlc.c

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

DEFINITIONS

This source file includes following definitions.
  1. hil_mlc_clear_di_map
  2. hil_mlc_clear_di_scratch
  3. hil_mlc_copy_di_scratch
  4. hil_mlc_match_di_scratch
  5. hil_mlc_find_free_di
  6. hil_mlc_clean_serio_map
  7. hil_mlc_send_polls
  8. hilse_match
  9. hilse_init_lcv
  10. hilse_inc_lcv
  11. hilse_set_lcv
  12. hilse_set_ddi
  13. hilse_dec_ddi
  14. hilse_inc_ddi
  15. hilse_take_idd
  16. hilse_take_rsc
  17. hilse_take_exd
  18. hilse_take_rnm
  19. hilse_operate
  20. hilse_setup_input
  21. hilse_donode
  22. hil_mlcs_process
  23. hil_mlcs_timer
  24. hil_mlc_serio_write
  25. hil_mlc_serio_open
  26. hil_mlc_serio_close
  27. hil_mlc_register
  28. hil_mlc_unregister
  29. hil_mlc_init
  30. hil_mlc_exit

   1 /*
   2  * HIL MLC state machine and serio interface driver
   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  *
  32  *
  33  *      Driver theory of operation:
  34  *
  35  *      Some access methods and an ISR is defined by the sub-driver
  36  *      (e.g. hp_sdc_mlc.c).  These methods are expected to provide a
  37  *      few bits of logic in addition to raw access to the HIL MLC,
  38  *      specifically, the ISR, which is entirely registered by the
  39  *      sub-driver and invoked directly, must check for record
  40  *      termination or packet match, at which point a semaphore must
  41  *      be cleared and then the hil_mlcs_tasklet must be scheduled.
  42  *
  43  *      The hil_mlcs_tasklet processes the state machine for all MLCs
  44  *      each time it runs, checking each MLC's progress at the current
  45  *      node in the state machine, and moving the MLC to subsequent nodes
  46  *      in the state machine when appropriate.  It will reschedule
  47  *      itself if output is pending.  (This rescheduling should be replaced
  48  *      at some point with a sub-driver-specific mechanism.)
  49  *
  50  *      A timer task prods the tasklet once per second to prevent
  51  *      hangups when attached devices do not return expected data
  52  *      and to initiate probes of the loop for new devices.
  53  */
  54 
  55 #include <linux/hil_mlc.h>
  56 #include <linux/errno.h>
  57 #include <linux/kernel.h>
  58 #include <linux/module.h>
  59 #include <linux/init.h>
  60 #include <linux/interrupt.h>
  61 #include <linux/slab.h>
  62 #include <linux/timer.h>
  63 #include <linux/list.h>
  64 
  65 MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
  66 MODULE_DESCRIPTION("HIL MLC serio");
  67 MODULE_LICENSE("Dual BSD/GPL");
  68 
  69 EXPORT_SYMBOL(hil_mlc_register);
  70 EXPORT_SYMBOL(hil_mlc_unregister);
  71 
  72 #define PREFIX "HIL MLC: "
  73 
  74 static LIST_HEAD(hil_mlcs);
  75 static DEFINE_RWLOCK(hil_mlcs_lock);
  76 static struct timer_list        hil_mlcs_kicker;
  77 static int                      hil_mlcs_probe;
  78 
  79 static void hil_mlcs_process(unsigned long unused);
  80 static DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0);
  81 
  82 
  83 /* #define HIL_MLC_DEBUG */
  84 
  85 /********************** Device info/instance management **********************/
  86 
  87 static void hil_mlc_clear_di_map(hil_mlc *mlc, int val)
  88 {
  89         int j;
  90 
  91         for (j = val; j < 7 ; j++)
  92                 mlc->di_map[j] = -1;
  93 }
  94 
  95 static void hil_mlc_clear_di_scratch(hil_mlc *mlc)
  96 {
  97         memset(&mlc->di_scratch, 0, sizeof(mlc->di_scratch));
  98 }
  99 
 100 static void hil_mlc_copy_di_scratch(hil_mlc *mlc, int idx)
 101 {
 102         memcpy(&mlc->di[idx], &mlc->di_scratch, sizeof(mlc->di_scratch));
 103 }
 104 
 105 static int hil_mlc_match_di_scratch(hil_mlc *mlc)
 106 {
 107         int idx;
 108 
 109         for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
 110                 int j, found = 0;
 111 
 112                 /* In-use slots are not eligible. */
 113                 for (j = 0; j < 7 ; j++)
 114                         if (mlc->di_map[j] == idx)
 115                                 found++;
 116 
 117                 if (found)
 118                         continue;
 119 
 120                 if (!memcmp(mlc->di + idx, &mlc->di_scratch,
 121                                 sizeof(mlc->di_scratch)))
 122                         break;
 123         }
 124         return idx >= HIL_MLC_DEVMEM ? -1 : idx;
 125 }
 126 
 127 static int hil_mlc_find_free_di(hil_mlc *mlc)
 128 {
 129         int idx;
 130 
 131         /* TODO: Pick all-zero slots first, failing that,
 132          * randomize the slot picked among those eligible.
 133          */
 134         for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
 135                 int j, found = 0;
 136 
 137                 for (j = 0; j < 7 ; j++)
 138                         if (mlc->di_map[j] == idx)
 139                                 found++;
 140 
 141                 if (!found)
 142                         break;
 143         }
 144 
 145         return idx; /* Note: It is guaranteed at least one above will match */
 146 }
 147 
 148 static inline void hil_mlc_clean_serio_map(hil_mlc *mlc)
 149 {
 150         int idx;
 151 
 152         for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
 153                 int j, found = 0;
 154 
 155                 for (j = 0; j < 7 ; j++)
 156                         if (mlc->di_map[j] == idx)
 157                                 found++;
 158 
 159                 if (!found)
 160                         mlc->serio_map[idx].di_revmap = -1;
 161         }
 162 }
 163 
 164 static void hil_mlc_send_polls(hil_mlc *mlc)
 165 {
 166         int did, i, cnt;
 167         struct serio *serio;
 168         struct serio_driver *drv;
 169 
 170         i = cnt = 0;
 171         did = (mlc->ipacket[0] & HIL_PKT_ADDR_MASK) >> 8;
 172         serio = did ? mlc->serio[mlc->di_map[did - 1]] : NULL;
 173         drv = (serio != NULL) ? serio->drv : NULL;
 174 
 175         while (mlc->icount < 15 - i) {
 176                 hil_packet p;
 177 
 178                 p = mlc->ipacket[i];
 179                 if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
 180                         if (drv && drv->interrupt) {
 181                                 drv->interrupt(serio, 0, 0);
 182                                 drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
 183                                 drv->interrupt(serio, HIL_PKT_CMD >> 8,  0);
 184                                 drv->interrupt(serio, HIL_CMD_POL + cnt, 0);
 185                         }
 186 
 187                         did = (p & HIL_PKT_ADDR_MASK) >> 8;
 188                         serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL;
 189                         drv = (serio != NULL) ? serio->drv : NULL;
 190                         cnt = 0;
 191                 }
 192 
 193                 cnt++;
 194                 i++;
 195 
 196                 if (drv && drv->interrupt) {
 197                         drv->interrupt(serio, (p >> 24), 0);
 198                         drv->interrupt(serio, (p >> 16) & 0xff, 0);
 199                         drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
 200                         drv->interrupt(serio, p & 0xff, 0);
 201                 }
 202         }
 203 }
 204 
 205 /*************************** State engine *********************************/
 206 
 207 #define HILSEN_SCHED    0x000100        /* Schedule the tasklet         */
 208 #define HILSEN_BREAK    0x000200        /* Wait until next pass         */
 209 #define HILSEN_UP       0x000400        /* relative node#, decrement    */
 210 #define HILSEN_DOWN     0x000800        /* relative node#, increment    */
 211 #define HILSEN_FOLLOW   0x001000        /* use retval as next node#     */
 212 
 213 #define HILSEN_MASK     0x0000ff
 214 #define HILSEN_START    0
 215 #define HILSEN_RESTART  1
 216 #define HILSEN_DHR      9
 217 #define HILSEN_DHR2     10
 218 #define HILSEN_IFC      14
 219 #define HILSEN_HEAL0    16
 220 #define HILSEN_HEAL     18
 221 #define HILSEN_ACF      21
 222 #define HILSEN_ACF2     22
 223 #define HILSEN_DISC0    25
 224 #define HILSEN_DISC     27
 225 #define HILSEN_MATCH    40
 226 #define HILSEN_OPERATE  41
 227 #define HILSEN_PROBE    44
 228 #define HILSEN_DSR      52
 229 #define HILSEN_REPOLL   55
 230 #define HILSEN_IFCACF   58
 231 #define HILSEN_END      60
 232 
 233 #define HILSEN_NEXT     (HILSEN_DOWN | 1)
 234 #define HILSEN_SAME     (HILSEN_DOWN | 0)
 235 #define HILSEN_LAST     (HILSEN_UP | 1)
 236 
 237 #define HILSEN_DOZE     (HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK)
 238 #define HILSEN_SLEEP    (HILSEN_SAME | HILSEN_BREAK)
 239 
 240 static int hilse_match(hil_mlc *mlc, int unused)
 241 {
 242         int rc;
 243 
 244         rc = hil_mlc_match_di_scratch(mlc);
 245         if (rc == -1) {
 246                 rc = hil_mlc_find_free_di(mlc);
 247                 if (rc == -1)
 248                         goto err;
 249 
 250 #ifdef HIL_MLC_DEBUG
 251                 printk(KERN_DEBUG PREFIX "new in slot %i\n", rc);
 252 #endif
 253                 hil_mlc_copy_di_scratch(mlc, rc);
 254                 mlc->di_map[mlc->ddi] = rc;
 255                 mlc->serio_map[rc].di_revmap = mlc->ddi;
 256                 hil_mlc_clean_serio_map(mlc);
 257                 serio_rescan(mlc->serio[rc]);
 258                 return -1;
 259         }
 260 
 261         mlc->di_map[mlc->ddi] = rc;
 262 #ifdef HIL_MLC_DEBUG
 263         printk(KERN_DEBUG PREFIX "same in slot %i\n", rc);
 264 #endif
 265         mlc->serio_map[rc].di_revmap = mlc->ddi;
 266         hil_mlc_clean_serio_map(mlc);
 267         return 0;
 268 
 269  err:
 270         printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n");
 271         return 1;
 272 }
 273 
 274 /* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */
 275 static int hilse_init_lcv(hil_mlc *mlc, int unused)
 276 {
 277         time64_t now = ktime_get_seconds();
 278 
 279         if (mlc->lcv && (now - mlc->lcv_time) < 5)
 280                 return -1;
 281 
 282         mlc->lcv_time = now;
 283         mlc->lcv = 0;
 284 
 285         return 0;
 286 }
 287 
 288 static int hilse_inc_lcv(hil_mlc *mlc, int lim)
 289 {
 290         return mlc->lcv++ >= lim ? -1 : 0;
 291 }
 292 
 293 #if 0
 294 static int hilse_set_lcv(hil_mlc *mlc, int val)
 295 {
 296         mlc->lcv = val;
 297 
 298         return 0;
 299 }
 300 #endif
 301 
 302 /* Management of the discovered device index (zero based, -1 means no devs) */
 303 static int hilse_set_ddi(hil_mlc *mlc, int val)
 304 {
 305         mlc->ddi = val;
 306         hil_mlc_clear_di_map(mlc, val + 1);
 307 
 308         return 0;
 309 }
 310 
 311 static int hilse_dec_ddi(hil_mlc *mlc, int unused)
 312 {
 313         mlc->ddi--;
 314         if (mlc->ddi <= -1) {
 315                 mlc->ddi = -1;
 316                 hil_mlc_clear_di_map(mlc, 0);
 317                 return -1;
 318         }
 319         hil_mlc_clear_di_map(mlc, mlc->ddi + 1);
 320 
 321         return 0;
 322 }
 323 
 324 static int hilse_inc_ddi(hil_mlc *mlc, int unused)
 325 {
 326         BUG_ON(mlc->ddi >= 6);
 327         mlc->ddi++;
 328 
 329         return 0;
 330 }
 331 
 332 static int hilse_take_idd(hil_mlc *mlc, int unused)
 333 {
 334         int i;
 335 
 336         /* Help the state engine:
 337          * Is this a real IDD response or just an echo?
 338          *
 339          * Real IDD response does not start with a command.
 340          */
 341         if (mlc->ipacket[0] & HIL_PKT_CMD)
 342                 goto bail;
 343 
 344         /* Should have the command echoed further down. */
 345         for (i = 1; i < 16; i++) {
 346                 if (((mlc->ipacket[i] & HIL_PKT_ADDR_MASK) ==
 347                      (mlc->ipacket[0] & HIL_PKT_ADDR_MASK)) &&
 348                     (mlc->ipacket[i] & HIL_PKT_CMD) &&
 349                     ((mlc->ipacket[i] & HIL_PKT_DATA_MASK) == HIL_CMD_IDD))
 350                         break;
 351         }
 352         if (i > 15)
 353                 goto bail;
 354 
 355         /* And the rest of the packets should still be clear. */
 356         while (++i < 16)
 357                 if (mlc->ipacket[i])
 358                         break;
 359 
 360         if (i < 16)
 361                 goto bail;
 362 
 363         for (i = 0; i < 16; i++)
 364                 mlc->di_scratch.idd[i] =
 365                         mlc->ipacket[i] & HIL_PKT_DATA_MASK;
 366 
 367         /* Next step is to see if RSC supported */
 368         if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_RSC)
 369                 return HILSEN_NEXT;
 370 
 371         if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
 372                 return HILSEN_DOWN | 4;
 373 
 374         return 0;
 375 
 376  bail:
 377         mlc->ddi--;
 378 
 379         return -1; /* This should send us off to ACF */
 380 }
 381 
 382 static int hilse_take_rsc(hil_mlc *mlc, int unused)
 383 {
 384         int i;
 385 
 386         for (i = 0; i < 16; i++)
 387                 mlc->di_scratch.rsc[i] =
 388                         mlc->ipacket[i] & HIL_PKT_DATA_MASK;
 389 
 390         /* Next step is to see if EXD supported (IDD has already been read) */
 391         if (mlc->di_scratch.idd[1] & HIL_IDD_HEADER_EXD)
 392                 return HILSEN_NEXT;
 393 
 394         return 0;
 395 }
 396 
 397 static int hilse_take_exd(hil_mlc *mlc, int unused)
 398 {
 399         int i;
 400 
 401         for (i = 0; i < 16; i++)
 402                 mlc->di_scratch.exd[i] =
 403                         mlc->ipacket[i] & HIL_PKT_DATA_MASK;
 404 
 405         /* Next step is to see if RNM supported. */
 406         if (mlc->di_scratch.exd[0] & HIL_EXD_HEADER_RNM)
 407                 return HILSEN_NEXT;
 408 
 409         return 0;
 410 }
 411 
 412 static int hilse_take_rnm(hil_mlc *mlc, int unused)
 413 {
 414         int i;
 415 
 416         for (i = 0; i < 16; i++)
 417                 mlc->di_scratch.rnm[i] =
 418                         mlc->ipacket[i] & HIL_PKT_DATA_MASK;
 419 
 420         printk(KERN_INFO PREFIX "Device name gotten: %16s\n",
 421                         mlc->di_scratch.rnm);
 422 
 423         return 0;
 424 }
 425 
 426 static int hilse_operate(hil_mlc *mlc, int repoll)
 427 {
 428 
 429         if (mlc->opercnt == 0)
 430                 hil_mlcs_probe = 0;
 431         mlc->opercnt = 1;
 432 
 433         hil_mlc_send_polls(mlc);
 434 
 435         if (!hil_mlcs_probe)
 436                 return 0;
 437         hil_mlcs_probe = 0;
 438         mlc->opercnt = 0;
 439         return 1;
 440 }
 441 
 442 #define FUNC(funct, funct_arg, zero_rc, neg_rc, pos_rc) \
 443 { HILSE_FUNC,           { .func = funct }, funct_arg, zero_rc, neg_rc, pos_rc },
 444 #define OUT(pack) \
 445 { HILSE_OUT,            { .packet = pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 },
 446 #define CTS \
 447 { HILSE_CTS,            { .packet = 0    }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 },
 448 #define EXPECT(comp, to, got, got_wrong, timed_out) \
 449 { HILSE_EXPECT,         { .packet = comp }, to, got, got_wrong, timed_out },
 450 #define EXPECT_LAST(comp, to, got, got_wrong, timed_out) \
 451 { HILSE_EXPECT_LAST,    { .packet = comp }, to, got, got_wrong, timed_out },
 452 #define EXPECT_DISC(comp, to, got, got_wrong, timed_out) \
 453 { HILSE_EXPECT_DISC,    { .packet = comp }, to, got, got_wrong, timed_out },
 454 #define IN(to, got, got_error, timed_out) \
 455 { HILSE_IN,             { .packet = 0    }, to, got, got_error, timed_out },
 456 #define OUT_DISC(pack) \
 457 { HILSE_OUT_DISC,       { .packet = pack }, 0, 0, 0, 0 },
 458 #define OUT_LAST(pack) \
 459 { HILSE_OUT_LAST,       { .packet = pack }, 0, 0, 0, 0 },
 460 
 461 static const struct hilse_node hil_mlc_se[HILSEN_END] = {
 462 
 463         /* 0  HILSEN_START */
 464         FUNC(hilse_init_lcv, 0, HILSEN_NEXT,    HILSEN_SLEEP,   0)
 465 
 466         /* 1  HILSEN_RESTART */
 467         FUNC(hilse_inc_lcv, 10, HILSEN_NEXT,    HILSEN_START,  0)
 468         OUT(HIL_CTRL_ONLY)                      /* Disable APE */
 469         CTS
 470 
 471 #define TEST_PACKET(x) \
 472 (HIL_PKT_CMD | (x << HIL_PKT_ADDR_SHIFT) | x << 4 | x)
 473 
 474         OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0x5))
 475         EXPECT(HIL_ERR_INT | TEST_PACKET(0x5),
 476                2000,            HILSEN_NEXT,    HILSEN_RESTART, HILSEN_RESTART)
 477         OUT(HIL_DO_ALTER_CTRL | HIL_CTRL_TEST | TEST_PACKET(0xa))
 478         EXPECT(HIL_ERR_INT | TEST_PACKET(0xa),
 479                2000,            HILSEN_NEXT,    HILSEN_RESTART, HILSEN_RESTART)
 480         OUT(HIL_CTRL_ONLY | 0)                  /* Disable test mode */
 481 
 482         /* 9  HILSEN_DHR */
 483         FUNC(hilse_init_lcv, 0, HILSEN_NEXT,    HILSEN_SLEEP,   0)
 484 
 485         /* 10 HILSEN_DHR2 */
 486         FUNC(hilse_inc_lcv, 10, HILSEN_NEXT,    HILSEN_START,   0)
 487         FUNC(hilse_set_ddi, -1, HILSEN_NEXT,    0,              0)
 488         OUT(HIL_PKT_CMD | HIL_CMD_DHR)
 489         IN(300000,              HILSEN_DHR2,    HILSEN_DHR2,    HILSEN_NEXT)
 490 
 491         /* 14 HILSEN_IFC */
 492         OUT(HIL_PKT_CMD | HIL_CMD_IFC)
 493         EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
 494                20000,           HILSEN_DISC,    HILSEN_DHR2,    HILSEN_NEXT )
 495 
 496         /* If devices are there, they weren't in PUP or other loopback mode.
 497          * We're more concerned at this point with restoring operation
 498          * to devices than discovering new ones, so we try to salvage
 499          * the loop configuration by closing off the loop.
 500          */
 501 
 502         /* 16 HILSEN_HEAL0 */
 503         FUNC(hilse_dec_ddi, 0,  HILSEN_NEXT,    HILSEN_ACF,     0)
 504         FUNC(hilse_inc_ddi, 0,  HILSEN_NEXT,    0,              0)
 505 
 506         /* 18 HILSEN_HEAL */
 507         OUT_LAST(HIL_CMD_ELB)
 508         EXPECT_LAST(HIL_CMD_ELB | HIL_ERR_INT,
 509                     20000,      HILSEN_REPOLL,  HILSEN_DSR,     HILSEN_NEXT)
 510         FUNC(hilse_dec_ddi, 0,  HILSEN_HEAL,    HILSEN_NEXT,    0)
 511 
 512         /* 21 HILSEN_ACF */
 513         FUNC(hilse_init_lcv, 0, HILSEN_NEXT,    HILSEN_DOZE,    0)
 514 
 515         /* 22 HILSEN_ACF2 */
 516         FUNC(hilse_inc_lcv, 10, HILSEN_NEXT,    HILSEN_START,   0)
 517         OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)
 518         IN(20000,               HILSEN_NEXT,    HILSEN_DSR,     HILSEN_NEXT)
 519 
 520         /* 25 HILSEN_DISC0 */
 521         OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)
 522         EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_ELB | HIL_ERR_INT,
 523                20000,           HILSEN_NEXT,    HILSEN_DSR,     HILSEN_DSR)
 524 
 525         /* Only enter here if response just received */
 526         /* 27 HILSEN_DISC */
 527         OUT_DISC(HIL_PKT_CMD | HIL_CMD_IDD)
 528         EXPECT_DISC(HIL_PKT_CMD | HIL_CMD_IDD | HIL_ERR_INT,
 529                20000,           HILSEN_NEXT,    HILSEN_DSR,     HILSEN_START)
 530         FUNC(hilse_inc_ddi,  0, HILSEN_NEXT,    HILSEN_START,   0)
 531         FUNC(hilse_take_idd, 0, HILSEN_MATCH,   HILSEN_IFCACF,  HILSEN_FOLLOW)
 532         OUT_LAST(HIL_PKT_CMD | HIL_CMD_RSC)
 533         EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RSC | HIL_ERR_INT,
 534                30000,           HILSEN_NEXT,    HILSEN_DSR,     HILSEN_DSR)
 535         FUNC(hilse_take_rsc, 0, HILSEN_MATCH,   0,              HILSEN_FOLLOW)
 536         OUT_LAST(HIL_PKT_CMD | HIL_CMD_EXD)
 537         EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_EXD | HIL_ERR_INT,
 538                30000,           HILSEN_NEXT,    HILSEN_DSR,     HILSEN_DSR)
 539         FUNC(hilse_take_exd, 0, HILSEN_MATCH,   0,              HILSEN_FOLLOW)
 540         OUT_LAST(HIL_PKT_CMD | HIL_CMD_RNM)
 541         EXPECT_LAST(HIL_PKT_CMD | HIL_CMD_RNM | HIL_ERR_INT,
 542                30000,           HILSEN_NEXT,    HILSEN_DSR,     HILSEN_DSR)
 543         FUNC(hilse_take_rnm, 0, HILSEN_MATCH,   0,              0)
 544 
 545         /* 40 HILSEN_MATCH */
 546         FUNC(hilse_match, 0,    HILSEN_NEXT,    HILSEN_NEXT,    /* TODO */ 0)
 547 
 548         /* 41 HILSEN_OPERATE */
 549         OUT(HIL_PKT_CMD | HIL_CMD_POL)
 550         EXPECT(HIL_PKT_CMD | HIL_CMD_POL | HIL_ERR_INT,
 551                20000,           HILSEN_NEXT,    HILSEN_DSR,     HILSEN_NEXT)
 552         FUNC(hilse_operate, 0,  HILSEN_OPERATE, HILSEN_IFC,     HILSEN_NEXT)
 553 
 554         /* 44 HILSEN_PROBE */
 555         OUT_LAST(HIL_PKT_CMD | HIL_CMD_EPT)
 556         IN(10000,               HILSEN_DISC,    HILSEN_DSR,     HILSEN_NEXT)
 557         OUT_DISC(HIL_PKT_CMD | HIL_CMD_ELB)
 558         IN(10000,               HILSEN_DISC,    HILSEN_DSR,     HILSEN_NEXT)
 559         OUT(HIL_PKT_CMD | HIL_CMD_ACF | 1)
 560         IN(10000,               HILSEN_DISC0,   HILSEN_DSR,     HILSEN_NEXT)
 561         OUT_LAST(HIL_PKT_CMD | HIL_CMD_ELB)
 562         IN(10000,               HILSEN_OPERATE, HILSEN_DSR,     HILSEN_DSR)
 563 
 564         /* 52 HILSEN_DSR */
 565         FUNC(hilse_set_ddi, -1, HILSEN_NEXT,    0,              0)
 566         OUT(HIL_PKT_CMD | HIL_CMD_DSR)
 567         IN(20000,               HILSEN_DHR,     HILSEN_DHR,     HILSEN_IFC)
 568 
 569         /* 55 HILSEN_REPOLL */
 570         OUT(HIL_PKT_CMD | HIL_CMD_RPL)
 571         EXPECT(HIL_PKT_CMD | HIL_CMD_RPL | HIL_ERR_INT,
 572                20000,           HILSEN_NEXT,    HILSEN_DSR,     HILSEN_NEXT)
 573         FUNC(hilse_operate, 1,  HILSEN_OPERATE, HILSEN_IFC,     HILSEN_PROBE)
 574 
 575         /* 58 HILSEN_IFCACF */
 576         OUT(HIL_PKT_CMD | HIL_CMD_IFC)
 577         EXPECT(HIL_PKT_CMD | HIL_CMD_IFC | HIL_ERR_INT,
 578                20000,           HILSEN_ACF2,    HILSEN_DHR2,    HILSEN_HEAL)
 579 
 580         /* 60 HILSEN_END */
 581 };
 582 
 583 static inline void hilse_setup_input(hil_mlc *mlc, const struct hilse_node *node)
 584 {
 585 
 586         switch (node->act) {
 587         case HILSE_EXPECT_DISC:
 588                 mlc->imatch = node->object.packet;
 589                 mlc->imatch |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
 590                 break;
 591         case HILSE_EXPECT_LAST:
 592                 mlc->imatch = node->object.packet;
 593                 mlc->imatch |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
 594                 break;
 595         case HILSE_EXPECT:
 596                 mlc->imatch = node->object.packet;
 597                 break;
 598         case HILSE_IN:
 599                 mlc->imatch = 0;
 600                 break;
 601         default:
 602                 BUG();
 603         }
 604         mlc->istarted = 1;
 605         mlc->intimeout = usecs_to_jiffies(node->arg);
 606         mlc->instart = jiffies;
 607         mlc->icount = 15;
 608         memset(mlc->ipacket, 0, 16 * sizeof(hil_packet));
 609         BUG_ON(down_trylock(&mlc->isem));
 610 }
 611 
 612 #ifdef HIL_MLC_DEBUG
 613 static int doze;
 614 static int seidx; /* For debug */
 615 #endif
 616 
 617 static int hilse_donode(hil_mlc *mlc)
 618 {
 619         const struct hilse_node *node;
 620         int nextidx = 0;
 621         int sched_long = 0;
 622         unsigned long flags;
 623 
 624 #ifdef HIL_MLC_DEBUG
 625         if (mlc->seidx && mlc->seidx != seidx &&
 626             mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
 627                 printk(KERN_DEBUG PREFIX "z%i \n {%i}", doze, mlc->seidx);
 628                 doze = 0;
 629         }
 630 
 631         seidx = mlc->seidx;
 632 #endif
 633         node = hil_mlc_se + mlc->seidx;
 634 
 635         switch (node->act) {
 636                 int rc;
 637                 hil_packet pack;
 638 
 639         case HILSE_FUNC:
 640                 BUG_ON(node->object.func == NULL);
 641                 rc = node->object.func(mlc, node->arg);
 642                 nextidx = (rc > 0) ? node->ugly :
 643                         ((rc < 0) ? node->bad : node->good);
 644                 if (nextidx == HILSEN_FOLLOW)
 645                         nextidx = rc;
 646                 break;
 647 
 648         case HILSE_EXPECT_LAST:
 649         case HILSE_EXPECT_DISC:
 650         case HILSE_EXPECT:
 651         case HILSE_IN:
 652                 /* Already set up from previous HILSE_OUT_* */
 653                 write_lock_irqsave(&mlc->lock, flags);
 654                 rc = mlc->in(mlc, node->arg);
 655                 if (rc == 2)  {
 656                         nextidx = HILSEN_DOZE;
 657                         sched_long = 1;
 658                         write_unlock_irqrestore(&mlc->lock, flags);
 659                         break;
 660                 }
 661                 if (rc == 1)
 662                         nextidx = node->ugly;
 663                 else if (rc == 0)
 664                         nextidx = node->good;
 665                 else
 666                         nextidx = node->bad;
 667                 mlc->istarted = 0;
 668                 write_unlock_irqrestore(&mlc->lock, flags);
 669                 break;
 670 
 671         case HILSE_OUT_LAST:
 672                 write_lock_irqsave(&mlc->lock, flags);
 673                 pack = node->object.packet;
 674                 pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
 675                 goto out;
 676 
 677         case HILSE_OUT_DISC:
 678                 write_lock_irqsave(&mlc->lock, flags);
 679                 pack = node->object.packet;
 680                 pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
 681                 goto out;
 682 
 683         case HILSE_OUT:
 684                 write_lock_irqsave(&mlc->lock, flags);
 685                 pack = node->object.packet;
 686         out:
 687                 if (!mlc->istarted) {
 688                         /* Prepare to receive input */
 689                         if ((node + 1)->act & HILSE_IN)
 690                                 hilse_setup_input(mlc, node + 1);
 691                 }
 692 
 693                 write_unlock_irqrestore(&mlc->lock, flags);
 694 
 695                 if (down_trylock(&mlc->osem)) {
 696                         nextidx = HILSEN_DOZE;
 697                         break;
 698                 }
 699                 up(&mlc->osem);
 700 
 701                 write_lock_irqsave(&mlc->lock, flags);
 702                 if (!mlc->ostarted) {
 703                         mlc->ostarted = 1;
 704                         mlc->opacket = pack;
 705                         mlc->out(mlc);
 706                         nextidx = HILSEN_DOZE;
 707                         write_unlock_irqrestore(&mlc->lock, flags);
 708                         break;
 709                 }
 710                 mlc->ostarted = 0;
 711                 mlc->instart = jiffies;
 712                 write_unlock_irqrestore(&mlc->lock, flags);
 713                 nextidx = HILSEN_NEXT;
 714                 break;
 715 
 716         case HILSE_CTS:
 717                 write_lock_irqsave(&mlc->lock, flags);
 718                 nextidx = mlc->cts(mlc) ? node->bad : node->good;
 719                 write_unlock_irqrestore(&mlc->lock, flags);
 720                 break;
 721 
 722         default:
 723                 BUG();
 724         }
 725 
 726 #ifdef HIL_MLC_DEBUG
 727         if (nextidx == HILSEN_DOZE)
 728                 doze++;
 729 #endif
 730 
 731         while (nextidx & HILSEN_SCHED) {
 732                 unsigned long now = jiffies;
 733 
 734                 if (!sched_long)
 735                         goto sched;
 736 
 737                 if (time_after(now, mlc->instart + mlc->intimeout))
 738                          goto sched;
 739                 mod_timer(&hil_mlcs_kicker, mlc->instart + mlc->intimeout);
 740                 break;
 741         sched:
 742                 tasklet_schedule(&hil_mlcs_tasklet);
 743                 break;
 744         }
 745 
 746         if (nextidx & HILSEN_DOWN)
 747                 mlc->seidx += nextidx & HILSEN_MASK;
 748         else if (nextidx & HILSEN_UP)
 749                 mlc->seidx -= nextidx & HILSEN_MASK;
 750         else
 751                 mlc->seidx = nextidx & HILSEN_MASK;
 752 
 753         if (nextidx & HILSEN_BREAK)
 754                 return 1;
 755 
 756         return 0;
 757 }
 758 
 759 /******************** tasklet context functions **************************/
 760 static void hil_mlcs_process(unsigned long unused)
 761 {
 762         struct list_head *tmp;
 763 
 764         read_lock(&hil_mlcs_lock);
 765         list_for_each(tmp, &hil_mlcs) {
 766                 struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list);
 767                 while (hilse_donode(mlc) == 0) {
 768 #ifdef HIL_MLC_DEBUG
 769                         if (mlc->seidx != 41 &&
 770                             mlc->seidx != 42 &&
 771                             mlc->seidx != 43)
 772                                 printk(KERN_DEBUG PREFIX " + ");
 773 #endif
 774                 }
 775         }
 776         read_unlock(&hil_mlcs_lock);
 777 }
 778 
 779 /************************* Keepalive timer task *********************/
 780 
 781 static void hil_mlcs_timer(struct timer_list *unused)
 782 {
 783         hil_mlcs_probe = 1;
 784         tasklet_schedule(&hil_mlcs_tasklet);
 785         /* Re-insert the periodic task. */
 786         if (!timer_pending(&hil_mlcs_kicker))
 787                 mod_timer(&hil_mlcs_kicker, jiffies + HZ);
 788 }
 789 
 790 /******************** user/kernel context functions **********************/
 791 
 792 static int hil_mlc_serio_write(struct serio *serio, unsigned char c)
 793 {
 794         struct hil_mlc_serio_map *map;
 795         struct hil_mlc *mlc;
 796         struct serio_driver *drv;
 797         uint8_t *idx, *last;
 798 
 799         map = serio->port_data;
 800         BUG_ON(map == NULL);
 801 
 802         mlc = map->mlc;
 803         BUG_ON(mlc == NULL);
 804 
 805         mlc->serio_opacket[map->didx] |=
 806                 ((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx]));
 807 
 808         if (mlc->serio_oidx[map->didx] >= 3) {
 809                 /* for now only commands */
 810                 if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD))
 811                         return -EIO;
 812                 switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) {
 813                 case HIL_CMD_IDD:
 814                         idx = mlc->di[map->didx].idd;
 815                         goto emu;
 816                 case HIL_CMD_RSC:
 817                         idx = mlc->di[map->didx].rsc;
 818                         goto emu;
 819                 case HIL_CMD_EXD:
 820                         idx = mlc->di[map->didx].exd;
 821                         goto emu;
 822                 case HIL_CMD_RNM:
 823                         idx = mlc->di[map->didx].rnm;
 824                         goto emu;
 825                 default:
 826                         break;
 827                 }
 828                 mlc->serio_oidx[map->didx] = 0;
 829                 mlc->serio_opacket[map->didx] = 0;
 830         }
 831 
 832         mlc->serio_oidx[map->didx]++;
 833         return -EIO;
 834  emu:
 835         drv = serio->drv;
 836         BUG_ON(drv == NULL);
 837 
 838         last = idx + 15;
 839         while ((last != idx) && (*last == 0))
 840                 last--;
 841 
 842         while (idx != last) {
 843                 drv->interrupt(serio, 0, 0);
 844                 drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
 845                 drv->interrupt(serio, 0, 0);
 846                 drv->interrupt(serio, *idx, 0);
 847                 idx++;
 848         }
 849         drv->interrupt(serio, 0, 0);
 850         drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
 851         drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
 852         drv->interrupt(serio, *idx, 0);
 853 
 854         mlc->serio_oidx[map->didx] = 0;
 855         mlc->serio_opacket[map->didx] = 0;
 856 
 857         return 0;
 858 }
 859 
 860 static int hil_mlc_serio_open(struct serio *serio)
 861 {
 862         struct hil_mlc_serio_map *map;
 863         struct hil_mlc *mlc;
 864 
 865         if (serio_get_drvdata(serio) != NULL)
 866                 return -EBUSY;
 867 
 868         map = serio->port_data;
 869         BUG_ON(map == NULL);
 870 
 871         mlc = map->mlc;
 872         BUG_ON(mlc == NULL);
 873 
 874         return 0;
 875 }
 876 
 877 static void hil_mlc_serio_close(struct serio *serio)
 878 {
 879         struct hil_mlc_serio_map *map;
 880         struct hil_mlc *mlc;
 881 
 882         map = serio->port_data;
 883         BUG_ON(map == NULL);
 884 
 885         mlc = map->mlc;
 886         BUG_ON(mlc == NULL);
 887 
 888         serio_set_drvdata(serio, NULL);
 889         serio->drv = NULL;
 890         /* TODO wake up interruptable */
 891 }
 892 
 893 static const struct serio_device_id hil_mlc_serio_id = {
 894         .type = SERIO_HIL_MLC,
 895         .proto = SERIO_HIL,
 896         .extra = SERIO_ANY,
 897         .id = SERIO_ANY,
 898 };
 899 
 900 int hil_mlc_register(hil_mlc *mlc)
 901 {
 902         int i;
 903         unsigned long flags;
 904 
 905         BUG_ON(mlc == NULL);
 906 
 907         mlc->istarted = 0;
 908         mlc->ostarted = 0;
 909 
 910         rwlock_init(&mlc->lock);
 911         sema_init(&mlc->osem, 1);
 912 
 913         sema_init(&mlc->isem, 1);
 914         mlc->icount = -1;
 915         mlc->imatch = 0;
 916 
 917         mlc->opercnt = 0;
 918 
 919         sema_init(&(mlc->csem), 0);
 920 
 921         hil_mlc_clear_di_scratch(mlc);
 922         hil_mlc_clear_di_map(mlc, 0);
 923         for (i = 0; i < HIL_MLC_DEVMEM; i++) {
 924                 struct serio *mlc_serio;
 925                 hil_mlc_copy_di_scratch(mlc, i);
 926                 mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
 927                 mlc->serio[i] = mlc_serio;
 928                 if (!mlc->serio[i]) {
 929                         for (; i >= 0; i--)
 930                                 kfree(mlc->serio[i]);
 931                         return -ENOMEM;
 932                 }
 933                 snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i);
 934                 snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i);
 935                 mlc_serio->id                   = hil_mlc_serio_id;
 936                 mlc_serio->id.id                = i; /* HIL port no. */
 937                 mlc_serio->write                = hil_mlc_serio_write;
 938                 mlc_serio->open                 = hil_mlc_serio_open;
 939                 mlc_serio->close                = hil_mlc_serio_close;
 940                 mlc_serio->port_data            = &(mlc->serio_map[i]);
 941                 mlc->serio_map[i].mlc           = mlc;
 942                 mlc->serio_map[i].didx          = i;
 943                 mlc->serio_map[i].di_revmap     = -1;
 944                 mlc->serio_opacket[i]           = 0;
 945                 mlc->serio_oidx[i]              = 0;
 946                 serio_register_port(mlc_serio);
 947         }
 948 
 949         mlc->tasklet = &hil_mlcs_tasklet;
 950 
 951         write_lock_irqsave(&hil_mlcs_lock, flags);
 952         list_add_tail(&mlc->list, &hil_mlcs);
 953         mlc->seidx = HILSEN_START;
 954         write_unlock_irqrestore(&hil_mlcs_lock, flags);
 955 
 956         tasklet_schedule(&hil_mlcs_tasklet);
 957         return 0;
 958 }
 959 
 960 int hil_mlc_unregister(hil_mlc *mlc)
 961 {
 962         struct list_head *tmp;
 963         unsigned long flags;
 964         int i;
 965 
 966         BUG_ON(mlc == NULL);
 967 
 968         write_lock_irqsave(&hil_mlcs_lock, flags);
 969         list_for_each(tmp, &hil_mlcs)
 970                 if (list_entry(tmp, hil_mlc, list) == mlc)
 971                         goto found;
 972 
 973         /* not found in list */
 974         write_unlock_irqrestore(&hil_mlcs_lock, flags);
 975         tasklet_schedule(&hil_mlcs_tasklet);
 976         return -ENODEV;
 977 
 978  found:
 979         list_del(tmp);
 980         write_unlock_irqrestore(&hil_mlcs_lock, flags);
 981 
 982         for (i = 0; i < HIL_MLC_DEVMEM; i++) {
 983                 serio_unregister_port(mlc->serio[i]);
 984                 mlc->serio[i] = NULL;
 985         }
 986 
 987         tasklet_schedule(&hil_mlcs_tasklet);
 988         return 0;
 989 }
 990 
 991 /**************************** Module interface *************************/
 992 
 993 static int __init hil_mlc_init(void)
 994 {
 995         timer_setup(&hil_mlcs_kicker, &hil_mlcs_timer, 0);
 996         mod_timer(&hil_mlcs_kicker, jiffies + HZ);
 997 
 998         tasklet_enable(&hil_mlcs_tasklet);
 999 
1000         return 0;
1001 }
1002 
1003 static void __exit hil_mlc_exit(void)
1004 {
1005         del_timer_sync(&hil_mlcs_kicker);
1006         tasklet_kill(&hil_mlcs_tasklet);
1007 }
1008 
1009 module_init(hil_mlc_init);
1010 module_exit(hil_mlc_exit);

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