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