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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      LASI PS/2 keyboard/psaux driver for HP-PARISC workstations
3
 *
4
 *      (c) Copyright 1999 The Puffin Group Inc.
5
 *      by Alex deVries <adevries@thepuffingroup.com>
6
 *      Copyright 1999, 2000 Philipp Rumpf <prumpf@tux.org>
7
 *
8
 *      2000/10/26      Debacker Xavier (debackex@esiee.fr)
9
 *      implemented the psaux and controlled the mouse scancode based on pc_keyb.c
10
 *                      Marteau Thomas (marteaut@esiee.fr)
11
 *      fixed leds control
12
 *
13
 *      2001/12/17      Marteau Thomas (marteaut@esiee.fr)
14
 *      get nice initialisation procedure
15
 */
16
 
17
#include <linux/config.h>
18
 
19
#include <linux/types.h>
20
#include <linux/ptrace.h>       /* interrupt.h wants struct pt_regs defined */
21
#include <linux/interrupt.h>
22
#include <linux/sched.h>        /* for request_irq/free_irq */
23
#include <linux/ioport.h>
24
#include <linux/kernel.h>
25
#include <linux/wait.h>
26
#include <linux/delay.h>
27
#include <linux/errno.h>
28
#include <linux/init.h>
29
#include <linux/module.h>
30
#include <linux/pc_keyb.h>
31
#include <linux/kbd_kern.h>
32
 
33
/* mouse includes */
34
#include <linux/miscdevice.h>
35
#include <linux/slab.h>
36
#include <linux/random.h>
37
#include <linux/spinlock.h>
38
#include <linux/smp_lock.h>
39
#include <linux/poll.h>
40
 
41
#include <asm/hardware.h>
42
#include <asm/keyboard.h>
43
#include <asm/gsc.h>
44
#include <asm/uaccess.h>
45
 
46
/* HP specific LASI PS/2 keyboard and psaux constants */
47
#define AUX_REPLY_ACK   0xFA    /* Command byte ACK. */
48
#define AUX_RESEND      0xFE    /* Sent by the keyb. Asking for resending the last command. */
49
#define AUX_RECONNECT   0xAA    /* scancode when ps2 device is plugged (back) in */
50
 
51
#define LASI_PSAUX_OFFSET 0x0100 /* offset from keyboard to psaux port */
52
 
53
#define LASI_ID         0x00    /* ID and reset port offsets */
54
#define LASI_RESET      0x00
55
#define LASI_RCVDATA    0x04    /* receive and transmit port offsets */
56
#define LASI_XMTDATA    0x04
57
#define LASI_CONTROL    0x08    /* see: control register bits */
58
#define LASI_STATUS     0x0C    /* see: status register bits */
59
 
60
/* control register bits */
61
#define LASI_CTRL_ENBL  0x01    /* enable interface */
62
#define LASI_CTRL_LPBXR 0x02    /* loopback operation */
63
#define LASI_CTRL_DIAG  0x20    /* directly control clock/data line */
64
#define LASI_CTRL_DATDIR 0x40   /* data line direct control */
65
#define LASI_CTRL_CLKDIR 0x80   /* clock line direct control */
66
 
67
/* status register bits */
68
#define LASI_STAT_RBNE  0x01
69
#define LASI_STAT_TBNE  0x02
70
#define LASI_STAT_TERR  0x04
71
#define LASI_STAT_PERR  0x08
72
#define LASI_STAT_CMPINTR 0x10
73
#define LASI_STAT_DATSHD 0x40
74
#define LASI_STAT_CLKSHD 0x80
75
 
76
static spinlock_t       kbd_controller_lock = SPIN_LOCK_UNLOCKED;
77
static unsigned long lasikbd_hpa;
78
 
79
static volatile int cmd_status;
80
 
81
static inline u8 read_input(unsigned long hpa)
82
{
83
        return gsc_readb(hpa+LASI_RCVDATA);
84
}
85
 
86
static inline u8 read_control(unsigned long hpa)
87
{
88
        return gsc_readb(hpa+LASI_CONTROL);
89
}
90
 
91
static inline void write_control(u8 val, unsigned long hpa)
92
{
93
        gsc_writeb(val, hpa+LASI_CONTROL);
94
}
95
 
96
static inline u8 read_status(unsigned long hpa)
97
{
98
        return gsc_readb(hpa+LASI_STATUS);
99
}
100
 
101
/* XXX should this grab the spinlock? */
102
 
103
static int write_output(u8 val, unsigned long hpa)
104
{
105
        int wait = 250;
106
 
107
        while (read_status(hpa) & LASI_STAT_TBNE) {
108
                if (!--wait) {
109
                        return 0;
110
                }
111
                mdelay(1);
112
        }
113
        gsc_writeb(val, hpa+LASI_XMTDATA);
114
 
115
        return 1;
116
}
117
 
118
/* XXX should this grab the spinlock? */
119
 
120
static u8 wait_input(unsigned long hpa)
121
{
122
        int wait = 250;
123
 
124
        while (!(read_status(hpa) & LASI_STAT_RBNE)) {
125
                if (!--wait) {
126
                        return 0;
127
                }
128
                mdelay(1);
129
        }
130
        return read_input(hpa);
131
}
132
 
133
/* This function is the PA-RISC adaptation of i386 source */
134
 
135
static inline int aux_write_ack(u8 val)
136
{
137
      return write_output(val, lasikbd_hpa+LASI_PSAUX_OFFSET);
138
}
139
 
140
/* This is wrong, should do something like the pc driver, which sends
141
 * the command up to 3 times at 1 second intervals, checking once
142
 * per millisecond for an acknowledge.
143
 */
144
 
145
static void lasikbd_leds(unsigned char leds)
146
{
147
        int loop = 1000;
148
 
149
        if (!lasikbd_hpa)
150
                return;
151
 
152
        cmd_status=2;
153
        while (cmd_status!=0 && --loop > 0) {
154
                write_output(KBD_CMD_SET_LEDS, lasikbd_hpa);
155
                mdelay(5);
156
        }
157
 
158
        cmd_status=2;
159
        while (cmd_status!=0 && --loop > 0) {
160
                write_output(leds, lasikbd_hpa);
161
                mdelay(5);
162
        }
163
 
164
        cmd_status=2;
165
        while (cmd_status!=0 && --loop > 0) {
166
           write_output(KBD_CMD_ENABLE, lasikbd_hpa);
167
           mdelay(5);
168
        }
169
        if (loop <= 0)
170
                printk("lasikbd_leds: timeout\n");
171
}
172
 
173
#if 0
174
/* this might become useful again at some point.  not now  -prumpf */
175
int lasi_ps2_test(void *hpa)
176
{
177
        u8 control,c;
178
        int i, ret = 0;
179
 
180
        control = read_control(hpa);
181
        write_control(control | LASI_CTRL_LPBXR | LASI_CTRL_ENBL, hpa);
182
 
183
        for (i=0; i<256; i++) {
184
                write_output(i, hpa);
185
 
186
                while (!(read_status(hpa) & LASI_STAT_RBNE))
187
                    /* just wait */;
188
 
189
                c = read_input(hpa);
190
                if (c != i)
191
                        ret--;
192
        }
193
 
194
        write_control(control, hpa);
195
 
196
        return ret;
197
}
198
#endif 
199
 
200
static int init_keyb(unsigned long hpa)
201
{
202
        int res = 0;
203
        unsigned long flags;
204
 
205
        spin_lock_irqsave(&kbd_controller_lock, flags);
206
 
207
        if (write_output(KBD_CMD_SET_LEDS, hpa) &&
208
                        wait_input(hpa) == AUX_REPLY_ACK &&
209
                        write_output(0, hpa) &&
210
                        wait_input(hpa) == AUX_REPLY_ACK &&
211
                        write_output(KBD_CMD_ENABLE, hpa) &&
212
                        wait_input(hpa) == AUX_REPLY_ACK)
213
                res = 1;
214
 
215
        spin_unlock_irqrestore(&kbd_controller_lock, flags);
216
 
217
        return res;
218
}
219
 
220
 
221
static void __init lasi_ps2_reset(unsigned long hpa)
222
{
223
        u8 control;
224
 
225
        /* reset the interface */
226
        gsc_writeb(0xff, hpa+LASI_RESET);
227
        gsc_writeb(0x0 , hpa+LASI_RESET);
228
 
229
        /* enable it */
230
        control = read_control(hpa);
231
        write_control(control | LASI_CTRL_ENBL, hpa);
232
}
233
 
234
/* Greatly inspired by pc_keyb.c */
235
 
236
/*
237
 * Wait for keyboard controller input buffer to drain.
238
 *
239
 * Don't use 'jiffies' so that we don't depend on
240
 * interrupts..
241
 *
242
 * Quote from PS/2 System Reference Manual:
243
 *
244
 * "Address hex 0060 and address hex 0064 should be written only when
245
 * the input-buffer-full bit and output-buffer-full bit in the
246
 * Controller Status register are set 0."
247
 */
248
#ifdef CONFIG_PSMOUSE
249
 
250
static struct aux_queue *queue;
251
static unsigned char    mouse_reply_expected;
252
static int              aux_count;
253
 
254
static int fasync_aux(int fd, struct file *filp, int on)
255
{
256
        int retval;
257
 
258
        retval = fasync_helper(fd, filp, on, &queue->fasync);
259
        if (retval < 0)
260
                return retval;
261
 
262
        return 0;
263
}
264
 
265
 
266
 
267
static inline void handle_mouse_scancode(unsigned char scancode)
268
{
269
        if (mouse_reply_expected) {
270
                if (scancode == AUX_REPLY_ACK) {
271
                        mouse_reply_expected--;
272
                        return;
273
                }
274
                mouse_reply_expected = 0;
275
        }
276
        else if (scancode == AUX_RECONNECT) {
277
                queue->head = queue->tail = 0;  /* Flush input queue */
278
                return;
279
        }
280
 
281
        add_mouse_randomness(scancode);
282
        if (aux_count) {
283
                int head = queue->head;
284
 
285
                queue->buf[head] = scancode;
286
                head = (head + 1) & (AUX_BUF_SIZE-1);
287
 
288
                if (head != queue->tail) {
289
                        queue->head = head;
290
                        kill_fasync(&queue->fasync, SIGIO, POLL_IN);
291
                        wake_up_interruptible(&queue->proc_list);
292
                }
293
        }
294
}
295
 
296
static inline int queue_empty(void)
297
{
298
        return queue->head == queue->tail;
299
}
300
 
301
static unsigned char get_from_queue(void)
302
{
303
        unsigned char result;
304
        unsigned long flags;
305
 
306
        spin_lock_irqsave(&kbd_controller_lock, flags);
307
        result = queue->buf[queue->tail];
308
        queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
309
        spin_unlock_irqrestore(&kbd_controller_lock, flags);
310
 
311
        return result;
312
}
313
 
314
 
315
/*
316
 * Write to the aux device.
317
 */
318
 
319
static ssize_t write_aux(struct file * file, const char * buffer,
320
                         size_t count, loff_t *ppos)
321
{
322
        ssize_t retval = 0;
323
 
324
        if (count) {
325
                ssize_t written = 0;
326
 
327
                if (count > 32)
328
                        count = 32; /* Limit to 32 bytes. */
329
                do {
330
                        char c;
331
                        get_user(c, buffer++);
332
                        written++;
333
                } while (--count);
334
                retval = -EIO;
335
                if (written) {
336
                        retval = written;
337
                        file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
338
                }
339
        }
340
 
341
        return retval;
342
}
343
 
344
 
345
 
346
static ssize_t read_aux(struct file * file, char * buffer,
347
                        size_t count, loff_t *ppos)
348
{
349
        DECLARE_WAITQUEUE(wait, current);
350
        ssize_t i = count;
351
        unsigned char c;
352
 
353
        if (queue_empty()) {
354
                if (file->f_flags & O_NONBLOCK)
355
                        return -EAGAIN;
356
                add_wait_queue(&queue->proc_list, &wait);
357
repeat:
358
                set_current_state(TASK_INTERRUPTIBLE);
359
                if (queue_empty() && !signal_pending(current)) {
360
                        schedule();
361
                        goto repeat;
362
                }
363
                current->state = TASK_RUNNING;
364
                remove_wait_queue(&queue->proc_list, &wait);
365
        }
366
        while (i > 0 && !queue_empty()) {
367
                c = get_from_queue();
368
                put_user(c, buffer++);
369
                i--;
370
        }
371
        if (count-i) {
372
                file->f_dentry->d_inode->i_atime = CURRENT_TIME;
373
                return count-i;
374
        }
375
        if (signal_pending(current))
376
                return -ERESTARTSYS;
377
        return 0;
378
}
379
 
380
 
381
static int open_aux(struct inode * inode, struct file * file)
382
{
383
        if (aux_count++)
384
                return 0;
385
 
386
        queue->head = queue->tail = 0;   /* Flush input queue */
387
        aux_count = 1;
388
        aux_write_ack(AUX_ENABLE_DEV);  /* Enable aux device */
389
 
390
        return 0;
391
}
392
 
393
 
394
/* No kernel lock held - fine */
395
static unsigned int aux_poll(struct file *file, poll_table * wait)
396
{
397
 
398
        poll_wait(file, &queue->proc_list, wait);
399
        if (!queue_empty())
400
                return POLLIN | POLLRDNORM;
401
        return 0;
402
}
403
 
404
 
405
static int release_aux(struct inode * inode, struct file * file)
406
{
407
        lock_kernel();
408
        fasync_aux(-1, file, 0);
409
        if (--aux_count) {
410
                unlock_kernel();
411
                return 0;
412
        }
413
        unlock_kernel();
414
        return 0;
415
}
416
 
417
static struct file_operations psaux_fops = {
418
        read:           read_aux,
419
        write:          write_aux,
420
        poll:           aux_poll,
421
        open:           open_aux,
422
        release:        release_aux,
423
        fasync:         fasync_aux,
424
};
425
 
426
static struct miscdevice psaux_mouse = {
427
        minor:          PSMOUSE_MINOR,
428
        name:           "psaux",
429
        fops:           &psaux_fops,
430
};
431
 
432
#endif /* CONFIG_PSMOUSE */
433
 
434
 
435
/* This function is looking at the PS2 controller and empty the two buffers */
436
 
437
static u8 handle_lasikbd_event(unsigned long hpa)
438
{
439
        u8 status_keyb,status_mouse,scancode,id;
440
        extern void handle_at_scancode(int); /* in drivers/char/keyb_at.c */
441
 
442
        /* Mask to get the base address of the PS/2 controller */
443
        id = gsc_readb(hpa+LASI_ID) & 0x0f;
444
 
445
        if (id==1)
446
                hpa -= LASI_PSAUX_OFFSET;
447
 
448
        status_keyb = read_status(hpa);
449
        status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
450
 
451
        while ((status_keyb|status_mouse) & LASI_STAT_RBNE){
452
 
453
                while (status_keyb & LASI_STAT_RBNE) {
454
 
455
                scancode = read_input(hpa);
456
 
457
                /* XXX don't know if this is a valid fix, but filtering
458
                 * 0xfa avoids 'unknown scancode' errors on, eg, capslock
459
                 * on some keyboards.
460
                 */
461
 
462
                if (scancode == AUX_REPLY_ACK)
463
                        cmd_status=0;
464
 
465
                else if (scancode == AUX_RESEND)
466
                        cmd_status=1;
467
                else
468
                        handle_at_scancode(scancode);
469
 
470
                status_keyb =read_status(hpa);
471
                }
472
 
473
#ifdef CONFIG_PSMOUSE
474
                while (status_mouse & LASI_STAT_RBNE) {
475
                        scancode = read_input(hpa+LASI_PSAUX_OFFSET);
476
                        handle_mouse_scancode(scancode);
477
                        status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
478
                }
479
                status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
480
#endif /* CONFIG_PSMOUSE */
481
                status_keyb = read_status(hpa);
482
        }
483
 
484
        tasklet_schedule(&keyboard_tasklet);
485
        return (status_keyb|status_mouse);
486
}
487
 
488
extern struct pt_regs *kbd_pt_regs;
489
 
490
static void lasikbd_interrupt(int irq, void *dev, struct pt_regs *regs)
491
{
492
        kbd_pt_regs = regs;
493
        handle_lasikbd_event((unsigned long) dev);
494
}
495
 
496
extern int pckbd_translate(unsigned char, unsigned char *, char);
497
extern int pckbd_setkeycode(unsigned int, unsigned int);
498
extern int pckbd_getkeycode(unsigned int);
499
 
500
static struct kbd_ops gsc_ps2_kbd_ops = {
501
        setkeycode:     pckbd_setkeycode,
502
        getkeycode:     pckbd_getkeycode,
503
        translate:      pckbd_translate,
504
        leds:           lasikbd_leds,
505
#ifdef CONFIG_MAGIC_SYSRQ
506
        sysrq_key:      0x54,
507
        sysrq_xlate:    hp_ps2kbd_sysrq_xlate,
508
#endif
509
};
510
 
511
 
512
 
513
#if 1
514
/* XXX: HACK !!!
515
 * remove this function and the call in hil_kbd.c
516
 * if hp_psaux.c/hp_keyb.c is converted to the input layer... */
517
int register_ps2_keybfuncs(void)
518
{
519
        gsc_ps2_kbd_ops.leds = NULL;
520
        register_kbd_ops(&gsc_ps2_kbd_ops);
521
}
522
EXPORT_SYMBOL(register_ps2_keybfuncs);
523
#endif
524
 
525
 
526
static int __init
527
lasi_ps2_register(struct parisc_device *dev)
528
{
529
        unsigned long hpa = dev->hpa;
530
        char *name;
531
        int device_found = 0;
532
        u8 id;
533
 
534
        id = gsc_readb(hpa+LASI_ID) & 0x0f;
535
 
536
        switch (id) {
537
        case 0:
538
                name = "keyboard";
539
                lasikbd_hpa = hpa;      /* save "hpa" for lasikbd_leds() */
540
                break;
541
        case 1:
542
                name = "psaux";
543
                break;
544
        default:
545
                printk(KERN_WARNING "%s: Unknown PS/2 port (id=%d) - ignored.\n",
546
                        __FUNCTION__, id );
547
                return 0;
548
        }
549
 
550
        /* reset the PS/2 port */
551
        lasi_ps2_reset(hpa);
552
 
553
        switch (id) {
554
        case 0:
555
                device_found = init_keyb(hpa);
556
                if (device_found) register_kbd_ops(&gsc_ps2_kbd_ops);
557
                break;
558
        case 1:
559
#ifdef CONFIG_PSMOUSE
560
                queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
561
                if (!queue)
562
                        return -ENOMEM;
563
 
564
                memset(queue, 0, sizeof(*queue));
565
                queue->head = queue->tail = 0;
566
                init_waitqueue_head(&queue->proc_list);
567
 
568
                misc_register(&psaux_mouse);
569
 
570
                aux_write_ack(AUX_ENABLE_DEV);
571
                /* try it a second time, this will give status if the device is
572
                 * available */
573
                device_found = aux_write_ack(AUX_ENABLE_DEV);
574
                break;
575
#else
576
                /* return without printing any unnecessary and misleading info */
577
                return 0;
578
#endif
579
        } /* of case */
580
 
581
        if (device_found) {
582
        /* Here we claim only if we have a device attached */
583
                /* allocate the irq and memory region for that device */
584
                if (!dev->irq)
585
                return -ENODEV;
586
 
587
                if (request_irq(dev->irq, lasikbd_interrupt, 0, name, (void *)hpa))
588
                return -ENODEV;
589
 
590
                if (!request_mem_region(hpa, LASI_STATUS + 4, name))
591
                return -ENODEV;
592
        }
593
 
594
        printk(KERN_INFO "PS/2 %s port at 0x%08lx (irq %d) found, "
595
                         "%sdevice attached.\n",
596
                        name, hpa, dev->irq, device_found ? "":"no ");
597
 
598
        return 0;
599
}
600
 
601
static struct parisc_device_id lasi_psaux_tbl[] = {
602
        { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 },
603
        { 0, } /* 0 terminated list */
604
};
605
 
606
MODULE_DEVICE_TABLE(parisc, lasi_psaux_tbl);
607
 
608
static struct parisc_driver lasi_psaux_driver = {
609
        name:           "Lasi psaux",
610
        id_table:       lasi_psaux_tbl,
611
        probe:          lasi_ps2_register,
612
};
613
 
614
static int __init gsc_ps2_init(void)
615
{
616
        return register_parisc_driver(&lasi_psaux_driver);
617
}
618
 
619
module_init(gsc_ps2_init);

powered by: WebSVN 2.1.0

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