|
|
1.1 root 1: /*-
2: * Copyright (c) 1992, 1993 Erik Forsberg.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: *
11: * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
12: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
14: * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
15: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
17: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
18: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
19: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
20: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21: */
22:
23: /*
24: * Ported to 386bsd Oct 17, 1992
25: * Sandi Donno, Computer Science, University of Cape Town, South Africa
26: * Please send bug reports to [email protected]
27: *
28: * Thanks are also due to Rick Macklem, [email protected] -
29: * although I was only partially successful in getting the alpha release
30: * of his "driver for the Logitech and ATI Inport Bus mice for use with
31: * 386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless
32: * found his code to be an invaluable reference when porting this driver
33: * to 386bsd.
34: *
35: * Further modifications for latest 386BSD+patchkit and port to NetBSD,
36: * Andrew Herbert <[email protected]> - 8 June 1993
37: *
38: * Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by
39: * Andrew Herbert - 12 June 1993
40: *
41: * Modified for PS/2 mouse by Charles Hannum <[email protected]>
42: * - 13 June 1993
43: */
44:
45: #include "pms.h"
46:
47: #if NPMS > 0
48:
49: #include "param.h"
50: #include "kernel.h"
51: #include "systm.h"
52: #include "buf.h"
53: #include "malloc.h"
54: #include "ioctl.h"
55: #include "tty.h"
56: #include "file.h"
57: #ifdef NetBSD
58: #include "select.h"
59: #endif
60: #include "proc.h"
61: #include "vnode.h"
62:
63: #include "i386/include/mouse.h"
64: #include "i386/include/pio.h" /* Julian's fast IO macros */
65: #include "i386/isa/isa_device.h"
66:
67: #define DATA 0 /* Offset for data port, read-write */
68: #define CNTRL 4 /* Offset for control port, write-only */
69: #define STATUS 4 /* Offset for status port, read-only */
70:
71: /* status bits */
72: #define PMS_OUTPUT_ACK 0x02 /* output acknowledge */
73:
74: /* controller commands */
75: #define PMS_ENABLE 0xa7 /* enable auxiliary port */
76: #define PMS_DISABLE 0xa8 /* disable auxiliary port */
77: #define PMS_INT_ENABLE 0x47 /* enable controller interrupts */
78: #define PMS_INT_DISABLE 0x65 /* disable controller interrupts */
79:
80: /* mouse commands */
81: #define PMS_SET_RES 0xe8 /* set resolution */
82: #define PMS_SET_SCALE 0xe9 /* set scaling factor */
83: #define PMS_SET_STREAM 0xea /* set streaming mode */
84: #define PMS_SET_SAMPLE 0xf3 /* set sampling rate */
85: #define PMS_DEV_ENABLE 0xf4 /* mouse on */
86: #define PMS_DEV_DISABLE 0xf5 /* mouse off */
87: #define PMS_RESET 0xff /* reset */
88:
89: #define PMSUNIT(dev) (minor(dev) >> 1)
90:
91: #ifndef min
92: #define min(x,y) (x < y ? x : y)
93: #endif min
94:
95: int pmsprobe (struct isa_device *);
96: int pmsattach (struct isa_device *);
97:
98: static int pmsaddr[NPMS]; /* Base I/O port addresses per unit */
99:
100: #define MSBSZ 1024 /* Output queue size (pwr of 2 is best) */
101:
102: struct ringbuf {
103: int count, first, last;
104: char queue[MSBSZ];
105: };
106:
107: static struct pms_softc { /* Driver status information */
108: struct ringbuf inq; /* Input queue */
109: #ifdef NetBSD
110: struct selinfo rsel;
111: #else
112: pid_t rsel; /* Process selecting for Input */
113: #endif
114: unsigned char state; /* Mouse driver state */
115: unsigned char status; /* Mouse button status */
116: unsigned char button; /* Previous mouse button status bits */
117: int x, y; /* accumulated motion in the X,Y axis */
118: } pms_softc[NPMS];
119:
120: #define OPEN 1 /* Device is open */
121: #define ASLP 2 /* Waiting for mouse data */
122:
123: struct isa_driver pmsdriver = { pmsprobe, pmsattach, "pms" };
124:
125: int pmsprobe(struct isa_device *dvp)
126: {
127: /* XXX: Needs a real probe routine. */
128:
129: return (1);
130: }
131:
132: static inline void pms_write(int ioport, u_char value)
133: {
134: outb(ioport+CNTRL, 0xd4);
135: outb(ioport+DATA, value);
136: while (!(inb(ioport+STATUS) & PMS_OUTPUT_ACK));
137: }
138:
139: static inline void pms_command(int ioport, u_char value)
140: {
141: outb(ioport+CNTRL, 0x60);
142: outb(ioport+DATA, value);
143: }
144:
145: int pmsattach(struct isa_device *dvp)
146: {
147: int unit = dvp->id_unit;
148: int ioport = dvp->id_iobase;
149: struct pms_softc *sc = &pms_softc[unit];
150:
151: /* Save I/O base address */
152:
153: pmsaddr[unit] = ioport;
154:
155: /* Disable mouse interrupts */
156:
157: pms_command(ioport, PMS_DISABLE);
158: #if 0
159: pms_command(ioport, PMS_INT_DISABLE);
160: #endif
161: pms_write(ioport, PMS_DEV_DISABLE);
162:
163: pms_write(ioport, PMS_SET_RES);
164: pms_write(ioport, 0x03); /* 8 counts/mm */
165: pms_write(ioport, PMS_SET_SCALE);
166: pms_write(ioport, 0x02); /* 2:1 */
167: pms_write(ioport, PMS_SET_SAMPLE);
168: pms_write(ioport, 0x64); /* 100 samples/sec */
169: pms_write(ioport, PMS_SET_STREAM);
170:
171: /* Setup initial state */
172:
173: sc->state = 0;
174:
175: /* Done */
176:
177: return(0);
178: }
179:
180: int pmsopen(dev_t dev, int flag, int fmt, struct proc *p)
181: {
182: int unit = PMSUNIT(dev);
183: struct pms_softc *sc;
184: int ioport;
185:
186: /* Validate unit number */
187:
188: if (unit >= NPMS)
189: return(ENXIO);
190:
191: /* Get device data */
192:
193: sc = &pms_softc[unit];
194: ioport = pmsaddr[unit];
195:
196: /* If device does not exist */
197:
198: if (ioport == 0)
199: return(ENXIO);
200:
201: /* Disallow multiple opens */
202:
203: if (sc->state & OPEN)
204: return(EBUSY);
205:
206: /* Initialize state */
207:
208: sc->state |= OPEN;
209: #ifdef NetBSD
210: sc->rsel.si_pid = 0;
211: sc->rsel.si_coll = 0;
212: #else
213: sc->rsel = 0;
214: #endif
215: sc->status = 0;
216: sc->button = 0;
217: sc->x = 0;
218: sc->y = 0;
219:
220: /* Allocate and initialize a ring buffer */
221:
222: sc->inq.count = sc->inq.first = sc->inq.last = 0;
223:
224: /* Enable Bus Mouse interrupts */
225:
226: pms_write(ioport, PMS_DEV_ENABLE);
227: #if 0
228: pms_command(ioport, PMS_INT_ENABLE);
229: #endif
230: pms_command(ioport, PMS_ENABLE);
231:
232: /* Successful open */
233:
234: return(0);
235: }
236:
237: int pmsclose(dev_t dev, int flag, int fmt, struct proc *p)
238: {
239: int unit, ioport;
240: struct pms_softc *sc;
241:
242: /* Get unit and associated info */
243:
244: unit = PMSUNIT(dev);
245: sc = &pms_softc[unit];
246: ioport = pmsaddr[unit];
247:
248: /* Disable further mouse interrupts */
249:
250: pms_command(ioport, PMS_DISABLE);
251: #if 0
252: pms_command(ioport, PMS_INT_DISABLE);
253: #endif
254: pms_write(ioport, PMS_DEV_DISABLE);
255:
256: /* Complete the close */
257:
258: sc->state &= ~OPEN;
259:
260: /* close is almost always successful */
261:
262: return(0);
263: }
264:
265: int pmsread(dev_t dev, struct uio *uio, int flag)
266: {
267: int s;
268: int error = 0; /* keep compiler quiet, even though initialisation
269: is unnecessary */
270: unsigned length;
271: struct pms_softc *sc;
272: unsigned char buffer[100];
273:
274: /* Get device information */
275:
276: sc = &pms_softc[PMSUNIT(dev)];
277:
278: /* Block until mouse activity occured */
279:
280: s = spltty();
281: while (sc->inq.count == 0) {
282: if (minor(dev) & 0x1) {
283: splx(s);
284: return(EWOULDBLOCK);
285: }
286: sc->state |= ASLP;
287: error = tsleep((caddr_t)sc, PZERO | PCATCH, "pmsrea", 0);
288: if (error != 0) {
289: splx(s);
290: return(error);
291: }
292: }
293:
294: /* Transfer as many chunks as possible */
295:
296: while (sc->inq.count > 0 && uio->uio_resid > 0) {
297: length = min(sc->inq.count, uio->uio_resid);
298: if (length > sizeof(buffer))
299: length = sizeof(buffer);
300:
301: /* Remove a small chunk from input queue */
302:
303: if (sc->inq.first + length >= MSBSZ) {
304: bcopy(&sc->inq.queue[sc->inq.first],
305: buffer, MSBSZ - sc->inq.first);
306: bcopy(sc->inq.queue, &buffer[MSBSZ-sc->inq.first],
307: length - (MSBSZ - sc->inq.first));
308: }
309: else
310: bcopy(&sc->inq.queue[sc->inq.first], buffer, length);
311:
312: sc->inq.first = (sc->inq.first + length) % MSBSZ;
313: sc->inq.count -= length;
314:
315: /* Copy data to user process */
316:
317: error = uiomove(buffer, length, uio);
318: if (error)
319: break;
320: }
321:
322: sc->x = sc->y = 0;
323:
324: /* Allow interrupts again */
325:
326: splx(s);
327: return(error);
328: }
329:
330: int pmsioctl(dev_t dev, caddr_t addr, int cmd, int flag, struct proc *p)
331: {
332: struct pms_softc *sc;
333: struct mouseinfo info;
334: int s, error;
335:
336: /* Get device information */
337:
338: sc = &pms_softc[PMSUNIT(dev)];
339:
340: /* Perform IOCTL command */
341:
342: switch (cmd) {
343:
344: case MOUSEIOCREAD:
345:
346: /* Don't modify info while calculating */
347:
348: s = spltty();
349:
350: /* Build mouse status octet */
351:
352: info.status = sc->status;
353: if (sc->x || sc->y)
354: info.status |= MOVEMENT;
355:
356: /* Encode X and Y motion as good as we can */
357:
358: if (sc->x > 127)
359: info.xmotion = 127;
360: else if (sc->x < -128)
361: info.xmotion = -128;
362: else
363: info.xmotion = sc->x;
364:
365: if (sc->y > 127)
366: info.ymotion = 127;
367: else if (sc->y < -128)
368: info.ymotion = -128;
369: else
370: info.ymotion = sc->y;
371:
372: /* Reset historical information */
373:
374: sc->x = 0;
375: sc->y = 0;
376: sc->status &= ~BUTCHNGMASK;
377:
378: /* Allow interrupts and copy result buffer */
379:
380: splx(s);
381: error = copyout(&info, addr, sizeof(struct mouseinfo));
382: break;
383:
384: default:
385: error = EINVAL;
386: break;
387: }
388:
389: /* Return error code */
390:
391: return(error);
392: }
393:
394: void pmsintr(unit)
395: int unit;
396: {
397: struct pms_softc *sc = &pms_softc[unit];
398: int ioport = pmsaddr[unit];
399: static int state = 0;
400: static char buttons, dx, dy;
401: char changed;
402:
403: switch (state) {
404:
405: case 0:
406: buttons = inb(ioport + DATA);
407: if (!(buttons & 0xc0))
408: ++state;
409: buttons = ~(((buttons&1) << 2) | (buttons&2));
410: break;
411:
412: case 1:
413: dx = inb(ioport + DATA) << 2;
414: dx >>= 2;
415: ++state;
416: break;
417:
418: case 2:
419: dy = inb(ioport + DATA) << 2;
420: dy >>= 2;
421: state = 0;
422:
423: dy = -dy;
424:
425: changed = buttons ^ sc->button;
426: sc->button = buttons;
427: sc->status = buttons | (sc->status & ~BUTSTATMASK) | (changed << 3);
428:
429: /* Update accumulated movements */
430:
431: sc->x += dx;
432: sc->y += dy;
433:
434: /* If device in use and a change occurred... */
435:
436: if (sc->state & OPEN && (dx || dy || changed)) {
437: sc->inq.queue[sc->inq.last++] = 0x40 |
438: (buttons ^ BUTSTATMASK);
439: sc->inq.queue[sc->inq.last++ % MSBSZ] = dx;
440: sc->inq.queue[sc->inq.last++ % MSBSZ] = dy;
441: sc->inq.queue[sc->inq.last++ % MSBSZ] = 0;
442: sc->inq.queue[sc->inq.last++ % MSBSZ] = 0;
443: sc->inq.last = sc->inq.last % MSBSZ;
444: sc->inq.count += 5;
445:
446: if (sc->state & ASLP) {
447: sc->state &= ~ASLP;
448: wakeup((caddr_t)sc);
449: }
450: #ifdef NetBSD
451: selwakeup(&sc->rsel);
452: #else
453: if (sc->rsel) {
454: selwakeup(sc->rsel, 0);
455: sc->rsel = 0;
456: }
457: #endif
458: }
459:
460: break;
461: }
462: }
463:
464: int pmsselect(dev_t dev, int rw, struct proc *p)
465: {
466: int s, ret;
467: struct pms_softc *sc = &pms_softc[PMSUNIT(dev)];
468:
469: /* Silly to select for output */
470:
471: if (rw == FWRITE)
472: return(0);
473:
474: /* Return true if a mouse event available */
475:
476: s = spltty();
477: if (sc->inq.count)
478: ret = 1;
479: else {
480: #ifdef NetBSD
481: selrecord(p, &sc->rsel);
482: #else
483: sc->rsel = p->p_pid;
484: #endif
485: ret = 0;
486: }
487: splx(s);
488:
489: return(ret);
490: }
491: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.