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

Subversion Repositories or1k

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

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Linux driver for the PC110 pad
3
 */
4
 
5
/**
6
 *      DOC: PC110 Digitizer Hardware
7
 *
8
 *      The pad provides triples of data. The first byte has
9
 *      0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down
10
 *      The second byte is bits 0-6 X
11
 *      The third is bits 0-6 Y
12
 *
13
 *      This is read internally and used to synthesize a stream of
14
 *      triples in the form expected from a PS/2 device. Specialist
15
 *      applications can choose to obtain the pad data in other formats
16
 *      including a debugging mode.
17
 *
18
 *      It would be good to add a joystick driver mode to this pad so
19
 *      that doom and other game playing are better. One possible approach
20
 *      would be to deactive the mouse mode while the joystick port is opened.
21
 */
22
 
23
/*
24
 *      History
25
 *
26
 *      0.0 1997-05-16 Alan Cox <alan@redhat.com> - Pad reader
27
 *      0.1 1997-05-19 Robin O'Leary <robin@acm.org> - PS/2 emulation
28
 *      0.2 1997-06-03 Robin O'Leary <robin@acm.org> - tap gesture
29
 *      0.3 1997-06-27 Alan Cox <alan@redhat.com> - 2.1 commit
30
 *      0.4 1997-11-09 Alan Cox <alan@redhat.com> - Single Unix VFS API changes
31
 *      0.5 2000-02-10 Alan Cox <alan@redhat.com> - 2.3.x cleanup, documentation
32
 */
33
 
34
#include <linux/module.h>
35
#include <linux/kernel.h>
36
#include <linux/signal.h>
37
#include <linux/errno.h>
38
#include <linux/mm.h>
39
#include <linux/miscdevice.h>
40
#include <linux/ptrace.h>
41
#include <linux/poll.h>
42
#include <linux/ioport.h>
43
#include <linux/interrupt.h>
44
#include <linux/smp_lock.h>
45
#include <linux/init.h>
46
 
47
#include <asm/signal.h>
48
#include <asm/io.h>
49
#include <asm/irq.h>
50
#include <asm/semaphore.h>
51
#include <linux/spinlock.h>
52
#include <asm/uaccess.h>
53
 
54
#include "pc110pad.h"
55
 
56
 
57
static struct pc110pad_params default_params = {
58
        mode:                   PC110PAD_PS2,
59
        bounce_interval:        50 MS,
60
        tap_interval:           200 MS,
61
        irq:                    10,
62
        io:                     0x15E0,
63
};
64
 
65
static struct pc110pad_params current_params;
66
 
67
 
68
/* driver/filesystem interface management */
69
static wait_queue_head_t queue;
70
static struct fasync_struct *asyncptr;
71
static int active;      /* number of concurrent open()s */
72
static struct semaphore reader_lock;
73
 
74
/**
75
 *      wake_readers:
76
 *
77
 *      Take care of letting any waiting processes know that
78
 *      now would be a good time to do a read().  Called
79
 *      whenever a state transition occurs, real or synthetic. Also
80
 *      issue any SIGIO's to programs that use SIGIO on mice (eg
81
 *      Executor)
82
 */
83
 
84
static void wake_readers(void)
85
{
86
        wake_up_interruptible(&queue);
87
        kill_fasync(&asyncptr, SIGIO, POLL_IN);
88
}
89
 
90
 
91
/*****************************************************************************/
92
/*
93
 * Deal with the messy business of synthesizing button tap and drag
94
 * events.
95
 *
96
 * Exports:
97
 *      notify_pad_up_down()
98
 *              Must be called whenever debounced pad up/down state changes.
99
 *      button_pending
100
 *              Flag is set whenever read_button() has new values
101
 *              to return.
102
 *      read_button()
103
 *              Obtains the current synthetic mouse button state.
104
 */
105
 
106
/*
107
 * These keep track of up/down transitions needed to generate the
108
 * synthetic mouse button events.  While recent_transition is set,
109
 * up/down events cause transition_count to increment.  tap_timer
110
 * turns off the recent_transition flag and may cause some synthetic
111
 * up/down mouse events to be created by incrementing synthesize_tap.
112
 */
113
 
114
static int button_pending;
115
static int recent_transition;
116
static int transition_count;
117
static int synthesize_tap;
118
static void tap_timeout(unsigned long data);
119
static struct timer_list tap_timer = { function: tap_timeout };
120
 
121
 
122
/**
123
 * tap_timeout:
124
 * @data: Unused
125
 *
126
 * This callback goes off a short time after an up/down transition;
127
 * before it goes off, transitions will be considered part of a
128
 * single PS/2 event and counted in transition_count.  Once the
129
 * timeout occurs the recent_transition flag is cleared and
130
 * any synthetic mouse up/down events are generated.
131
 */
132
 
133
static void tap_timeout(unsigned long data)
134
{
135
        if(!recent_transition)
136
        {
137
                printk(KERN_ERR "pc110pad: tap_timeout but no recent transition!\n");
138
        }
139
        if( transition_count==2 || transition_count==4 || transition_count==6 )
140
        {
141
                synthesize_tap+=transition_count;
142
                button_pending = 1;
143
                wake_readers();
144
        }
145
        recent_transition=0;
146
}
147
 
148
 
149
/**
150
 * notify_pad_up_down:
151
 *
152
 * Called by the raw pad read routines when a (debounced) up/down
153
 * transition is detected.
154
 */
155
 
156
void notify_pad_up_down(void)
157
{
158
        if(recent_transition)
159
        {
160
                transition_count++;
161
        }
162
        else
163
        {
164
                transition_count=1;
165
                recent_transition=1;
166
        }
167
        mod_timer(&tap_timer, jiffies + current_params.tap_interval);
168
 
169
        /* changes to transition_count can cause reported button to change */
170
        button_pending = 1;
171
        wake_readers();
172
}
173
 
174
/**
175
 *      read_button:
176
 *      @b: pointer to the button status.
177
 *
178
 *      The actual button state depends on what we are seeing. We have to check
179
 *      for the tap gesture and also for dragging.
180
 */
181
 
182
static void read_button(int *b)
183
{
184
        if(synthesize_tap)
185
        {
186
                *b=--synthesize_tap & 1;
187
        }
188
        else
189
        {
190
                *b=(!recent_transition && transition_count==3); /* drag */
191
        }
192
        button_pending=(synthesize_tap>0);
193
}
194
 
195
 
196
/*****************************************************************************/
197
/*
198
 * Read pad absolute co-ordinates and debounced up/down state.
199
 *
200
 * Exports:
201
 *      pad_irq()
202
 *              Function to be called whenever the pad signals
203
 *              that it has new data available.
204
 *      read_raw_pad()
205
 *              Returns the most current pad state.
206
 *      xy_pending
207
 *              Flag is set whenever read_raw_pad() has new values
208
 *              to return.
209
 * Imports:
210
 *      wake_readers()
211
 *              Called when movement occurs.
212
 *      notify_pad_up_down()
213
 *              Called when debounced up/down status changes.
214
 */
215
 
216
/*
217
 * These are up/down state and absolute co-ords read directly from pad
218
 */
219
 
220
static int raw_data[3];
221
static int raw_data_count;
222
static int raw_x, raw_y;        /* most recent absolute co-ords read */
223
static int raw_down;            /* raw up/down state */
224
static int debounced_down;      /* up/down state after debounce processing */
225
static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE;
226
                                /* set just after an up/down transition */
227
static int xy_pending;  /* set if new data have not yet been read */
228
 
229
/*
230
 * Timer goes off a short while after an up/down transition and copies
231
 * the value of raw_down to debounced_down.
232
 */
233
 
234
static void bounce_timeout(unsigned long data);
235
static struct timer_list bounce_timer = { function: bounce_timeout };
236
 
237
 
238
 
239
/**
240
 * bounce_timeout:
241
 * @data: Unused
242
 *
243
 * No further up/down transitions happened within the
244
 * bounce period, so treat this as a genuine transition.
245
 */
246
 
247
static void bounce_timeout(unsigned long data)
248
{
249
        switch(bounce)
250
        {
251
                case NO_BOUNCE:
252
                {
253
                        /*
254
                         * Strange; the timer callback should only go off if
255
                         * we were expecting to do bounce processing!
256
                         */
257
                        printk(KERN_WARNING "pc110pad, bounce_timeout: bounce flag not set!\n");
258
                        break;
259
                }
260
                case JUST_GONE_UP:
261
                {
262
                        /*
263
                         * The last up we spotted really was an up, so set
264
                         * debounced state the same as raw state.
265
                         */
266
                        bounce=NO_BOUNCE;
267
                        if(debounced_down==raw_down)
268
                        {
269
                                printk(KERN_WARNING "pc110pad, bounce_timeout: raw already debounced!\n");
270
                        }
271
                        debounced_down=raw_down;
272
 
273
                        notify_pad_up_down();
274
                        break;
275
                }
276
                case JUST_GONE_DOWN:
277
                {
278
                        /*
279
                         * We don't debounce down events, but we still time
280
                         * out soon after one occurs so we can avoid the (x,y)
281
                         * skittering that sometimes happens.
282
                         */
283
                        bounce=NO_BOUNCE;
284
                        break;
285
                }
286
        }
287
}
288
 
289
 
290
/**
291
 * pad_irq:
292
 * @irq: Interrupt number
293
 * @ptr: Unused
294
 * @regs: Unused
295
 *
296
 * Callback when pad's irq goes off; copies values in to raw_* globals;
297
 * initiates debounce processing. This isn't SMP safe however there are
298
 * no SMP machines with a PC110 touchpad on them.
299
 */
300
 
301
static void pad_irq(int irq, void *ptr, struct pt_regs *regs)
302
{
303
 
304
        /* Obtain byte from pad and prime for next byte */
305
        {
306
                int value=inb_p(current_params.io);
307
                int handshake=inb_p(current_params.io+2);
308
                outb_p(handshake | 1, current_params.io+2);
309
                outb_p(handshake &~1, current_params.io+2);
310
                inb_p(0x64);
311
 
312
                raw_data[raw_data_count++]=value;
313
        }
314
 
315
        if(raw_data_count==3)
316
        {
317
                int new_down=raw_data[0]&0x01;
318
                int new_x=raw_data[1];
319
                int new_y=raw_data[2];
320
                if(raw_data[0]&0x10) new_x+=128;
321
                if(raw_data[0]&0x80) new_x+=256;
322
                if(raw_data[0]&0x08) new_y+=128;
323
 
324
                if( (raw_x!=new_x) || (raw_y!=new_y) )
325
                {
326
                        raw_x=new_x;
327
                        raw_y=new_y;
328
                        xy_pending=1;
329
                }
330
 
331
                if(new_down != raw_down)
332
                {
333
                        /* Down state has changed.  raw_down always holds
334
                         * the most recently observed state.
335
                         */
336
                        raw_down=new_down;
337
 
338
                        /* Forget any earlier bounce processing */
339
                        if(bounce)
340
                        {
341
                                del_timer(&bounce_timer);
342
                                bounce=NO_BOUNCE;
343
                        }
344
 
345
                        if(new_down)
346
                        {
347
                                if(debounced_down)
348
                                {
349
                                        /* pad gone down, but we were reporting
350
                                         * it down anyway because we suspected
351
                                         * (correctly) that the last up was just
352
                                         * a bounce
353
                                         */
354
                                }
355
                                else
356
                                {
357
                                        bounce=JUST_GONE_DOWN;
358
                                        mod_timer(&bounce_timer,
359
                                                jiffies+current_params.bounce_interval);
360
                                        /* start new stroke/tap */
361
                                        debounced_down=new_down;
362
                                        notify_pad_up_down();
363
                                }
364
                        }
365
                        else /* just gone up */
366
                        {
367
                                if(recent_transition)
368
                                {
369
                                        /* early bounces are probably part of
370
                                         * a multi-tap gesture, so process
371
                                         * immediately
372
                                         */
373
                                        debounced_down=new_down;
374
                                        notify_pad_up_down();
375
                                }
376
                                else
377
                                {
378
                                        /* don't trust it yet */
379
                                        bounce=JUST_GONE_UP;
380
                                        mod_timer(&bounce_timer,
381
                                                jiffies+current_params.bounce_interval);
382
                                }
383
                        }
384
                }
385
                wake_readers();
386
                raw_data_count=0;
387
        }
388
}
389
 
390
/**
391
 *      read_raw_pad:
392
 *      @down: set if the pen is down
393
 *      @debounced: set if the debounced pen position is down
394
 *      @x: X position
395
 *      @y: Y position
396
 *
397
 *      Retrieve the data saved by the interrupt handler and indicate we
398
 *      have no more pending XY to do.
399
 *
400
 *      FIXME: We should switch to a spinlock for this.
401
 */
402
 
403
static void read_raw_pad(int *down, int *debounced, int *x, int *y)
404
{
405
        disable_irq(current_params.irq);
406
        {
407
                *down=raw_down;
408
                *debounced=debounced_down;
409
                *x=raw_x;
410
                *y=raw_y;
411
                xy_pending = 0;
412
        }
413
        enable_irq(current_params.irq);
414
}
415
 
416
/*****************************************************************************/
417
/*
418
 * Filesystem interface
419
 */
420
 
421
/*
422
 * Read returns byte triples, so we need to keep track of
423
 * how much of a triple has been read.  This is shared across
424
 * all processes which have this device open---not that anything
425
 * will make much sense in that case.
426
 */
427
static int read_bytes[3];
428
static int read_byte_count;
429
 
430
/**
431
 *      sample_raw:
432
 *      @d: sample buffer
433
 *
434
 *      Retrieve a triple of sample data.
435
 */
436
 
437
 
438
static void sample_raw(int d[3])
439
{
440
        d[0]=raw_data[0];
441
        d[1]=raw_data[1];
442
        d[2]=raw_data[2];
443
}
444
 
445
/**
446
 *      sample_rare:
447
 *      @d: sample buffer
448
 *
449
 *      Retrieve a triple of sample data and sanitize it. We do the needed
450
 *      scaling and masking to get the current status.
451
 */
452
 
453
 
454
static void sample_rare(int d[3])
455
{
456
        int thisd, thisdd, thisx, thisy;
457
 
458
        read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
459
 
460
        d[0]=(thisd?0x80:0)
461
           | (thisx/256)<<4
462
           | (thisdd?0x08:0)
463
           | (thisy/256)
464
        ;
465
        d[1]=thisx%256;
466
        d[2]=thisy%256;
467
}
468
 
469
/**
470
 *      sample_debug:
471
 *      @d: sample buffer
472
 *
473
 *      Retrieve a triple of sample data and mix it up with the state
474
 *      information in the gesture parser. Not useful for normal users but
475
 *      handy when debugging
476
 */
477
 
478
static void sample_debug(int d[3])
479
{
480
        int thisd, thisdd, thisx, thisy;
481
        int b;
482
        unsigned long flags;
483
 
484
        save_flags(flags);
485
        cli();
486
        read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
487
        d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce;
488
        d[1]=(recent_transition?0x80:0)+transition_count;
489
        read_button(&b);
490
        d[2]=(synthesize_tap<<4) | (b?0x01:0);
491
        restore_flags(flags);
492
}
493
 
494
/**
495
 *      sample_ps2:
496
 *      @d: sample buffer
497
 *
498
 *      Retrieve a triple of sample data and turn the debounced tap and
499
 *      stroke information into what appears to be a PS/2 mouse. This means
500
 *      the PC110 pad needs no funny application side support.
501
 */
502
 
503
 
504
static void sample_ps2(int d[3])
505
{
506
        static int lastx, lasty, lastd;
507
 
508
        int thisd, thisdd, thisx, thisy;
509
        int dx, dy, b;
510
 
511
        /*
512
         * Obtain the current mouse parameters and limit as appropriate for
513
         * the return data format.  Interrupts are only disabled while
514
         * obtaining the parameters, NOT during the puts_fs_byte() calls,
515
         * so paging in put_user() does not affect mouse tracking.
516
         */
517
        read_raw_pad(&thisd, &thisdd, &thisx, &thisy);
518
        read_button(&b);
519
 
520
        /* Now compare with previous readings.  Note that we use the
521
         * raw down flag rather than the debounced one.
522
         */
523
        if( (thisd && !lastd) /* new stroke */
524
         || (bounce!=NO_BOUNCE) )
525
        {
526
                dx=0;
527
                dy=0;
528
        }
529
        else
530
        {
531
                dx =  (thisx-lastx);
532
                dy = -(thisy-lasty);
533
        }
534
        lastx=thisx;
535
        lasty=thisy;
536
        lastd=thisd;
537
 
538
/*
539
        d[0]= ((dy<0)?0x20:0)
540
            | ((dx<0)?0x10:0)
541
            | 0x08
542
            | (b? 0x01:0x00)
543
        ;
544
*/
545
        d[0]= ((dy<0)?0x20:0)
546
            | ((dx<0)?0x10:0)
547
            | (b? 0x00:0x08)
548
        ;
549
        d[1]=dx;
550
        d[2]=dy;
551
}
552
 
553
 
554
/**
555
 *      fasync_pad:
556
 *      @fd:    file number for the file
557
 *      @filp:  file handle
558
 *      @on:    1 to add, 0 to remove a notifier
559
 *
560
 *      Update the queue of asynchronous event notifiers. We can use the
561
 *      same helper the mice do and that does almost everything we need.
562
 */
563
 
564
static int fasync_pad(int fd, struct file *filp, int on)
565
{
566
        int retval;
567
 
568
        retval = fasync_helper(fd, filp, on, &asyncptr);
569
        if (retval < 0)
570
                return retval;
571
        return 0;
572
}
573
 
574
 
575
/**
576
 *      close_pad:
577
 *      @inode: inode of pad
578
 *      @file: file handle to pad
579
 *
580
 *      Close access to the pad. We turn the pad power off if this is the
581
 *      last user of the pad. I've not actually measured the power draw but
582
 *      the DOS driver is careful to do this so we follow suit.
583
 */
584
 
585
static int close_pad(struct inode * inode, struct file * file)
586
{
587
        lock_kernel();
588
        fasync_pad(-1, file, 0);
589
        if (!--active)
590
                outb(0x30, current_params.io+2);  /* switch off digitiser */
591
        unlock_kernel();
592
        return 0;
593
}
594
 
595
 
596
/**
597
 *      open_pad:
598
 *      @inode: inode of pad
599
 *      @file: file handle to pad
600
 *
601
 *      Open access to the pad. We turn the pad off first (we turned it off
602
 *      on close but if this is the first open after a crash the state is
603
 *      indeterminate). The device has a small fifo so we empty that before
604
 *      we kick it back into action.
605
 */
606
 
607
static int open_pad(struct inode * inode, struct file * file)
608
{
609
        unsigned long flags;
610
 
611
        if (active++)
612
                return 0;
613
 
614
        save_flags(flags);
615
        cli();
616
        outb(0x30, current_params.io+2);        /* switch off digitiser */
617
        pad_irq(0,0,0);            /* read to flush any pending bytes */
618
        pad_irq(0,0,0);            /* read to flush any pending bytes */
619
        pad_irq(0,0,0);            /* read to flush any pending bytes */
620
        outb(0x38, current_params.io+2);        /* switch on digitiser */
621
        current_params = default_params;
622
        raw_data_count=0;                /* re-sync input byte counter */
623
        read_byte_count=0;               /* re-sync output byte counter */
624
        button_pending=0;
625
        recent_transition=0;
626
        transition_count=0;
627
        synthesize_tap=0;
628
        del_timer(&bounce_timer);
629
        del_timer(&tap_timer);
630
        restore_flags(flags);
631
 
632
        return 0;
633
}
634
 
635
 
636
/**
637
 *      write_pad:
638
 *      @file: File handle to the pad
639
 *      @buffer: Unused
640
 *      @count: Unused
641
 *      @ppos: Unused
642
 *
643
 *      Writes are disallowed. A true PS/2 mouse lets you write stuff. Everyone
644
 *      seems happy with this and not faking the write modes.
645
 */
646
 
647
static ssize_t write_pad(struct file * file, const char * buffer, size_t count, loff_t *ppos)
648
{
649
        return -EINVAL;
650
}
651
 
652
 
653
/*
654
 *      new_sample:
655
 *      @d: sample buffer
656
 *
657
 *      Fetch a new sample according the current mouse mode the pad is
658
 *      using.
659
 */
660
 
661
void new_sample(int d[3])
662
{
663
        switch(current_params.mode)
664
        {
665
                case PC110PAD_RAW:      sample_raw(d);          break;
666
                case PC110PAD_RARE:     sample_rare(d);         break;
667
                case PC110PAD_DEBUG:    sample_debug(d);        break;
668
                case PC110PAD_PS2:      sample_ps2(d);          break;
669
        }
670
}
671
 
672
 
673
/**
674
 * read_pad:
675
 * @file: File handle to pad
676
 * @buffer: Target for the mouse data
677
 * @count: Buffer length
678
 * @ppos: Offset (unused)
679
 *
680
 * Read data from the pad. We use the reader_lock to avoid mess when there are
681
 * two readers. This shouldnt be happening anyway but we play safe.
682
 */
683
 
684
static ssize_t read_pad(struct file * file, char * buffer, size_t count, loff_t *ppos)
685
{
686
        int r;
687
 
688
        down(&reader_lock);
689
        for(r=0; r<count; r++)
690
        {
691
                if(!read_byte_count)
692
                        new_sample(read_bytes);
693
                if(put_user(read_bytes[read_byte_count], buffer+r))
694
                {
695
                        r = -EFAULT;
696
                        break;
697
                }
698
                read_byte_count = (read_byte_count+1)%3;
699
        }
700
        up(&reader_lock);
701
        return r;
702
}
703
 
704
 
705
/**
706
 * pad_poll:
707
 * @file: File of the pad device
708
 * @wait: Poll table
709
 *
710
 * The pad is ready to read if there is a button or any position change
711
 * pending in the queue. The reading and interrupt routines maintain the
712
 * required state for us and do needed wakeups.
713
 */
714
 
715
static unsigned int pad_poll(struct file *file, poll_table * wait)
716
{
717
        poll_wait(file, &queue, wait);
718
        if(button_pending || xy_pending)
719
                return POLLIN | POLLRDNORM;
720
        return 0;
721
}
722
 
723
 
724
/**
725
 *      pad_ioctl;
726
 *      @inode: Inode of the pad
727
 *      @file: File handle to the pad
728
 *      @cmd: Ioctl command
729
 *      @arg: Argument pointer
730
 *
731
 *      The PC110 pad supports two ioctls both of which use the pc110pad_params
732
 *      structure. GETP queries the current pad status. SETP changes the pad
733
 *      configuration. Changing configuration during normal mouse operations
734
 *      may give momentarily odd results as things like tap gesture state
735
 *      may be lost.
736
 */
737
 
738
static int pad_ioctl(struct inode *inode, struct file * file,
739
        unsigned int cmd, unsigned long arg)
740
{
741
        struct pc110pad_params new;
742
 
743
        if (!inode)
744
                return -EINVAL;
745
 
746
        switch (cmd) {
747
        case PC110PADIOCGETP:
748
                new = current_params;
749
                if(copy_to_user((void *)arg, &new, sizeof(new)))
750
                        return -EFAULT;
751
                return 0;
752
 
753
        case PC110PADIOCSETP:
754
                if(copy_from_user(&new, (void *)arg, sizeof(new)))
755
                        return -EFAULT;
756
 
757
                if( (new.mode<PC110PAD_RAW)
758
                 || (new.mode>PC110PAD_PS2)
759
                 || (new.bounce_interval<0)
760
                 || (new.tap_interval<0)
761
                )
762
                        return -EINVAL;
763
 
764
                current_params.mode     = new.mode;
765
                current_params.bounce_interval  = new.bounce_interval;
766
                current_params.tap_interval     = new.tap_interval;
767
                return 0;
768
        }
769
        return -ENOTTY;
770
}
771
 
772
 
773
static struct file_operations pad_fops = {
774
        owner:          THIS_MODULE,
775
        read:           read_pad,
776
        write:          write_pad,
777
        poll:           pad_poll,
778
        ioctl:          pad_ioctl,
779
        open:           open_pad,
780
        release:        close_pad,
781
        fasync:         fasync_pad,
782
};
783
 
784
 
785
static struct miscdevice pc110_pad = {
786
        minor:          PC110PAD_MINOR,
787
        name:           "pc110 pad",
788
        fops:           &pad_fops,
789
};
790
 
791
 
792
/**
793
 *      pc110pad_init_driver:
794
 *
795
 *      We configure the pad with the default parameters (that is PS/2
796
 *      emulation mode. We then claim the needed I/O and interrupt resources.
797
 *      Finally as a matter of paranoia we turn the pad off until we are
798
 *      asked to open it by an application.
799
 */
800
 
801
static char banner[] __initdata = KERN_INFO "PC110 digitizer pad at 0x%X, irq %d.\n";
802
 
803
static int __init pc110pad_init_driver(void)
804
{
805
        init_MUTEX(&reader_lock);
806
        current_params = default_params;
807
 
808
        if (request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0)) {
809
                printk(KERN_ERR "pc110pad: Unable to get IRQ.\n");
810
                return -EBUSY;
811
        }
812
        if (!request_region(current_params.io, 4, "pc110pad"))  {
813
                printk(KERN_ERR "pc110pad: I/O area in use.\n");
814
                free_irq(current_params.irq,0);
815
                return -EBUSY;
816
        }
817
        init_waitqueue_head(&queue);
818
        printk(banner, current_params.io, current_params.irq);
819
        misc_register(&pc110_pad);
820
        outb(0x30, current_params.io+2);        /* switch off digitiser */
821
        return 0;
822
}
823
 
824
/*
825
 *      pc110pad_exit_driver:
826
 *
827
 *      Free the resources we acquired when the module was loaded. We also
828
 *      turn the pad off to be sure we don't leave it using power.
829
 */
830
 
831
static void __exit pc110pad_exit_driver(void)
832
{
833
        outb(0x30, current_params.io+2);        /* switch off digitiser */
834
        if (current_params.irq)
835
                free_irq(current_params.irq, 0);
836
        current_params.irq = 0;
837
        release_region(current_params.io, 4);
838
        misc_deregister(&pc110_pad);
839
}
840
 
841
module_init(pc110pad_init_driver);
842
module_exit(pc110pad_exit_driver);
843
 
844
MODULE_AUTHOR("Alan Cox, Robin O'Leary");
845
MODULE_DESCRIPTION("Driver for the touchpad on the IBM PC110 palmtop");
846
MODULE_LICENSE("GPL");
847
 
848
EXPORT_NO_SYMBOLS;

powered by: WebSVN 2.1.0

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