1*6ab0f5cdSMatthew Wilcox /* 2*6ab0f5cdSMatthew Wilcox * HP Human Interface Loop Master Link Controller driver. 3*6ab0f5cdSMatthew Wilcox * 4*6ab0f5cdSMatthew Wilcox * Copyright (c) 2001 Brian S. Julin 5*6ab0f5cdSMatthew Wilcox * All rights reserved. 6*6ab0f5cdSMatthew Wilcox * 7*6ab0f5cdSMatthew Wilcox * Redistribution and use in source and binary forms, with or without 8*6ab0f5cdSMatthew Wilcox * modification, are permitted provided that the following conditions 9*6ab0f5cdSMatthew Wilcox * are met: 10*6ab0f5cdSMatthew Wilcox * 1. Redistributions of source code must retain the above copyright 11*6ab0f5cdSMatthew Wilcox * notice, this list of conditions, and the following disclaimer, 12*6ab0f5cdSMatthew Wilcox * without modification. 13*6ab0f5cdSMatthew Wilcox * 2. The name of the author may not be used to endorse or promote products 14*6ab0f5cdSMatthew Wilcox * derived from this software without specific prior written permission. 15*6ab0f5cdSMatthew Wilcox * 16*6ab0f5cdSMatthew Wilcox * Alternatively, this software may be distributed under the terms of the 17*6ab0f5cdSMatthew Wilcox * GNU General Public License ("GPL"). 18*6ab0f5cdSMatthew Wilcox * 19*6ab0f5cdSMatthew Wilcox * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20*6ab0f5cdSMatthew Wilcox * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*6ab0f5cdSMatthew Wilcox * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*6ab0f5cdSMatthew Wilcox * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 23*6ab0f5cdSMatthew Wilcox * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24*6ab0f5cdSMatthew Wilcox * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25*6ab0f5cdSMatthew Wilcox * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26*6ab0f5cdSMatthew Wilcox * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27*6ab0f5cdSMatthew Wilcox * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28*6ab0f5cdSMatthew Wilcox * 29*6ab0f5cdSMatthew Wilcox * References: 30*6ab0f5cdSMatthew Wilcox * HP-HIL Technical Reference Manual. Hewlett Packard Product No. 45918A 31*6ab0f5cdSMatthew Wilcox * 32*6ab0f5cdSMatthew Wilcox */ 33*6ab0f5cdSMatthew Wilcox 34*6ab0f5cdSMatthew Wilcox #include <linux/hil.h> 35*6ab0f5cdSMatthew Wilcox #include <linux/time.h> 36*6ab0f5cdSMatthew Wilcox #include <linux/interrupt.h> 37*6ab0f5cdSMatthew Wilcox #include <asm/semaphore.h> 38*6ab0f5cdSMatthew Wilcox #include <linux/serio.h> 39*6ab0f5cdSMatthew Wilcox #include <linux/list.h> 40*6ab0f5cdSMatthew Wilcox 41*6ab0f5cdSMatthew Wilcox typedef struct hil_mlc hil_mlc; 42*6ab0f5cdSMatthew Wilcox 43*6ab0f5cdSMatthew Wilcox /* The HIL has a complicated state engine. 44*6ab0f5cdSMatthew Wilcox * We define the structure of nodes in the state engine here. 45*6ab0f5cdSMatthew Wilcox */ 46*6ab0f5cdSMatthew Wilcox enum hilse_act { 47*6ab0f5cdSMatthew Wilcox /* HILSE_OUT prepares to receive input if the next node 48*6ab0f5cdSMatthew Wilcox * is an IN or EXPECT, and then sends the given packet. 49*6ab0f5cdSMatthew Wilcox */ 50*6ab0f5cdSMatthew Wilcox HILSE_OUT = 0, 51*6ab0f5cdSMatthew Wilcox 52*6ab0f5cdSMatthew Wilcox /* HILSE_CTS checks if the loop is busy. */ 53*6ab0f5cdSMatthew Wilcox HILSE_CTS, 54*6ab0f5cdSMatthew Wilcox 55*6ab0f5cdSMatthew Wilcox /* HILSE_OUT_LAST sends the given command packet to 56*6ab0f5cdSMatthew Wilcox * the last configured/running device on the loop. 57*6ab0f5cdSMatthew Wilcox */ 58*6ab0f5cdSMatthew Wilcox HILSE_OUT_LAST, 59*6ab0f5cdSMatthew Wilcox 60*6ab0f5cdSMatthew Wilcox /* HILSE_OUT_DISC sends the given command packet to 61*6ab0f5cdSMatthew Wilcox * the next device past the last configured/running one. 62*6ab0f5cdSMatthew Wilcox */ 63*6ab0f5cdSMatthew Wilcox HILSE_OUT_DISC, 64*6ab0f5cdSMatthew Wilcox 65*6ab0f5cdSMatthew Wilcox /* HILSE_FUNC runs a callback function with given arguments. 66*6ab0f5cdSMatthew Wilcox * a positive return value causes the "ugly" branch to be taken. 67*6ab0f5cdSMatthew Wilcox */ 68*6ab0f5cdSMatthew Wilcox HILSE_FUNC, 69*6ab0f5cdSMatthew Wilcox 70*6ab0f5cdSMatthew Wilcox /* HILSE_IN simply expects any non-errored packet to arrive 71*6ab0f5cdSMatthew Wilcox * within arg usecs. 72*6ab0f5cdSMatthew Wilcox */ 73*6ab0f5cdSMatthew Wilcox HILSE_IN = 0x100, 74*6ab0f5cdSMatthew Wilcox 75*6ab0f5cdSMatthew Wilcox /* HILSE_EXPECT expects a particular packet to arrive 76*6ab0f5cdSMatthew Wilcox * within arg usecs, any other packet is considered an error. 77*6ab0f5cdSMatthew Wilcox */ 78*6ab0f5cdSMatthew Wilcox HILSE_EXPECT, 79*6ab0f5cdSMatthew Wilcox 80*6ab0f5cdSMatthew Wilcox /* HILSE_EXPECT_LAST as above but dev field should be last 81*6ab0f5cdSMatthew Wilcox * discovered/operational device. 82*6ab0f5cdSMatthew Wilcox */ 83*6ab0f5cdSMatthew Wilcox HILSE_EXPECT_LAST, 84*6ab0f5cdSMatthew Wilcox 85*6ab0f5cdSMatthew Wilcox /* HILSE_EXPECT_LAST as above but dev field should be first 86*6ab0f5cdSMatthew Wilcox * undiscovered/inoperational device. 87*6ab0f5cdSMatthew Wilcox */ 88*6ab0f5cdSMatthew Wilcox HILSE_EXPECT_DISC 89*6ab0f5cdSMatthew Wilcox }; 90*6ab0f5cdSMatthew Wilcox 91*6ab0f5cdSMatthew Wilcox typedef int (hilse_func) (hil_mlc *mlc, int arg); 92*6ab0f5cdSMatthew Wilcox struct hilse_node { 93*6ab0f5cdSMatthew Wilcox enum hilse_act act; /* How to process this node */ 94*6ab0f5cdSMatthew Wilcox union { 95*6ab0f5cdSMatthew Wilcox hilse_func *func; /* Function to call if HILSE_FUNC */ 96*6ab0f5cdSMatthew Wilcox hil_packet packet; /* Packet to send or to compare */ 97*6ab0f5cdSMatthew Wilcox } object; 98*6ab0f5cdSMatthew Wilcox int arg; /* Timeout in usec or parm for func */ 99*6ab0f5cdSMatthew Wilcox int good; /* Node to jump to on success */ 100*6ab0f5cdSMatthew Wilcox int bad; /* Node to jump to on error */ 101*6ab0f5cdSMatthew Wilcox int ugly; /* Node to jump to on timeout */ 102*6ab0f5cdSMatthew Wilcox }; 103*6ab0f5cdSMatthew Wilcox 104*6ab0f5cdSMatthew Wilcox /* Methods for back-end drivers, e.g. hp_sdc_mlc */ 105*6ab0f5cdSMatthew Wilcox typedef int (hil_mlc_cts) (hil_mlc *mlc); 106*6ab0f5cdSMatthew Wilcox typedef void (hil_mlc_out) (hil_mlc *mlc); 107*6ab0f5cdSMatthew Wilcox typedef int (hil_mlc_in) (hil_mlc *mlc, suseconds_t timeout); 108*6ab0f5cdSMatthew Wilcox 109*6ab0f5cdSMatthew Wilcox struct hil_mlc_devinfo { 110*6ab0f5cdSMatthew Wilcox uint8_t idd[16]; /* Device ID Byte and Describe Record */ 111*6ab0f5cdSMatthew Wilcox uint8_t rsc[16]; /* Security Code Header and Record */ 112*6ab0f5cdSMatthew Wilcox uint8_t exd[16]; /* Extended Describe Record */ 113*6ab0f5cdSMatthew Wilcox uint8_t rnm[16]; /* Device name as returned by RNM command */ 114*6ab0f5cdSMatthew Wilcox }; 115*6ab0f5cdSMatthew Wilcox 116*6ab0f5cdSMatthew Wilcox struct hil_mlc_serio_map { 117*6ab0f5cdSMatthew Wilcox hil_mlc *mlc; 118*6ab0f5cdSMatthew Wilcox int di_revmap; 119*6ab0f5cdSMatthew Wilcox int didx; 120*6ab0f5cdSMatthew Wilcox }; 121*6ab0f5cdSMatthew Wilcox 122*6ab0f5cdSMatthew Wilcox /* How many (possibly old/detached) devices the we try to keep track of */ 123*6ab0f5cdSMatthew Wilcox #define HIL_MLC_DEVMEM 16 124*6ab0f5cdSMatthew Wilcox 125*6ab0f5cdSMatthew Wilcox struct hil_mlc { 126*6ab0f5cdSMatthew Wilcox struct list_head list; /* hil_mlc is organized as linked list */ 127*6ab0f5cdSMatthew Wilcox 128*6ab0f5cdSMatthew Wilcox rwlock_t lock; 129*6ab0f5cdSMatthew Wilcox 130*6ab0f5cdSMatthew Wilcox void *priv; /* Data specific to a particular type of MLC */ 131*6ab0f5cdSMatthew Wilcox 132*6ab0f5cdSMatthew Wilcox int seidx; /* Current node in state engine */ 133*6ab0f5cdSMatthew Wilcox int istarted, ostarted; 134*6ab0f5cdSMatthew Wilcox 135*6ab0f5cdSMatthew Wilcox hil_mlc_cts *cts; 136*6ab0f5cdSMatthew Wilcox struct semaphore csem; /* Raised when loop idle */ 137*6ab0f5cdSMatthew Wilcox 138*6ab0f5cdSMatthew Wilcox hil_mlc_out *out; 139*6ab0f5cdSMatthew Wilcox struct semaphore osem; /* Raised when outpacket dispatched */ 140*6ab0f5cdSMatthew Wilcox hil_packet opacket; 141*6ab0f5cdSMatthew Wilcox 142*6ab0f5cdSMatthew Wilcox hil_mlc_in *in; 143*6ab0f5cdSMatthew Wilcox struct semaphore isem; /* Raised when a packet arrives */ 144*6ab0f5cdSMatthew Wilcox hil_packet ipacket[16]; 145*6ab0f5cdSMatthew Wilcox hil_packet imatch; 146*6ab0f5cdSMatthew Wilcox int icount; 147*6ab0f5cdSMatthew Wilcox struct timeval instart; 148*6ab0f5cdSMatthew Wilcox suseconds_t intimeout; 149*6ab0f5cdSMatthew Wilcox 150*6ab0f5cdSMatthew Wilcox int ddi; /* Last operational device id */ 151*6ab0f5cdSMatthew Wilcox int lcv; /* LCV to throttle loops */ 152*6ab0f5cdSMatthew Wilcox struct timeval lcv_tv; /* Time loop was started */ 153*6ab0f5cdSMatthew Wilcox 154*6ab0f5cdSMatthew Wilcox int di_map[7]; /* Maps below items to live devs */ 155*6ab0f5cdSMatthew Wilcox struct hil_mlc_devinfo di[HIL_MLC_DEVMEM]; 156*6ab0f5cdSMatthew Wilcox struct serio *serio[HIL_MLC_DEVMEM]; 157*6ab0f5cdSMatthew Wilcox struct hil_mlc_serio_map serio_map[HIL_MLC_DEVMEM]; 158*6ab0f5cdSMatthew Wilcox hil_packet serio_opacket[HIL_MLC_DEVMEM]; 159*6ab0f5cdSMatthew Wilcox int serio_oidx[HIL_MLC_DEVMEM]; 160*6ab0f5cdSMatthew Wilcox struct hil_mlc_devinfo di_scratch; /* Temporary area */ 161*6ab0f5cdSMatthew Wilcox 162*6ab0f5cdSMatthew Wilcox int opercnt; 163*6ab0f5cdSMatthew Wilcox 164*6ab0f5cdSMatthew Wilcox struct tasklet_struct *tasklet; 165*6ab0f5cdSMatthew Wilcox }; 166*6ab0f5cdSMatthew Wilcox 167*6ab0f5cdSMatthew Wilcox int hil_mlc_register(hil_mlc *mlc); 168*6ab0f5cdSMatthew Wilcox int hil_mlc_unregister(hil_mlc *mlc); 169