File Index
Files and directories
Sign in
FILE

hil_mlc.c

File preview with syntax highlighting.

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