OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [hil/] [hil_mlc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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 tasket 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 rwlock_t                 hil_mlcs_lock = RW_LOCK_UNLOCKED;
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_dev *dev;
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
        dev = (serio != NULL) ? serio->dev : 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 (dev == NULL || dev->interrupt == NULL) goto skip;
164
 
165
                        dev->interrupt(serio, 0, 0);
166
                        dev->interrupt(serio, HIL_ERR_INT >> 16, 0);
167
                        dev->interrupt(serio, HIL_PKT_CMD >> 8, 0);
168
                        dev->interrupt(serio, HIL_CMD_POL + cnt, 0);
169
                skip:
170
                        did = (p & HIL_PKT_ADDR_MASK) >> 8;
171
                        serio = did ? &(mlc->serio[mlc->di_map[did-1]]) : NULL;
172
                        dev = (serio != NULL) ? serio->dev : NULL;
173
                        cnt = 0;
174
                }
175
                cnt++; i++;
176
                if (dev == NULL || dev->interrupt == NULL) continue;
177
                dev->interrupt(serio, (p >> 24), 0);
178
                dev->interrupt(serio, (p >> 16) & 0xff, 0);
179
                dev->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
180
                dev->interrupt(serio, p & 0xff, 0);
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_dev *dev;
732
        uint8_t *idx, *last;
733
 
734
        map = serio->driver;
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
        dev = serio->dev;
775
        if (dev == NULL) {
776
                BUG();
777
                return -EIO;
778
        }
779
        last = idx + 15;
780
        while ((last != idx) && (*last == 0)) last--;
781
 
782
        while (idx != last) {
783
                dev->interrupt(serio, 0, 0);
784
                dev->interrupt(serio, HIL_ERR_INT >> 16, 0);
785
                dev->interrupt(serio, 0, 0);
786
                dev->interrupt(serio, *idx, 0);
787
                idx++;
788
        }
789
        dev->interrupt(serio, 0, 0);
790
        dev->interrupt(serio, HIL_ERR_INT >> 16, 0);
791
        dev->interrupt(serio, HIL_PKT_CMD >> 8, 0);
792
        dev->interrupt(serio, *idx, 0);
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->private != NULL) return -EBUSY;
805
 
806
        map = serio->driver;
807
        if (map == NULL) {
808
                BUG();
809
                return -ENODEV;
810
        }
811
        mlc = map->mlc;
812
        if (mlc == NULL) {
813
                BUG();
814
                return -ENODEV;
815
        }
816
 
817
        mlc->inc_use_count();
818
 
819
        return 0;
820
}
821
 
822
static void hil_mlc_serio_close(struct serio *serio) {
823
        struct hil_mlc_serio_map *map;
824
        struct hil_mlc *mlc;
825
 
826
        map = serio->driver;
827
        if (map == NULL) {
828
                BUG();
829
                return;
830
        }
831
        mlc = map->mlc;
832
        if (mlc == NULL) {
833
                BUG();
834
                return;
835
        }
836
 
837
        mlc->dec_use_count();
838
 
839
        serio->private = NULL;
840
        serio->dev = NULL;
841
        /* TODO wake up interruptable */
842
}
843
 
844
int hil_mlc_register(hil_mlc *mlc) {
845
        int i;
846
        unsigned long flags;
847
 
848
        MOD_INC_USE_COUNT;
849
        if (mlc == NULL) {
850
                MOD_DEC_USE_COUNT;
851
                return -EINVAL;
852
        }
853
 
854
        mlc->istarted = 0;
855
        mlc->ostarted = 0;
856
 
857
        mlc->lock = RW_LOCK_UNLOCKED;
858
        init_MUTEX(&(mlc->osem));
859
 
860
        init_MUTEX(&(mlc->isem));
861
        mlc->icount = -1;
862
        mlc->imatch = 0;
863
 
864
        mlc->opercnt = 0;
865
 
866
        init_MUTEX_LOCKED(&(mlc->csem));
867
 
868
        hil_mlc_clear_di_scratch(mlc);
869
        hil_mlc_clear_di_map(mlc, 0);
870
        for (i = 0; i < HIL_MLC_DEVMEM; i++) {
871
                hil_mlc_copy_di_scratch(mlc, i);
872
                memset(&(mlc->serio[i]), 0, sizeof(mlc->serio[0]));
873
                mlc->serio[i].type              = SERIO_HIL | SERIO_HIL_MLC;
874
                mlc->serio[i].write             = hil_mlc_serio_write;
875
                mlc->serio[i].open              = hil_mlc_serio_open;
876
                mlc->serio[i].close             = hil_mlc_serio_close;
877
                mlc->serio[i].driver            = &(mlc->serio_map[i]);
878
                mlc->serio_map[i].mlc           = mlc;
879
                mlc->serio_map[i].didx          = i;
880
                mlc->serio_map[i].di_revmap     = -1;
881
                mlc->serio_opacket[i]           = 0;
882
                mlc->serio_oidx[i]              = 0;
883
                serio_register_port(&(mlc->serio[i]));
884
        }
885
 
886
        mlc->tasklet = &hil_mlcs_tasklet;
887
 
888
        write_lock_irqsave(&hil_mlcs_lock, flags);
889
        list_add_tail(&mlc->list, &hil_mlcs);
890
        mlc->seidx = HILSEN_START;
891
        write_unlock_irqrestore(&hil_mlcs_lock, flags);
892
 
893
        tasklet_schedule(&hil_mlcs_tasklet);
894
        return 0;
895
}
896
 
897
int hil_mlc_unregister(hil_mlc *mlc) {
898
        struct list_head *tmp;
899
        unsigned long flags;
900
        int i;
901
 
902
        if (mlc == NULL)
903
                return -EINVAL;
904
 
905
        write_lock_irqsave(&hil_mlcs_lock, flags);
906
        list_for_each(tmp, &hil_mlcs) {
907
                if (list_entry(tmp, hil_mlc, list) == mlc)
908
                        goto found;
909
        }
910
 
911
        /* not found in list */
912
        write_unlock_irqrestore(&hil_mlcs_lock, flags);
913
        tasklet_schedule(&hil_mlcs_tasklet);
914
        return -ENODEV;
915
 
916
 found:
917
        list_del(tmp);
918
        write_unlock_irqrestore(&hil_mlcs_lock, flags);
919
        MOD_DEC_USE_COUNT;
920
 
921
        for (i = 0; i < HIL_MLC_DEVMEM; i++)
922
                serio_unregister_port(&(mlc->serio[i]));
923
 
924
        tasklet_schedule(&hil_mlcs_tasklet);
925
        return 0;
926
}
927
 
928
/**************************** Module interface *************************/
929
 
930
static int __init hil_mlc_init(void)
931
{
932
        init_timer(&hil_mlcs_kicker);
933
        hil_mlcs_kicker.expires = jiffies + HZ;
934
        hil_mlcs_kicker.function = &hil_mlcs_timer;
935
        add_timer(&hil_mlcs_kicker);
936
 
937
        tasklet_enable(&hil_mlcs_tasklet);
938
 
939
        return 0;
940
}
941
 
942
static void __exit hil_mlc_exit(void)
943
{
944
        del_timer(&hil_mlcs_kicker);
945
 
946
        tasklet_disable(&hil_mlcs_tasklet);
947
        tasklet_kill(&hil_mlcs_tasklet);
948
}
949
 
950
module_init(hil_mlc_init);
951
module_exit(hil_mlc_exit);

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.