1 /*
2  * HP Human Interface Loop Master Link Controller 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 
34 #include <linux/hil.h>
35 #include <linux/time.h>
36 #include <linux/interrupt.h>
37 #include <asm/semaphore.h>
38 #include <linux/serio.h>
39 #include <linux/list.h>
40 
41 typedef struct hil_mlc hil_mlc;
42 
43 /* The HIL has a complicated state engine.
44  * We define the structure of nodes in the state engine here.
45  */
46 enum hilse_act {
47   	/* HILSE_OUT prepares to receive input if the next node
48 	 * is an IN or EXPECT, and then sends the given packet.
49 	 */
50 	HILSE_OUT = 0,
51 
52   	/* HILSE_CTS checks if the loop is busy. */
53 	HILSE_CTS,
54 
55 	/* HILSE_OUT_LAST sends the given command packet to
56 	 * the last configured/running device on the loop.
57 	 */
58 	HILSE_OUT_LAST,
59 
60 	/* HILSE_OUT_DISC sends the given command packet to
61 	 * the next device past the last configured/running one.
62 	 */
63 	HILSE_OUT_DISC,
64 
65 	/* HILSE_FUNC runs a callback function with given arguments.
66 	 * a positive return value causes the "ugly" branch to be taken.
67 	 */
68 	HILSE_FUNC,
69 
70   	/* HILSE_IN simply expects any non-errored packet to arrive
71 	 * within arg usecs.
72 	 */
73 	HILSE_IN		= 0x100,
74 
75   	/* HILSE_EXPECT expects a particular packet to arrive
76 	 * within arg usecs, any other packet is considered an error.
77 	 */
78 	HILSE_EXPECT,
79 
80   	/* HILSE_EXPECT_LAST as above but dev field should be last
81 	 * discovered/operational device.
82 	 */
83 	HILSE_EXPECT_LAST,
84 
85   	/* HILSE_EXPECT_LAST as above but dev field should be first
86 	 * undiscovered/inoperational device.
87 	 */
88 	HILSE_EXPECT_DISC
89 };
90 
91 typedef int	(hilse_func) (hil_mlc *mlc, int arg);
92 struct hilse_node {
93 	enum hilse_act		act;	/* How to process this node         */
94 	union {
95 		hilse_func	*func;	/* Function to call if HILSE_FUNC   */
96 		hil_packet	packet;	/* Packet to send or to compare     */
97 	} object;
98 	int			arg;	/* Timeout in usec or parm for func */
99 	int			good;	/* Node to jump to on success       */
100 	int			bad;	/* Node to jump to on error         */
101 	int			ugly;	/* Node to jump to on timeout       */
102 };
103 
104 /* Methods for back-end drivers, e.g. hp_sdc_mlc */
105 typedef int	(hil_mlc_cts) (hil_mlc *mlc);
106 typedef void	(hil_mlc_out) (hil_mlc *mlc);
107 typedef int	(hil_mlc_in)  (hil_mlc *mlc, suseconds_t timeout);
108 
109 struct hil_mlc_devinfo {
110 	uint8_t	idd[16];	/* Device ID Byte and Describe Record */
111 	uint8_t	rsc[16];	/* Security Code Header and Record */
112 	uint8_t	exd[16];	/* Extended Describe Record */
113 	uint8_t	rnm[16];	/* Device name as returned by RNM command */
114 };
115 
116 struct hil_mlc_serio_map {
117 	hil_mlc *mlc;
118 	int di_revmap;
119 	int didx;
120 };
121 
122 /* How many (possibly old/detached) devices the we try to keep track of */
123 #define HIL_MLC_DEVMEM 16
124 
125 struct hil_mlc {
126 	struct list_head	list;	/* hil_mlc is organized as linked list */
127 
128 	rwlock_t		lock;
129 
130 	void *priv; /* Data specific to a particular type of MLC */
131 
132 	int 			seidx;	/* Current node in state engine */
133 	int			istarted, ostarted;
134 
135 	hil_mlc_cts		*cts;
136 	struct semaphore	csem;   /* Raised when loop idle */
137 
138 	hil_mlc_out		*out;
139 	struct semaphore	osem;   /* Raised when outpacket dispatched */
140 	hil_packet		opacket;
141 
142 	hil_mlc_in		*in;
143 	struct semaphore	isem;   /* Raised when a packet arrives */
144 	hil_packet		ipacket[16];
145 	hil_packet		imatch;
146 	int			icount;
147 	struct timeval		instart;
148 	suseconds_t		intimeout;
149 
150 	int			ddi;	/* Last operational device id */
151 	int			lcv;	/* LCV to throttle loops */
152 	struct timeval		lcv_tv; /* Time loop was started */
153 
154 	int			di_map[7]; /* Maps below items to live devs */
155 	struct hil_mlc_devinfo	di[HIL_MLC_DEVMEM];
156 	struct serio		serio[HIL_MLC_DEVMEM];
157 	struct hil_mlc_serio_map serio_map[HIL_MLC_DEVMEM];
158 	hil_packet		serio_opacket[HIL_MLC_DEVMEM];
159 	int			serio_oidx[HIL_MLC_DEVMEM];
160 	struct hil_mlc_devinfo	di_scratch; /* Temporary area */
161 
162 	void			(*inc_use_count)(void);
163 	void			(*dec_use_count)(void);
164 
165 	int			opercnt;
166 
167 	struct tasklet_struct	*tasklet;
168 };
169 
170 int hil_mlc_register(hil_mlc *mlc);
171 int hil_mlc_unregister(hil_mlc *mlc);
172