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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [input/] [serio/] [hil_mlc.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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/list.h>
63
 
64
MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
65
MODULE_DESCRIPTION("HIL MLC serio");
66
MODULE_LICENSE("Dual BSD/GPL");
67
 
68
EXPORT_SYMBOL(hil_mlc_register);
69
EXPORT_SYMBOL(hil_mlc_unregister);
70
 
71
#define PREFIX "HIL MLC: "
72
 
73
static LIST_HEAD(hil_mlcs);
74
static DEFINE_RWLOCK(hil_mlcs_lock);
75
static struct timer_list        hil_mlcs_kicker;
76
static int                      hil_mlcs_probe;
77
 
78
static void hil_mlcs_process(unsigned long unused);
79
DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0);
80
 
81
 
82
/* #define HIL_MLC_DEBUG */
83
 
84
/********************** Device info/instance management **********************/
85
 
86
static void hil_mlc_clear_di_map(hil_mlc *mlc, int val)
87
{
88
        int j;
89
 
90
        for (j = val; j < 7 ; j++)
91
                mlc->di_map[j] = -1;
92
}
93
 
94
static void hil_mlc_clear_di_scratch(hil_mlc *mlc)
95
{
96
        memset(&mlc->di_scratch, 0, sizeof(mlc->di_scratch));
97
}
98
 
99
static void hil_mlc_copy_di_scratch(hil_mlc *mlc, int idx)
100
{
101
        memcpy(&mlc->di[idx], &mlc->di_scratch, sizeof(mlc->di_scratch));
102
}
103
 
104
static int hil_mlc_match_di_scratch(hil_mlc *mlc)
105
{
106
        int idx;
107
 
108
        for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
109
                int j, found = 0;
110
 
111
                /* In-use slots are not eligible. */
112
                for (j = 0; j < 7 ; j++)
113
                        if (mlc->di_map[j] == idx)
114
                                found++;
115
 
116
                if (found)
117
                        continue;
118
 
119
                if (!memcmp(mlc->di + idx, &mlc->di_scratch,
120
                                sizeof(mlc->di_scratch)))
121
                        break;
122
        }
123
        return idx >= HIL_MLC_DEVMEM ? -1 : idx;
124
}
125
 
126
static int hil_mlc_find_free_di(hil_mlc *mlc)
127
{
128
        int idx;
129
 
130
        /* TODO: Pick all-zero slots first, failing that,
131
         * randomize the slot picked among those eligible.
132
         */
133
        for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
134
                int j, found = 0;
135
 
136
                for (j = 0; j < 7 ; j++)
137
                        if (mlc->di_map[j] == idx)
138
                                found++;
139
 
140
                if (!found)
141
                        break;
142
        }
143
 
144
        return idx; /* Note: It is guaranteed at least one above will match */
145
}
146
 
147
static inline void hil_mlc_clean_serio_map(hil_mlc *mlc)
148
{
149
        int idx;
150
 
151
        for (idx = 0; idx < HIL_MLC_DEVMEM; idx++) {
152
                int j, found = 0;
153
 
154
                for (j = 0; j < 7 ; j++)
155
                        if (mlc->di_map[j] == idx)
156
                                found++;
157
 
158
                if (!found)
159
                        mlc->serio_map[idx].di_revmap = -1;
160
        }
161
}
162
 
163
static void hil_mlc_send_polls(hil_mlc *mlc)
164
{
165
        int did, i, cnt;
166
        struct serio *serio;
167
        struct serio_driver *drv;
168
 
169
        i = cnt = 0;
170
        did = (mlc->ipacket[0] & HIL_PKT_ADDR_MASK) >> 8;
171
        serio = did ? mlc->serio[mlc->di_map[did - 1]] : NULL;
172
        drv = (serio != NULL) ? serio->drv : NULL;
173
 
174
        while (mlc->icount < 15 - i) {
175
                hil_packet p;
176
 
177
                p = mlc->ipacket[i];
178
                if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
179
                        if (drv && drv->interrupt) {
180
                                drv->interrupt(serio, 0, 0);
181
                                drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
182
                                drv->interrupt(serio, HIL_PKT_CMD >> 8,  0);
183
                                drv->interrupt(serio, HIL_CMD_POL + cnt, 0);
184
                        }
185
 
186
                        did = (p & HIL_PKT_ADDR_MASK) >> 8;
187
                        serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL;
188
                        drv = (serio != NULL) ? serio->drv : NULL;
189
                        cnt = 0;
190
                }
191
 
192
                cnt++;
193
                i++;
194
 
195
                if (drv && drv->interrupt) {
196
                        drv->interrupt(serio, (p >> 24), 0);
197
                        drv->interrupt(serio, (p >> 16) & 0xff, 0);
198
                        drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
199
                        drv->interrupt(serio, p & 0xff, 0);
200
                }
201
        }
202
}
203
 
204
/*************************** State engine *********************************/
205
 
206
#define HILSEN_SCHED    0x000100        /* Schedule the tasklet         */
207
#define HILSEN_BREAK    0x000200        /* Wait until next pass         */
208
#define HILSEN_UP       0x000400        /* relative node#, decrement    */
209
#define HILSEN_DOWN     0x000800        /* relative node#, increment    */
210
#define HILSEN_FOLLOW   0x001000        /* use retval as next node#     */
211
 
212
#define HILSEN_MASK     0x0000ff
213
#define HILSEN_START    0
214
#define HILSEN_RESTART  1
215
#define HILSEN_DHR      9
216
#define HILSEN_DHR2     10
217
#define HILSEN_IFC      14
218
#define HILSEN_HEAL0    16
219
#define HILSEN_HEAL     18
220
#define HILSEN_ACF      21
221
#define HILSEN_ACF2     22
222
#define HILSEN_DISC0    25
223
#define HILSEN_DISC     27
224
#define HILSEN_MATCH    40
225
#define HILSEN_OPERATE  41
226
#define HILSEN_PROBE    44
227
#define HILSEN_DSR      52
228
#define HILSEN_REPOLL   55
229
#define HILSEN_IFCACF   58
230
#define HILSEN_END      60
231
 
232
#define HILSEN_NEXT     (HILSEN_DOWN | 1)
233
#define HILSEN_SAME     (HILSEN_DOWN | 0)
234
#define HILSEN_LAST     (HILSEN_UP | 1)
235
 
236
#define HILSEN_DOZE     (HILSEN_SAME | HILSEN_SCHED | HILSEN_BREAK)
237
#define HILSEN_SLEEP    (HILSEN_SAME | HILSEN_BREAK)
238
 
239
static int hilse_match(hil_mlc *mlc, int unused)
240
{
241
        int rc;
242
 
243
        rc = hil_mlc_match_di_scratch(mlc);
244
        if (rc == -1) {
245
                rc = hil_mlc_find_free_di(mlc);
246
                if (rc == -1)
247
                        goto err;
248
 
249
#ifdef HIL_MLC_DEBUG
250
                printk(KERN_DEBUG PREFIX "new in slot %i\n", rc);
251
#endif
252
                hil_mlc_copy_di_scratch(mlc, rc);
253
                mlc->di_map[mlc->ddi] = rc;
254
                mlc->serio_map[rc].di_revmap = mlc->ddi;
255
                hil_mlc_clean_serio_map(mlc);
256
                serio_rescan(mlc->serio[rc]);
257
                return -1;
258
        }
259
 
260
        mlc->di_map[mlc->ddi] = rc;
261
#ifdef HIL_MLC_DEBUG
262
        printk(KERN_DEBUG PREFIX "same in slot %i\n", rc);
263
#endif
264
        mlc->serio_map[rc].di_revmap = mlc->ddi;
265
        hil_mlc_clean_serio_map(mlc);
266
        return 0;
267
 
268
 err:
269
        printk(KERN_ERR PREFIX "Residual device slots exhausted, close some serios!\n");
270
        return 1;
271
}
272
 
273
/* An LCV used to prevent runaway loops, forces 5 second sleep when reset. */
274
static int hilse_init_lcv(hil_mlc *mlc, int unused)
275
{
276
        struct timeval tv;
277
 
278
        do_gettimeofday(&tv);
279
 
280
        if (mlc->lcv && (tv.tv_sec - mlc->lcv_tv.tv_sec) < 5)
281
                return -1;
282
 
283
        mlc->lcv_tv = tv;
284
        mlc->lcv = 0;
285
 
286
        return 0;
287
}
288
 
289
static int hilse_inc_lcv(hil_mlc *mlc, int lim)
290
{
291
        return mlc->lcv++ >= lim ? -1 : 0;
292
}
293
 
294
#if 0
295
static 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) */
304
static 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
 
312
static 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
 
325
static 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
 
333
static 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
 
383
static 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
 
398
static 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
 
413
static 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
 
427
static 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
 
462
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
 
584
static 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 = node->arg;
607
        do_gettimeofday(&(mlc->instart));
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
614
static int doze;
615
static int seidx; /* For debug */
616
#endif
617
 
618
static 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
                        goto out2;
690
                /* Prepare to receive input */
691
                if ((node + 1)->act & HILSE_IN)
692
                        hilse_setup_input(mlc, node + 1);
693
 
694
        out2:
695
                write_unlock_irqrestore(&mlc->lock, flags);
696
 
697
                if (down_trylock(&mlc->osem)) {
698
                        nextidx = HILSEN_DOZE;
699
                        break;
700
                }
701
                up(&mlc->osem);
702
 
703
                write_lock_irqsave(&mlc->lock, flags);
704
                if (!mlc->ostarted) {
705
                        mlc->ostarted = 1;
706
                        mlc->opacket = pack;
707
                        mlc->out(mlc);
708
                        nextidx = HILSEN_DOZE;
709
                        write_unlock_irqrestore(&mlc->lock, flags);
710
                        break;
711
                }
712
                mlc->ostarted = 0;
713
                do_gettimeofday(&(mlc->instart));
714
                write_unlock_irqrestore(&mlc->lock, flags);
715
                nextidx = HILSEN_NEXT;
716
                break;
717
 
718
        case HILSE_CTS:
719
                write_lock_irqsave(&mlc->lock, flags);
720
                nextidx = mlc->cts(mlc) ? node->bad : node->good;
721
                write_unlock_irqrestore(&mlc->lock, flags);
722
                break;
723
 
724
        default:
725
                BUG();
726
        }
727
 
728
#ifdef HIL_MLC_DEBUG
729
        if (nextidx == HILSEN_DOZE)
730
                doze++;
731
#endif
732
 
733
        while (nextidx & HILSEN_SCHED) {
734
                struct timeval tv;
735
 
736
                if (!sched_long)
737
                        goto sched;
738
 
739
                do_gettimeofday(&tv);
740
                tv.tv_usec += USEC_PER_SEC * (tv.tv_sec - mlc->instart.tv_sec);
741
                tv.tv_usec -= mlc->instart.tv_usec;
742
                if (tv.tv_usec >= mlc->intimeout) goto sched;
743
                tv.tv_usec = (mlc->intimeout - tv.tv_usec) * HZ / USEC_PER_SEC;
744
                if (!tv.tv_usec) goto sched;
745
                mod_timer(&hil_mlcs_kicker, jiffies + tv.tv_usec);
746
                break;
747
        sched:
748
                tasklet_schedule(&hil_mlcs_tasklet);
749
                break;
750
        }
751
 
752
        if (nextidx & HILSEN_DOWN)
753
                mlc->seidx += nextidx & HILSEN_MASK;
754
        else if (nextidx & HILSEN_UP)
755
                mlc->seidx -= nextidx & HILSEN_MASK;
756
        else
757
                mlc->seidx = nextidx & HILSEN_MASK;
758
 
759
        if (nextidx & HILSEN_BREAK)
760
                return 1;
761
 
762
        return 0;
763
}
764
 
765
/******************** tasklet context functions **************************/
766
static void hil_mlcs_process(unsigned long unused)
767
{
768
        struct list_head *tmp;
769
 
770
        read_lock(&hil_mlcs_lock);
771
        list_for_each(tmp, &hil_mlcs) {
772
                struct hil_mlc *mlc = list_entry(tmp, hil_mlc, list);
773
                while (hilse_donode(mlc) == 0) {
774
#ifdef HIL_MLC_DEBUG
775
                        if (mlc->seidx != 41 &&
776
                            mlc->seidx != 42 &&
777
                            mlc->seidx != 43)
778
                                printk(KERN_DEBUG PREFIX " + ");
779
#endif
780
                }
781
        }
782
        read_unlock(&hil_mlcs_lock);
783
}
784
 
785
/************************* Keepalive timer task *********************/
786
 
787
void hil_mlcs_timer(unsigned long data)
788
{
789
        hil_mlcs_probe = 1;
790
        tasklet_schedule(&hil_mlcs_tasklet);
791
        /* Re-insert the periodic task. */
792
        if (!timer_pending(&hil_mlcs_kicker))
793
                mod_timer(&hil_mlcs_kicker, jiffies + HZ);
794
}
795
 
796
/******************** user/kernel context functions **********************/
797
 
798
static int hil_mlc_serio_write(struct serio *serio, unsigned char c)
799
{
800
        struct hil_mlc_serio_map *map;
801
        struct hil_mlc *mlc;
802
        struct serio_driver *drv;
803
        uint8_t *idx, *last;
804
 
805
        map = serio->port_data;
806
        BUG_ON(map == NULL);
807
 
808
        mlc = map->mlc;
809
        BUG_ON(mlc == NULL);
810
 
811
        mlc->serio_opacket[map->didx] |=
812
                ((hil_packet)c) << (8 * (3 - mlc->serio_oidx[map->didx]));
813
 
814
        if (mlc->serio_oidx[map->didx] >= 3) {
815
                /* for now only commands */
816
                if (!(mlc->serio_opacket[map->didx] & HIL_PKT_CMD))
817
                        return -EIO;
818
                switch (mlc->serio_opacket[map->didx] & HIL_PKT_DATA_MASK) {
819
                case HIL_CMD_IDD:
820
                        idx = mlc->di[map->didx].idd;
821
                        goto emu;
822
                case HIL_CMD_RSC:
823
                        idx = mlc->di[map->didx].rsc;
824
                        goto emu;
825
                case HIL_CMD_EXD:
826
                        idx = mlc->di[map->didx].exd;
827
                        goto emu;
828
                case HIL_CMD_RNM:
829
                        idx = mlc->di[map->didx].rnm;
830
                        goto emu;
831
                default:
832
                        break;
833
                }
834
                mlc->serio_oidx[map->didx] = 0;
835
                mlc->serio_opacket[map->didx] = 0;
836
        }
837
 
838
        mlc->serio_oidx[map->didx]++;
839
        return -EIO;
840
 emu:
841
        drv = serio->drv;
842
        BUG_ON(drv == NULL);
843
 
844
        last = idx + 15;
845
        while ((last != idx) && (*last == 0))
846
                last--;
847
 
848
        while (idx != last) {
849
                drv->interrupt(serio, 0, 0);
850
                drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
851
                drv->interrupt(serio, 0, 0);
852
                drv->interrupt(serio, *idx, 0);
853
                idx++;
854
        }
855
        drv->interrupt(serio, 0, 0);
856
        drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
857
        drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
858
        drv->interrupt(serio, *idx, 0);
859
 
860
        mlc->serio_oidx[map->didx] = 0;
861
        mlc->serio_opacket[map->didx] = 0;
862
 
863
        return 0;
864
}
865
 
866
static int hil_mlc_serio_open(struct serio *serio)
867
{
868
        struct hil_mlc_serio_map *map;
869
        struct hil_mlc *mlc;
870
 
871
        if (serio_get_drvdata(serio) != NULL)
872
                return -EBUSY;
873
 
874
        map = serio->port_data;
875
        BUG_ON(map == NULL);
876
 
877
        mlc = map->mlc;
878
        BUG_ON(mlc == NULL);
879
 
880
        return 0;
881
}
882
 
883
static void hil_mlc_serio_close(struct serio *serio)
884
{
885
        struct hil_mlc_serio_map *map;
886
        struct hil_mlc *mlc;
887
 
888
        map = serio->port_data;
889
        BUG_ON(map == NULL);
890
 
891
        mlc = map->mlc;
892
        BUG_ON(mlc == NULL);
893
 
894
        serio_set_drvdata(serio, NULL);
895
        serio->drv = NULL;
896
        /* TODO wake up interruptable */
897
}
898
 
899
static const struct serio_device_id hil_mlc_serio_id = {
900
        .type = SERIO_HIL_MLC,
901
        .proto = SERIO_HIL,
902
        .extra = SERIO_ANY,
903
        .id = SERIO_ANY,
904
};
905
 
906
int hil_mlc_register(hil_mlc *mlc)
907
{
908
        int i;
909
        unsigned long flags;
910
 
911
        BUG_ON(mlc == NULL);
912
 
913
        mlc->istarted = 0;
914
        mlc->ostarted = 0;
915
 
916
        rwlock_init(&mlc->lock);
917
        init_MUTEX(&mlc->osem);
918
 
919
        init_MUTEX(&mlc->isem);
920
        mlc->icount = -1;
921
        mlc->imatch = 0;
922
 
923
        mlc->opercnt = 0;
924
 
925
        init_MUTEX_LOCKED(&(mlc->csem));
926
 
927
        hil_mlc_clear_di_scratch(mlc);
928
        hil_mlc_clear_di_map(mlc, 0);
929
        for (i = 0; i < HIL_MLC_DEVMEM; i++) {
930
                struct serio *mlc_serio;
931
                hil_mlc_copy_di_scratch(mlc, i);
932
                mlc_serio = kzalloc(sizeof(*mlc_serio), GFP_KERNEL);
933
                mlc->serio[i] = mlc_serio;
934
                snprintf(mlc_serio->name, sizeof(mlc_serio->name)-1, "HIL_SERIO%d", i);
935
                snprintf(mlc_serio->phys, sizeof(mlc_serio->phys)-1, "HIL%d", i);
936
                mlc_serio->id                   = hil_mlc_serio_id;
937
                mlc_serio->write                = hil_mlc_serio_write;
938
                mlc_serio->open                 = hil_mlc_serio_open;
939
                mlc_serio->close                = hil_mlc_serio_close;
940
                mlc_serio->port_data            = &(mlc->serio_map[i]);
941
                mlc->serio_map[i].mlc           = mlc;
942
                mlc->serio_map[i].didx          = i;
943
                mlc->serio_map[i].di_revmap     = -1;
944
                mlc->serio_opacket[i]           = 0;
945
                mlc->serio_oidx[i]              = 0;
946
                serio_register_port(mlc_serio);
947
        }
948
 
949
        mlc->tasklet = &hil_mlcs_tasklet;
950
 
951
        write_lock_irqsave(&hil_mlcs_lock, flags);
952
        list_add_tail(&mlc->list, &hil_mlcs);
953
        mlc->seidx = HILSEN_START;
954
        write_unlock_irqrestore(&hil_mlcs_lock, flags);
955
 
956
        tasklet_schedule(&hil_mlcs_tasklet);
957
        return 0;
958
}
959
 
960
int hil_mlc_unregister(hil_mlc *mlc)
961
{
962
        struct list_head *tmp;
963
        unsigned long flags;
964
        int i;
965
 
966
        BUG_ON(mlc == NULL);
967
 
968
        write_lock_irqsave(&hil_mlcs_lock, flags);
969
        list_for_each(tmp, &hil_mlcs)
970
                if (list_entry(tmp, hil_mlc, list) == mlc)
971
                        goto found;
972
 
973
        /* not found in list */
974
        write_unlock_irqrestore(&hil_mlcs_lock, flags);
975
        tasklet_schedule(&hil_mlcs_tasklet);
976
        return -ENODEV;
977
 
978
 found:
979
        list_del(tmp);
980
        write_unlock_irqrestore(&hil_mlcs_lock, flags);
981
 
982
        for (i = 0; i < HIL_MLC_DEVMEM; i++) {
983
                serio_unregister_port(mlc->serio[i]);
984
                mlc->serio[i] = NULL;
985
        }
986
 
987
        tasklet_schedule(&hil_mlcs_tasklet);
988
        return 0;
989
}
990
 
991
/**************************** Module interface *************************/
992
 
993
static int __init hil_mlc_init(void)
994
{
995
        init_timer(&hil_mlcs_kicker);
996
        hil_mlcs_kicker.expires = jiffies + HZ;
997
        hil_mlcs_kicker.function = &hil_mlcs_timer;
998
        add_timer(&hil_mlcs_kicker);
999
 
1000
        tasklet_enable(&hil_mlcs_tasklet);
1001
 
1002
        return 0;
1003
}
1004
 
1005
static void __exit hil_mlc_exit(void)
1006
{
1007
        del_timer(&hil_mlcs_kicker);
1008
 
1009
        tasklet_disable(&hil_mlcs_tasklet);
1010
        tasklet_kill(&hil_mlcs_tasklet);
1011
}
1012
 
1013
module_init(hil_mlc_init);
1014
module_exit(hil_mlc_exit);

powered by: WebSVN 2.1.0

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