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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [char/] [mc68328digi.c] - Blame information for rev 199

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

Line No. Rev Author Line
1 199 simons
/* mc68328digi.c
2
 *
3
 * Linux driver to make the PalmPilot's touchpad behave
4
 * like a PS/2 mouse.
5
 *
6
 * My apologies, this is currently a complete mess. It'll notice taps
7
 * on Copilot and a real Pilot, but can't figure out the coordinates on the Pilot.
8
 *
9
 * Based on touchpad driver.
10
 * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
11
 *                     The Silver Hammer Group, Ltd.
12
 *
13
 * Original History
14
 * -------
15
 *      0.0 1997-05-16 Alan Cox <alan@cymru.net> - Pad reader
16
 *      0.1 1997-05-19 Robin O'Leary <robin@acm.org> - PS/2 emulation
17
 *      0.2 1997-06-03 Robin O'Leary <robin@acm.org> - tap gesture
18
 *      0.3 1997-07-10 Robin O'Leary <robin@acm.org> - sticky drag
19
 *
20
 * Distribution
21
 * ------------
22
 * Copyright (C) 1997-06-18 Robin O'Leary <robin@acm.org>  All rights reserved.
23
 * This program is free software; you can redistribute it and/or modify
24
 * it under the terms of the GNU General Public License as published by
25
 * the Free Software Foundation; either version 2 of the License, or
26
 * (at your option) any later version.
27
 *
28
 * Get the latest version from ftp://swan.ml.org/pub/pc110/
29
 */
30
 
31
#include <linux/config.h>
32
#include <linux/module.h>
33
#include <linux/delay.h>
34
#include <linux/kernel.h>
35
#include <linux/busmouse.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/ioport.h>
42
#include <linux/interrupt.h>
43
 
44
#include <asm/signal.h>
45
#include <asm/io.h>
46
#include <asm/irq.h>
47
 
48
#include "mc68328digi.h"
49
 
50
 
51
static struct mc68328digi_params default_params = {
52
        MC68328DIGI_PS2,        /* read mode */
53
        50 MS,          /* bounce interval */
54
        800 MS,         /* sticky-drag */
55
        300 MS,         /* tap interval */
56
        10,             /* IRQ */
57
        0x15E0,         /* I/O port */
58
        0,               /* Not calibrated */
59
        1<<16,  0,       /* X calibration values (unity) */
60
        1<<16,  0        /* Y calibration values (unity) */
61
};
62
 
63
 
64
static struct mc68328digi_params current_params;
65
 
66
 
67
/* driver/filesystem interface management */
68
static struct wait_queue *queue;
69
static struct fasync_struct *asyncptr;
70
static int active=0;     /* number of concurrent open()s */
71
 
72
 
73
/*
74
 * Utility to reset a timer to go off some time in the future.
75
 */
76
static void set_timer_callback(struct timer_list *timer, int ticks)
77
{
78
        cli();
79
        del_timer(timer);
80
        timer->expires = jiffies+ticks;
81
        add_timer(timer);
82
        sti();
83
}
84
 
85
 
86
/* Take care of letting any waiting processes know that
87
 * now would be a good time to do a read().  Called
88
 * whenever a state transition occurs, real or synthetic.
89
 */
90
static void wake_readers(void)
91
{
92
        wake_up_interruptible(&queue);
93
        if(asyncptr)
94
                kill_fasync(asyncptr, SIGIO);
95
}
96
 
97
 
98
/*****************************************************************************/
99
/*
100
 * Deal with the messy business of synthesizing button tap and drag
101
 * events.
102
 *
103
 * Exports:
104
 *      notify_digi_up_down()
105
 *              Must be called whenever debounced pad up/down state changes.
106
 *      button_pending
107
 *              Flag is set whenever read_button() has new values
108
 *              to return.
109
 *      read_button()
110
 *              Obtains the current synthetic mouse button state.
111
 */
112
 
113
/* These keep track of up/down transitions needed to generate the
114
 * synthetic mouse button events.  While recent_transition is set,
115
 * up/down events cause transition_count to increment.  tap_timer
116
 * turns off the recent_transition flag and may cause some synthetic
117
 * up/down mouse events to be created by incrementing synthesize_tap.
118
 */
119
static int button_pending=0;
120
static int recent_transition=0;
121
static int transition_count=0;
122
static int synthesize_tap=0;
123
static void tap_timeout(unsigned long data);
124
static struct timer_list tap_timer = { NULL, NULL, 0, 0, tap_timeout };
125
 
126
 
127
/* This callback goes off a short time after an up/down transition;
128
 * before it goes off, transitions will be considered part of a
129
 * single PS/2 event and counted in transition_count.  Once the
130
 * timeout occurs the recent_transition flag is cleared and
131
 * any synthetic mouse up/down events are generated.
132
 */
133
static void tap_timeout(unsigned long data)
134
{
135
        printk("tap_timeout\n");
136
        if(!recent_transition)
137
        {
138
                printk("mc68328digi: tap_timeout but no recent transition!\n");
139
        }
140
        if( (transition_count==2)
141
         || (transition_count==4)
142
         || (transition_count==6) )
143
        {
144
                synthesize_tap+=transition_count;
145
                button_pending = 1;
146
                wake_readers();
147
        }
148
        recent_transition=0;
149
}
150
 
151
 
152
static void read_button(int *b)
153
{
154
        if(synthesize_tap)
155
        {
156
                *b=--synthesize_tap & 1;
157
        }
158
        else
159
        {
160
                *b=(!recent_transition && transition_count==3); /* drag */
161
        }
162
        button_pending=(synthesize_tap>0);
163
}
164
 
165
 
166
 
167
/*****************************************************************************/
168
/*
169
 * Read pad absolute co-ordinates and debounced up/down state.
170
 *
171
 * Exports:
172
 *      pad_irq()
173
 *              Function to be called whenever the pad signals
174
 *              that it has new data available.
175
 *      read_raw_digi()
176
 *              Returns the most current pad state.
177
 *      xy_pending
178
 *              Flag is set whenever read_raw_digi() has new values
179
 *              to return.
180
 * Imports:
181
 *      wake_readers()
182
 *              Called when movement occurs.
183
 *      notify_digi_up_down()
184
 *              Called when debounced up/down status changes.
185
 */
186
 
187
/* These are up/down state and absolute co-ords read directly from pad */
188
static int raw_data[3];
189
static int raw_data_count=0;
190
static int raw_x=0, raw_y=0;      /* most recent absolute co-ords read */
191
static int raw_down=0;           /* raw up/down state */
192
static int debounced_down=0;     /* up/down state after debounce processing */
193
static int is_new_stroke=0;      /* set when xy are discontinuous */
194
static enum {
195
        NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN, STICKY_DRAG_UP
196
} bounce=NO_BOUNCE;
197
                                /* set just after an up/down transition */
198
static int xy_pending=0; /* set if new data have not yet been read */
199
 
200
/* Timer goes off a short while after an up/down transition and copies
201
 * the value of raw_down to debounced_down.
202
 */
203
static void bounce_timeout(unsigned long data);
204
static struct timer_list bounce_timer = { NULL, NULL, 0, 0, bounce_timeout };
205
 
206
 
207
/* Called by the raw pad read routines when a (debounced) up/down
208
 * transition is detected.
209
 */
210
void notify_digi_up_down(void)
211
{
212
        if(recent_transition)
213
        {
214
                transition_count++;
215
        }
216
        else
217
        {
218
                transition_count=1;
219
                recent_transition=1;
220
        }
221
        set_timer_callback(&tap_timer, current_params.tap_interval);
222
 
223
        /* changes to transition_count can cause reported button to change */
224
        button_pending = 1;
225
        is_new_stroke=1;
226
        wake_readers();
227
}
228
 
229
 
230
 
231
static void bounce_timeout(unsigned long data)
232
{
233
        /* No further up/down transitions happened within the
234
         * bounce period, so treat this as a genuine transition.
235
         */
236
        switch(bounce)
237
        {
238
                case NO_BOUNCE:
239
                {
240
                        /* Strange; the timer callback should only go off if
241
                         * we were expecting to do bounce processing!
242
                         */
243
                        printk("mc68328digi, bounce_timeout: bounce flag not set!\n");
244
                        break;
245
                }
246
                case JUST_GONE_UP:
247
                case STICKY_DRAG_UP:
248
                {
249
                        /* The last up we spotted really was an up, so set
250
                         * debounced state the same as raw state.
251
                         */
252
                        bounce=NO_BOUNCE;
253
                        if(debounced_down==raw_down)
254
                        {
255
                                printk("mc68328digi, bounce_timeout: raw already debounced!\n");
256
                        }
257
                        debounced_down=raw_down;
258
                        notify_digi_up_down();
259
                        break;
260
                }
261
                case JUST_GONE_DOWN:
262
                {
263
                        /* We don't debounce down events, but we still time
264
                         * out soon after one occurs so we can avoid the (x,y)
265
                         * skittering that sometimes happens.
266
                         */
267
                        bounce=NO_BOUNCE;
268
                        break;
269
                }
270
        }
271
}
272
 
273
static void handle_raw(int new_x, int new_y, int new_down);
274
 
275
static void release_timeout(void);
276
static struct timer_list release_timer = { NULL, NULL, 0, 0, release_timeout };
277
static void release_timeout(void)
278
{
279
        (*((volatile unsigned long*)0xFFFFF304)) |= (1<<20);
280
 
281
        handle_raw(raw_x, raw_y, 0);
282
 
283
        (*((volatile unsigned long*)0xFFFFF304)) &= ~(1<<20);   /* Enable interrupt */
284
}
285
 
286
 
287
/*
288
 * Callback when pad's irq goes off; copies values in to raw_* globals;
289
 * initiates debounce processing.
290
 */
291
void digi_interrupt(int irq, void *ptr, struct pt_regs *regs)
292
{
293
        unsigned long flags;
294
        int new_x, new_y, new_down;
295
        volatile int i;
296
 
297
/*      set_timer_callback(&release_timer, 1);*/
298
 
299
        save_flags(flags); cli();
300
 
301
#define PORTF_DIR (*(volatile unsigned char*)0xFFFFF428)
302
#define PORTF_DAT (*(volatile unsigned char*)0xFFFFF429)
303
#define PORTF_PUP (*(volatile unsigned char*)0xFFFFF42A)
304
#define PORTF_SEL (*(volatile unsigned char*)0xFFFFF42B)
305
 
306
#define PORTM_DIR (*(volatile unsigned char*)0xFFFFF448)
307
#define PORTM_DAT (*(volatile unsigned char*)0xFFFFF449)
308
#define PORTM_PUP (*(volatile unsigned char*)0xFFFFF44A)
309
#define PORTM_SEL (*(volatile unsigned char*)0xFFFFF44B)
310
 
311
#define SPIMCONT (*(volatile unsigned short*)0xFFFFF802)
312
#define SPIMDATA (*(volatile unsigned short*)0xFFFFF800)
313
 
314
 
315
#define SPIMCONT_IRQEN  0x40
316
#define SPIMCONT_IRQ    0x80
317
#define SPIMCONT_XCH    0x100
318
#define SPIMCONT_EN     0x200
319
 
320
#define PF_DigiYVOff    0x01
321
#define PF_DigiYGOn     0x02
322
#define PF_DigiXVOff    0x04
323
#define PF_DigiXGOn     0x08
324
#define PF_LCDEnable    0x10
325
#define PF_LCDVccOff    0x20
326
#define PF_LCDVeeOn     0x40
327
#define PF_ADSelect     0x80
328
 
329
#define PF_DigiMask     0x0f
330
#define PF_DigiOff      (PF_DigiYVOff|PF_DigiXVOff)
331
#define PF_DigiTap      (PF_DigiXGOn|PF_DigiYVOff|PF_DigiXVOff)
332
#define PF_DigiGetY     (PF_DigiXGOn|PF_DigiYVOff)
333
#define PF_DigiGetX     (PF_DigiXVOff|PF_DigiYGOn)
334
 
335
#define PM_VCCFAIL      0x04
336
#define PM_DOCKBUTTON   0x20
337
#define PM_PENIO        0x40
338
#define PM_DOCKIN       0x80
339
 
340
 
341
#if 0
342
        PORTM_PUP &= ~PM_PENIO;
343
        PORTM_SEL |= PM_PENIO;
344
 
345
        PORTF_DAT = (PORTF_DAT & ~PF_DigiMask) | PF_DigiOff;
346
        PORTF_DAT = (PORTF_DAT & ~PF_DigiMask) | PF_DigiGetY;
347
 
348
 
349
        SPIMCONT = 0x427f;
350
        SPIMDATA = 0xc000;
351
 
352
        PORTF_DAT &= ~PF_ADSelect;
353
 
354
        /* Tell SPIM to sequence */
355
        SPIMCONT &= ~SPIMCONT_XCH;
356
        SPIMCONT |= SPIMCONT_XCH;
357
 
358
        /* Wait till sample is retrieved */
359
        while (!(SPIMCONT & SPIMCONT_IRQ))
360
                ;
361
        new_y = SPIMDATA;
362
 
363
        PORTF_DAT |= PF_ADSelect;
364
 
365
        SPIMCONT &= ~SPIMCONT_EN;
366
 
367
        PORTF_DAT = (PORTF_DAT & ~PF_DigiMask) | PF_DigiOff;
368
        PORTF_DAT = (PORTF_DAT & ~PF_DigiMask) | PF_DigiGetX;
369
 
370
        SPIMCONT = 0x427F;
371
        SPIMDATA = 0xffff;
372
 
373
        PORTF_DAT &= ~PF_ADSelect;
374
 
375
        /* Tell SPIM to sequence */
376
        SPIMCONT &= ~SPIMCONT_XCH;
377
        SPIMCONT |= SPIMCONT_XCH;
378
 
379
        /* Wait till sample is retrieved */
380
        while (!(SPIMCONT & SPIMCONT_IRQ))
381
                ;
382
        new_x = SPIMDATA;
383
 
384
        PORTF_DAT |= PF_ADSelect;
385
 
386
        SPIMCONT &= ~SPIMCONT_EN;
387
 
388
        PORTF_DAT = (PORTF_DAT & PF_DigiMask) | PF_DigiOff;
389
        PORTF_DAT = (PORTF_DAT & PF_DigiMask) | PF_DigiTap;
390
 
391
        PORTM_PUP |= PM_PENIO;
392
        PORTM_SEL &= ~PM_PENIO;
393
#endif
394
 
395
 
396
#if 1
397
 
398
 
399
#define PFDATA (*((volatile unsigned char*)0xFFFFF429)) 
400
 
401
#if 0
402
        (*(volatile unsigned char*)0xFFFFF44A) &= ~64; /* Switch off Port M Pen IRQ pullup */
403
        (*(volatile unsigned char*)0xFFFFF44B) |= 64;  /* Turn on Port M Pen IRQ select */
404
#endif
405
        (*(volatile unsigned char*)0xFFFFF44A) = 0xad; /* Switch off Port M Pen IRQ pullup */
406
        (*(volatile unsigned char*)0xFFFFF44B) = 0xd0;  /* Turn on Port M Pen IRQ select */
407
 
408
#if 0
409
        (*(volatile unsigned char*)0xFFFFF429) = 0xD5;    /* Set PFDATA to D5, Turn off digi power */
410
#endif
411
        PFDATA = (PFDATA & 0xf0) | 5;
412
        (*(volatile unsigned char*)0xFFFFF429) = 0xD9;    /* Set PFDATA to D9, Measure Y */
413
        (*(volatile unsigned short*)0xFFFFF802) = 0x427f; /* Set SPIMCONT to 427f */
414
        (*(volatile unsigned short*)0xFFFFF800) = 0xc000; /* Set SPIMDATA to c000, Preload data*/
415
#if 0
416
        (*((volatile unsigned char*)0xFFFFF439)) &= ~2;    /* Enable A/D */
417
#endif
418
        PFDATA &= ~0x80;
419
#if 0
420
        (*((volatile unsigned char*)0xFFFFF429)) = 0x59;    /* Set PFDATA to 59, Measure Y, A/D select HW2  */
421
#endif  
422
        (*((volatile unsigned short*)0xFFFFF802)) &= ~0x0100; /* Set SPIMCONT to 427f */
423
        (*((volatile unsigned short*)0xFFFFF802)) |= 0x0100; /* Set SPIMCONT to 437f */
424
 
425
        while(!((*((volatile unsigned short*)0xFFFFF802)) & 0x80))
426
                ;
427
 
428
        new_y = (*((volatile unsigned short*)0xFFFFF800)); /* Read SPIMDATA */
429
 
430
        PFDATA |= 0x80;
431
#if 0
432
        (*(volatile unsigned char*)0xFFFFF429) = 0xD9;    /* Set PFDATA to D9 */
433
#endif
434
#if 0
435
        (*((volatile unsigned char*)0xFFFFF439)) |= 2;    /* Disable A/D */
436
#endif
437
        (*(volatile unsigned short*)0xFFFFF802) = 0x407f;/* Set SPIMCONT to 407f */
438
 
439
        (*(volatile unsigned char*)0xFFFFF429) = 0xD5;    /* Set PFDATA to D5 */
440
        (*(volatile unsigned char*)0xFFFFF429) = 0xD6;    /* Set PFDATA to D6 */
441
        (*(volatile unsigned short*)0xFFFFF802) = 0x427f;/* Set SPIMCONT to 427f */
442
        (*(volatile unsigned short*)0xFFFFF800) = 0xffff; /* Set SPIMDATA to ffff */
443
 
444
        PFDATA &= ~0x80;
445
#if 0
446
        (*((volatile unsigned char*)0xFFFFF429)) = 0x56;    /* Set PFDATA to 56 */
447
#endif
448
#if 0
449
        (*((volatile unsigned char*)0xFFFFF439)) &= ~2;    /* Enable A/D */
450
#endif
451
        (*(volatile unsigned short*)0xFFFFF802) = 0x427f;/* Set SPIMCONT to 427f */
452
        (*((volatile unsigned short*)0xFFFFF802)) = 0x437f; /* Set SPIMCONT to 437f */
453
 
454
        while(!((*((volatile unsigned short*)0xFFFFF802)) & 0x80))
455
                ;
456
 
457
        new_x = (*((volatile unsigned short*)0xFFFFF800)); /* Read SPIMDATA */
458
 
459
        PFDATA |= 0x80;
460
#if 0
461
        (*(volatile unsigned char*)0xFFFFF429) = 0xD6;    /* Set PFDATA to d6 */
462
#endif
463
#if 0
464
        (*((volatile unsigned char*)0xFFFFF439)) |= 2;    /* Disable A/D */
465
#endif
466
        (*(volatile unsigned short*)0xFFFFF802) = 0x407f;/* Set SPIMCONT to 407f */
467
 
468
        (*(volatile unsigned char*)0xFFFFF429) = 0xD5;    /* Set PFDATA to d5 */
469
        (*(volatile unsigned char*)0xFFFFF429) = 0xDD;    /* Set PFDATA to dd */
470
 
471
#if 0
472
        (*(volatile unsigned char*)0xFFFFF44A) |= 64; /* Turn on Port M Pen IRQ pullup */
473
        (*(volatile unsigned char*)0xFFFFF44B) &= ~64;  /* Switch off Port M Pen IRQ select */
474
#endif
475
        (*(volatile unsigned char*)0xFFFFF44A) = 0xed; /* Switch off Port M Pen IRQ pullup */
476
        (*(volatile unsigned char*)0xFFFFF44B) = 0x90;  /* Turn on Port M Pen IRQ select */
477
 
478
 
479
#if 0   
480
        new_x = ((long)new_x * current_params.x_a + current_params.x_b) >> 16;
481
        new_y = ((long)new_y * current_params.y_a + current_params.y_b) >> 16;
482
 
483
        /*printk("calibrated x=%d, y=%d\n", new_x, new_y);*/
484
 
485
        handle_raw(new_x, new_y, 1);
486
#endif
487
 
488
#endif
489
 
490
        printk("raw x=%d, y=%d\n", new_x, new_y);
491
 
492
        restore_flags(flags);
493
 
494
 
495
 
496
}
497
 
498
void handle_raw(int new_x, int new_y, int new_down) {
499
 
500
        /*printk("Pen: %x,%x %x\n", new_x, new_y, new_down);*/
501
 
502
        if( (raw_x!=new_x) || (raw_y!=new_y) )
503
        {
504
                raw_x=new_x;
505
                raw_y=new_y;
506
                xy_pending=1;
507
        }
508
 
509
        if(new_down != raw_down)
510
        {
511
                /* Down state has changed.  raw_down always holds
512
                 * the most recently observed state.
513
                 */
514
                raw_down=new_down;
515
 
516
                /* Forget any earlier bounce processing */
517
                if(bounce)
518
                {
519
                        del_timer(&bounce_timer);
520
                        bounce=NO_BOUNCE;
521
                }
522
 
523
                if(new_down)
524
                {
525
                        if(debounced_down)
526
                        {
527
                                /* pad gone down, but we were reporting
528
                                 * it down anyway because we suspected
529
                                 * (correctly) that the last up was just
530
                                 * a bounce
531
                                 */
532
                                is_new_stroke=1;
533
                        }
534
                        else
535
                        {
536
                                bounce=JUST_GONE_DOWN;
537
                                set_timer_callback(&bounce_timer,
538
                                        current_params.bounce_interval);
539
                                /* start new stroke/tap */
540
                                debounced_down=new_down;
541
                                notify_digi_up_down();
542
                        }
543
                }
544
                else /* just gone up */
545
                {
546
                        if(recent_transition)
547
                        {
548
                                /* early bounces are probably part of
549
                                 * a multi-tap gesture, so process
550
                                 * immediately
551
                                 */
552
                                debounced_down=new_down;
553
                                notify_digi_up_down();
554
                        }
555
                        else if(transition_count==3)
556
                        {
557
                                /* give chance to move */
558
                                bounce=STICKY_DRAG_UP;
559
                                set_timer_callback(&bounce_timer,
560
                                        current_params.sticky_drag);
561
                        }
562
                        else
563
                        {
564
                                /* don't trust it yet */
565
                                bounce=JUST_GONE_UP;
566
                                set_timer_callback(&bounce_timer,
567
                                        current_params.bounce_interval);
568
                        }
569
                }
570
        }
571
        /*printk("Bounce=%d, x=%d, y=%d, new_stroke=%d, debounced_down=%d\n",
572
                bounce, raw_x, raw_y, is_new_stroke, debounced_down);*/
573
 
574
        wake_readers();
575
 
576
 
577
#if 0   
578
 
579
        /* Obtain byte from pad and prime for next byte */
580
        {
581
                int value=inb_p(current_params.io);
582
                int handshake=inb_p(current_params.io+2);
583
                outb_p(handshake | 1, current_params.io+2);
584
                outb_p(handshake &~1, current_params.io+2);
585
                inb_p(0x64);
586
 
587
                raw_data[raw_data_count++]=value;
588
        }
589
 
590
        if(raw_data_count==3)
591
        {
592
                /* The pad provides triples of data. The first byte has
593
                 * 0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down
594
                 * The second byte is bits 0-6 X
595
                 * The third is bits 0-6 Y
596
                 */
597
                int new_down=raw_data[0]&0x01;
598
                int new_x=raw_data[1];
599
                int new_y=raw_data[2];
600
                if(raw_data[0]&0x10) new_x+=128;
601
                if(raw_data[0]&0x80) new_x+=256;
602
                if(raw_data[0]&0x08) new_y+=128;
603
 
604
                if( (raw_x!=new_x) || (raw_y!=new_y) )
605
                {
606
                        raw_x=new_x;
607
                        raw_y=new_y;
608
                        xy_pending=1;
609
                }
610
 
611
                if(new_down != raw_down)
612
                {
613
                        /* Down state has changed.  raw_down always holds
614
                         * the most recently observed state.
615
                         */
616
                        raw_down=new_down;
617
 
618
                        /* Forget any earlier bounce processing */
619
                        if(bounce)
620
                        {
621
                                del_timer(&bounce_timer);
622
                                bounce=NO_BOUNCE;
623
                        }
624
 
625
                        if(new_down)
626
                        {
627
                                if(debounced_down)
628
                                {
629
                                        /* pad gone down, but we were reporting
630
                                         * it down anyway because we suspected
631
                                         * (correctly) that the last up was just
632
                                         * a bounce
633
                                         */
634
                                        is_new_stroke=1;
635
                                }
636
                                else
637
                                {
638
                                        bounce=JUST_GONE_DOWN;
639
                                        set_timer_callback(&bounce_timer,
640
                                                current_params.bounce_interval);
641
                                        /* start new stroke/tap */
642
                                        debounced_down=new_down;
643
                                        notify_digi_up_down();
644
                                }
645
                        }
646
                        else /* just gone up */
647
                        {
648
                                if(recent_transition)
649
                                {
650
                                        /* early bounces are probably part of
651
                                         * a multi-tap gesture, so process
652
                                         * immediately
653
                                         */
654
                                        debounced_down=new_down;
655
                                        notify_digi_up_down();
656
                                }
657
                                else if(transition_count==3)
658
                                {
659
                                        /* give chance to move */
660
                                        bounce=STICKY_DRAG_UP;
661
                                        set_timer_callback(&bounce_timer,
662
                                                current_params.sticky_drag);
663
                                }
664
                                else
665
                                {
666
                                        /* don't trust it yet */
667
                                        bounce=JUST_GONE_UP;
668
                                        set_timer_callback(&bounce_timer,
669
                                                current_params.bounce_interval);
670
                                }
671
                        }
672
                }
673
                wake_readers();
674
                raw_data_count=0;
675
        }
676
#endif
677
}
678
 
679
 
680
static void read_raw_digi(int *down, int *debounced, int *stroke, int *x, int *y)
681
{
682
 
683
        /*disable_irq(current_params.irq);*/
684
        (*((volatile unsigned long*)0xFFFFF304)) |= (1<<20);   /* Enable interrupt */
685
        {
686
                *down=raw_down;
687
                *debounced=debounced_down;
688
                *stroke=is_new_stroke;
689
                *x=raw_x;
690
                *y=raw_y;
691
                xy_pending = 0;
692
                is_new_stroke = 0;
693
        }
694
        (*((volatile unsigned long*)0xFFFFF304)) &= ~(1<<20);   /* Enable interrupt */
695
        /*enable_irq(current_params.irq);*/
696
}
697
 
698
/*****************************************************************************/
699
/*
700
 * Filesystem interface
701
 */
702
 
703
/* Read returns byte triples, so we need to keep track of
704
 * how much of a triple has been read.  This is shared across
705
 * all processes which have this device open---not that anything
706
 * will make much sense in that case.
707
 */
708
static int read_bytes[3];
709
static int read_byte_count=0;
710
 
711
 
712
static void sample_rare(int d[3])
713
{
714
        int thisd, thisdd, thiss, thisx, thisy;
715
 
716
        read_raw_digi(&thisd, &thisdd, &thiss, &thisx, &thisy);
717
 
718
        d[0]=(thisd?0x80:0)
719
           | (thisx/256)<<4
720
           | (thisdd?0x08:0)
721
           | (thisy/256)
722
        ;
723
        d[1]=thisx%256;
724
        d[2]=thisy%256;
725
}
726
 
727
 
728
static void sample_debug(int d[3])
729
{
730
        int thisd, thisdd, thiss, thisx, thisy;
731
        int b;
732
        cli();
733
        read_raw_digi(&thisd, &thisdd, &thiss, &thisx, &thisy);
734
        d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | (thiss?0x20:0) | bounce;
735
        d[1]=(recent_transition?0x80:0)+transition_count;
736
        read_button(&b);
737
        d[2]=(synthesize_tap<<4) | (b?0x01:0);
738
        sti();
739
}
740
 
741
 
742
static void sample_ps2(int d[3])
743
{
744
        static int lastx, lasty;
745
 
746
        int thisd, thisdd, thiss, thisx, thisy;
747
        int dx, dy, b;
748
 
749
        /*
750
         * Obtain the current mouse parameters and limit as appropriate for
751
         * the return data format.  Interrupts are only disabled while
752
         * obtaining the parameters, NOT during the puts_fs_byte() calls,
753
         * so paging in put_user() does not affect mouse tracking.
754
         */
755
        read_raw_digi(&thisd, &thisdd, &thiss, &thisx, &thisy);
756
        read_button(&b);
757
 
758
        /* Now compare with previous readings. */
759
        if( thiss /* new stroke */
760
         || (bounce!=NO_BOUNCE) )
761
        {
762
                dx=0;
763
                dy=0;
764
        }
765
        else
766
        {
767
                dx = (thisx-lastx);
768
                dy = -(thisy-lasty);
769
        }
770
        lastx=thisx;
771
        lasty=thisy;
772
 
773
        d[0]= ((dy<0)?0x20:0)
774
            | ((dx<0)?0x10:0)
775
            | (b? 0x00:0x08)
776
        ;
777
        d[1]=dx;
778
        d[2]=dy;
779
}
780
 
781
 
782
 
783
static int fasync_digi(struct inode *inode, struct file *filp, int on)
784
{
785
        int retval;
786
 
787
        retval = fasync_helper(inode, filp, on, &asyncptr);
788
        if (retval < 0)
789
                return retval;
790
        return 0;
791
}
792
 
793
 
794
/*
795
 * close access to the pad
796
 */
797
static void close_digi(struct inode * inode, struct file * file)
798
{
799
        fasync_digi(inode, file, 0);
800
        if (--active)
801
                return;
802
 
803
        (*((volatile unsigned long*)0xFFFFF304)) |= (1<<20);   /* Enable interrupt */
804
#if 0
805
        outb(0x30, current_params.io+2);        /* switch off digitiser */
806
#endif
807
        MOD_DEC_USE_COUNT;
808
}
809
 
810
 
811
/*
812
 * open access to the pad
813
 */
814
static int open_digi(struct inode * inode, struct file * file)
815
{
816
        if (active++)
817
                return 0;
818
        MOD_INC_USE_COUNT;
819
 
820
#if 0
821
        cli();
822
        outb(0x30, current_params.io+2);        /* switch off digitiser */
823
        pad_irq(0,0,0);            /* read to flush any pending bytes */
824
        pad_irq(0,0,0);            /* read to flush any pending bytes */
825
        pad_irq(0,0,0);            /* read to flush any pending bytes */
826
        outb(0x38, current_params.io+2);        /* switch on digitiser */
827
        current_params = default_params;
828
        raw_data_count=0;                /* re-sync input byte counter */
829
        read_byte_count=0;               /* re-sync output byte counter */
830
        button_pending=0;
831
        recent_transition=0;
832
        transition_count=0;
833
        synthesize_tap=0;
834
        del_timer(&bounce_timer);
835
        del_timer(&tap_timer);
836
        sti();
837
#endif
838
 
839
        cli();
840
        current_params = default_params;
841
        raw_data_count=0;                /* re-sync input byte counter */
842
        read_byte_count=0;               /* re-sync output byte counter */
843
        button_pending=0;
844
        recent_transition=0;
845
        transition_count=0;
846
        synthesize_tap=0;
847
        del_timer(&bounce_timer);
848
        del_timer(&tap_timer);
849
        sti();
850
 
851
        return 0;
852
}
853
 
854
 
855
/*
856
 * writes are disallowed
857
 */
858
static int write_digi(struct inode * inode, struct file * file, const char * buffer, int count)
859
{
860
        return -EINVAL;
861
}
862
 
863
 
864
void new_sample(int d[3])
865
{
866
        switch(current_params.mode)
867
        {
868
                case MC68328DIGI_RARE:  sample_rare(d);         break;
869
                case MC68328DIGI_DEBUG: sample_debug(d);        break;
870
                case MC68328DIGI_PS2:   sample_ps2(d);          break;
871
        }
872
}
873
 
874
 
875
/*
876
 * Read pad data.  Currently never blocks.
877
 */
878
static int read_digi(struct inode * inode, struct file * file, char * buffer, int count)
879
{
880
        int r;
881
 
882
        if ((r = verify_area(VERIFY_WRITE, buffer, count)))
883
                return r;
884
 
885
        for(r=0; r<count; r++)
886
        {
887
                if(!read_byte_count)
888
                        new_sample(read_bytes);
889
                put_user(read_bytes[read_byte_count], buffer+r);
890
                read_byte_count = (read_byte_count+1)%3;
891
        }
892
        return r;
893
}
894
 
895
 
896
/*
897
 * select for pad input
898
 */
899
static int pad_select(struct inode *inode, struct file *file, int sel_type, select_table * wait)
900
{
901
        if(sel_type == SEL_IN) {
902
                if(button_pending || xy_pending)
903
                        return 1;
904
                select_wait(&queue, wait);
905
        }
906
        return 0;
907
}
908
 
909
 
910
static int pad_ioctl(struct inode *inode, struct file * file,
911
        unsigned int cmd, unsigned long arg)
912
{
913
        int i;
914
        struct mc68328digi_params new;
915
 
916
        if (!inode)
917
                return -EINVAL;
918
 
919
        switch (cmd) {
920
        case MC68328DIGIIOCGETP:
921
                printk("pad_ioctl: get %d\n",current_params.mode);
922
                i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(new));
923
                if(i) return i;
924
                new = current_params;
925
                memcpy_tofs((void *)arg, &new, sizeof(new));
926
                return 0;
927
 
928
        case MC68328DIGIIOCSETP:
929
                printk("pad_ioctl: set, was %d",current_params.mode);
930
                i = verify_area(VERIFY_READ, (void *)arg, sizeof(new));
931
                if (i) return i;
932
                memcpy_fromfs(&new, (void *)arg, sizeof(new));
933
 
934
                if( (new.mode<MC68328DIGI_RARE)
935
                 || (new.mode>MC68328DIGI_PS2)
936
                 || (new.bounce_interval<0)
937
                 || (new.sticky_drag<0)
938
                 || (new.tap_interval<0)
939
                )
940
                        return -EINVAL;
941
 
942
                current_params.mode     = new.mode;
943
                current_params.bounce_interval  = new.bounce_interval;
944
                current_params.sticky_drag      = new.sticky_drag;
945
                current_params.tap_interval     = new.tap_interval;
946
                printk("now %d\n",current_params.mode);
947
                return 0;
948
        }
949
        return -ENOIOCTLCMD;
950
}
951
 
952
 
953
static struct file_operations pad_fops = {
954
        NULL,           /* pad_seek */
955
        read_digi,
956
        write_digi,
957
        NULL,           /* pad_readdir */
958
        pad_select,
959
        pad_ioctl,
960
        NULL,           /* pad_mmap */
961
        open_digi,
962
        close_digi,
963
        NULL,
964
        fasync_digi,
965
};
966
 
967
 
968
static struct miscdevice mc68328_digi = {
969
        MC68328DIGI_MINOR, "mc68328 digitizer", &pad_fops
970
};
971
 
972
 
973
int mc68328digi_init(void)
974
{
975
        current_params = default_params;
976
        raw_data_count=0;                /* re-sync input byte counter */
977
        read_byte_count=0;               /* re-sync output byte counter */
978
        button_pending=0;
979
        recent_transition=0;
980
        transition_count=0;
981
        synthesize_tap=0;
982
        del_timer(&bounce_timer);
983
        del_timer(&tap_timer);
984
 
985
 
986
        /*if(request_irq(current_params.irq, pad_irq, 0, "mc68328digi", 0))
987
        {
988
                printk("mc68328digi: Unable to get IRQ.\n");
989
                return -EBUSY;
990
        }
991
        if(check_region(current_params.io, 4))
992
        {
993
                printk("mc68328digi: I/O area in use.\n");
994
                free_irq(current_params.irq,0);
995
                return -EBUSY;
996
        }
997
        request_region(current_params.io, 4, "mc68328digi");
998
        printk("PC110 digitizer pad at 0x%X, irq %d.\n",
999
                current_params.io,current_params.irq);*/
1000
 
1001
        if (request_irq(IRQ_MACHSPEC | PEN_IRQ_NUM,
1002
                        digi_interrupt,
1003
                        IRQ_FLG_STD,
1004
                        "M68328 Digitizer", NULL))
1005
                panic("Unable to attach 68328 digitizer interrupt\n");
1006
 
1007
        printk("MC68328 digitizer.\n");
1008
        misc_register(&mc68328_digi);
1009
 
1010
        (*(volatile unsigned char*)0xFFFFF42B) = 0xFF; /*Setting PFSEL byte to ff*/
1011
        (*(volatile unsigned char*)0xFFFFF428) = 0xFF; /*Setting PFDIR byte to ff*/
1012
        (*(volatile unsigned char*)0xFFFFF42A) = 0x00; /*Setting PFPUEN byte to 0*/
1013
 
1014
        (*(volatile unsigned char*)0xFFFFF429) = 0xc5; /*Setting PFDATA byte to c5*/
1015
        (*(volatile unsigned char*)0xFFFFF429) = 0xd5; /*Setting PFDATA byte to d5*/
1016
        (*(volatile unsigned char*)0xFFFFF448) = 0x50; /*Setting PMDIR byte to 50*/
1017
        (*(volatile unsigned char*)0xFFFFF449) = 0x00; /*Setting PMDATA byte to 0*/
1018
        (*(volatile unsigned char*)0xFFFFF44B) = 0xd0; /*Setting PMSEL byte to d0*/
1019
        (*(volatile unsigned char*)0xFFFFF429) = 0xd5; /*Setting PFDATA byte to d5*/
1020
#if 0
1021
        (*(volatile unsigned char*)0xFFFFF431) = 0x60; /*Setting PGDATA byte to 60*/
1022
#endif
1023
        (*(volatile unsigned short*)0xFFFFF802) = 0x427f; /*Setting SPIMCONT word to 427f*/
1024
        (*(volatile unsigned short*)0xFFFFF800) = 0xffff; /*Setting SPIMDATA word to ffff*/
1025
        (*(volatile unsigned char*)0xFFFFF429) = 0x55; /*Setting PFDATA byte to 55*/
1026
        (*(volatile unsigned short*)0xFFFFF802) = 0x427f; /*Setting SPIMCONT word to 427f*/
1027
        (*(volatile unsigned short*)0xFFFFF802) = 0x437f; /*Setting SPIMCONT word to 437f*/
1028
        (void)(*(volatile unsigned short*)0xFFFFF800); /*Returning word from SPIMDATA ffff*/
1029
        (*(volatile unsigned char*)0xFFFFF429) = 0xd5; /*Setting PFDATA byte to d5*/
1030
        (*(volatile unsigned short*)0xFFFFF802) = 0x407f; /*Setting SPIMCONT word to 407f*/
1031
#if 0
1032
        (*(volatile unsigned char*)0xFFFFF431) = 0x70; /*Setting PGDATA byte to 70*/
1033
#endif
1034
        (*(volatile unsigned char*)0xFFFFF448) = 0x50; /*Setting PMDIR byte to 50*/
1035
        (*(volatile unsigned char*)0xFFFFF449) = 0x00; /*Setting PMDATA byte to 0*/
1036
        (*(volatile unsigned char*)0xFFFFF44A) = 0xED; /* Port M Pullups (dangerous?) */
1037
        (*(volatile unsigned char*)0xFFFFF44B) = 0xd0; /*Setting PMSEL byte to d0*/
1038
        (*(volatile unsigned char*)0xFFFFF429) = 0xd5; /*Setting PFDATA byte to d5*/
1039
        (*(volatile unsigned char*)0xFFFFF429) = 0xdd; /*Setting PFDATA byte to dd*/
1040
 
1041
 
1042
        (*((volatile unsigned long*)0xFFFFF304)) &= ~(1<<20);   /* Enable interrupt */
1043
        (*(volatile unsigned char*)0xFFFFF44A) |= 64; /* Turn on Port M Pen IRQ pullup */
1044
        (*(volatile unsigned char*)0xFFFFF44B) &= ~64;  /* Switch off Port M Pen IRQ select */
1045
 
1046
        /*outb(0x30, current_params.io+2);*/    /* switch off digitiser */
1047
 
1048
        return 0;
1049
}
1050
 
1051
 
1052
static void mc68328digi_unload(void)
1053
{
1054
#if 0
1055
        outb(0x30, current_params.io+2);        /* switch off digitiser */
1056
#endif
1057
        /*if(current_params.irq)
1058
                free_irq(current_params.irq, 0);
1059
        current_params.irq=0;
1060
        release_region(current_params.io, 4);*/
1061
        misc_deregister(&mc68328_digi);
1062
}
1063
 
1064
 
1065
int init_module(void)
1066
{
1067
        return mc68328digi_init();
1068
}
1069
 
1070
void cleanup_module(void)
1071
{
1072
        mc68328digi_unload();
1073
}

powered by: WebSVN 2.1.0

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