xref: /netbsd-src/sys/arch/mac68k/dev/adb.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: adb.c,v 1.1 1994/12/03 23:34:12 briggs Exp $	*/
2 
3 /*-
4  * Copyright (C) 1994	Bradley A. Grantham
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Bradley A. Grantham.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <machine/param.h>
36 #include <sys/device.h>
37 #include <sys/fcntl.h>
38 #include <sys/select.h>
39 #include <sys/proc.h>
40 #include <sys/systm.h>
41 #include <machine/adbsys.h>
42 #include "adbvar.h"
43 #include <machine/keyboard.h>
44 #include "../mac68k/macrom.h"
45 
46 /*
47  * External keyboard translation matrix
48  */
49 extern unsigned char keyboard[128][3];
50 
51 
52 /*
53  * Event queue definitions
54  */
55 #if !defined(ADB_MAX_EVENTS)
56 #define ADB_MAX_EVENTS 200	/* Maximum events to be kept in queue */
57 #endif /* !defined(ADB_MAX_EVENTS) */
58 	/* maybe should be higher for slower macs? */
59 
60 static adb_event_t adb_evq[ADB_MAX_EVENTS];	/* ADB event queue */
61 static int adb_evq_tail = 0;			/* event queue tail */
62 static int adb_evq_len = 0;			/* event queue length */
63 
64 
65 /*
66  * ADB device state information
67  */
68 static int adb_isopen = 0;	/* Are we queuing events for adb_read? */
69 int adb_polling = 0;		/* Are we polling?  (Debugger mode) */
70 static struct selinfo adb_selinfo;	/* select() info */
71 static struct proc *adb_ioproc = NULL;	/* process to wakeup */
72 
73 
74 /*
75  * Key repeat parameters
76  */
77 static int adb_rptdelay = 20;		/* ticks before auto-repeat */
78 static int adb_rptinterval = 6;		/* ticks between auto-repeat */
79 static int adb_repeating = -1;		/* key that is auto-repeating */
80 static adb_event_t adb_rptevent;	/* event to auto-repeat */
81 
82 
83 static void
84 adbattach(parent, dev, aux)
85 	struct device	*parent, *dev;
86 	void		*aux;
87 {
88 	printf(" (ADB event device)\n");
89 }
90 
91 
92 /*
93  * Auto-configure parameters
94  */
95 extern int matchbyname();
96 
97 struct cfdriver adbcd =
98       { NULL,
99 	"adb",
100 	matchbyname,
101 	adbattach,
102 	DV_DULL,
103 	sizeof(struct device),
104 	NULL,
105 	0 };
106 
107 
108 void adb_enqevent(
109 	adb_event_t *event)
110 {
111 	int s;
112 
113 	if(adb_evq_tail < 0 || adb_evq_tail >= ADB_MAX_EVENTS)
114 		panic("adb: event queue tail is out of bounds");
115 
116 	if(adb_evq_len < 0 || adb_evq_len > ADB_MAX_EVENTS)
117 		panic("adb: event queue len is out of bounds");
118 
119 	s = splhigh();
120 
121 	if(adb_evq_len == ADB_MAX_EVENTS){
122 		splx(s);
123 		return;	/* Oh, well... */
124 	}
125 
126 	adb_evq[(adb_evq_len + adb_evq_tail) % ADB_MAX_EVENTS] =
127 		*event;
128 	adb_evq_len++;
129 
130 	selwakeup(&adb_selinfo);
131 	if(adb_ioproc)
132 		psignal(adb_ioproc, SIGIO);
133 
134 	splx(s);
135 }
136 
137 void adb_handoff(
138 	adb_event_t *event)
139 {
140 	if(adb_isopen && !adb_polling){
141 		adb_enqevent(event);
142 	}else{
143 		if(event->def_addr == 2)
144 			ite_intr(event);
145 	}
146 }
147 
148 
149 void adb_autorepeat(
150 	void *keyp)
151 {
152 	int key = (int)keyp;
153 
154 	adb_rptevent.bytes[0] |= 0x80;
155 	microtime(&adb_rptevent.timestamp);
156 	adb_handoff(&adb_rptevent);	/* do key up */
157 
158 	adb_rptevent.bytes[0] &= 0x7f;
159 	microtime(&adb_rptevent.timestamp);
160 	adb_handoff(&adb_rptevent);	/* do key down */
161 
162 	if(adb_repeating == key){
163 		timeout(adb_autorepeat, keyp, adb_rptinterval);
164 	}
165 }
166 
167 
168 void adb_dokeyupdown(
169 	adb_event_t *event)
170 {
171 	int adb_key;
172 
173 	if(event->def_addr == 2){
174 		adb_key = event->u.k.key & 0x7f;
175 		if(!(event->u.k.key & 0x80) &&
176 			keyboard[event->u.k.key & 0x7f][0] != 0)
177 		{
178 			/* ignore shift & control */
179 			if(adb_repeating != -1){
180 				untimeout(adb_autorepeat,
181 					(void *)adb_rptevent.u.k.key);
182 			}
183 			adb_rptevent = *event;
184 			adb_repeating = adb_key;
185 			timeout(adb_autorepeat,
186 				(void *)adb_key, adb_rptdelay);
187 		}else{
188 			if(adb_repeating != -1){
189 				adb_repeating = -1;
190 				untimeout(adb_autorepeat,
191 					(void *)adb_rptevent.u.k.key);
192 			}
193 			adb_rptevent = *event;
194 		}
195 	}
196 	adb_handoff(event);
197 }
198 
199 static adb_ms_buttons = 0;
200 
201 void adb_keymaybemouse(
202 	adb_event_t *event)
203 {
204 	adb_event_t new_event;
205 	static optionkey_down = 0;
206 
207 	if(event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)){
208 		optionkey_down = 1;
209 	}else if(event->u.k.key == ADBK_KEYUP(ADBK_OPTION)){ /* keyup */
210 		optionkey_down = 0;
211 		if(adb_ms_buttons & 0xfe){
212 			adb_ms_buttons &= 1;
213 			new_event.def_addr = ADBADDR_MS;
214 			new_event.u.m.buttons = adb_ms_buttons;
215 			new_event.u.m.dx = new_event.u.m.dy = 0;
216 			microtime(&new_event.timestamp);
217 			adb_dokeyupdown(&new_event);
218 		}
219 	}else if(optionkey_down){
220 		if(event->u.k.key == ADBK_KEYDOWN(ADBK_LEFT)){
221 			adb_ms_buttons |= 2;	/* middle down */
222 			new_event.def_addr = ADBADDR_MS;
223 			new_event.u.m.buttons = adb_ms_buttons;
224 			new_event.u.m.dx = new_event.u.m.dy = 0;
225 			microtime(&new_event.timestamp);
226 			adb_dokeyupdown(&new_event);
227 		}else if(event->u.k.key == ADBK_KEYUP(ADBK_LEFT)){
228 			adb_ms_buttons &= ~2;	/* middle up */
229 			new_event.def_addr = ADBADDR_MS;
230 			new_event.u.m.buttons = adb_ms_buttons;
231 			new_event.u.m.dx = new_event.u.m.dy = 0;
232 			microtime(&new_event.timestamp);
233 			adb_dokeyupdown(&new_event);
234 		}else if(event->u.k.key == ADBK_KEYDOWN(ADBK_RIGHT)){
235 			adb_ms_buttons |= 4;	/* right down */
236 			new_event.def_addr = ADBADDR_MS;
237 			new_event.u.m.buttons = adb_ms_buttons;
238 			new_event.u.m.dx = new_event.u.m.dy = 0;
239 			microtime(&new_event.timestamp);
240 			adb_dokeyupdown(&new_event);
241 		}else if(event->u.k.key == ADBK_KEYUP(ADBK_RIGHT)){
242 			adb_ms_buttons &= ~4;	/* right up */
243 			new_event.def_addr = ADBADDR_MS;
244 			new_event.u.m.buttons = adb_ms_buttons;
245 			new_event.u.m.dx = new_event.u.m.dy = 0;
246 			microtime(&new_event.timestamp);
247 			adb_dokeyupdown(&new_event);
248 		}else if(ADBK_MODIFIER(event->u.k.key)){ /* ctrl, shift, cmd */
249 			adb_dokeyupdown(event);
250 		}else if(event->u.k.key & 0x80){ /* key down */
251 			new_event = *event;
252 
253 			new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION);		/* send option-down */
254 			new_event.bytes[0] = new_event.u.k.key;
255 			microtime(&new_event.timestamp);
256 			adb_dokeyupdown(&new_event);
257 
258 			new_event.u.k.key = event->bytes[0];			/* send key-down */
259 			new_event.bytes[0] = new_event.u.k.key;
260 			microtime(&new_event.timestamp);
261 			adb_dokeyupdown(&new_event);
262 
263 			new_event.u.k.key = ADBK_KEYVAL(event->bytes[0]);	/* send key-up */
264 			adb_dokeyupdown(&new_event);
265 			microtime(&new_event.timestamp);
266 			new_event.bytes[0] = new_event.u.k.key;
267 
268 			new_event.u.k.key = ADBK_OPTION;			/* send option-up */
269 			new_event.bytes[0] = new_event.u.k.key;
270 			microtime(&new_event.timestamp);
271 			adb_dokeyupdown(&new_event);
272 
273 		}else{
274 			/* option-keyup -- do nothing */
275 		}
276 	}else{
277 		adb_dokeyupdown(event);
278 	}
279 }
280 
281 
282 void adb_processevent(
283 	adb_event_t *event)
284 {
285 	adb_event_t new_event;
286 
287 	new_event = *event;
288 
289 	switch(event->def_addr){
290 		case ADBADDR_KBD:
291 			new_event.u.k.key = event->bytes[0];
292 			new_event.bytes[1] = 0xff;
293 			adb_keymaybemouse(&new_event);
294 			if(event->bytes[1] != 0xff){
295 				new_event.u.k.key = event->bytes[1];
296 				new_event.bytes[0] = event->bytes[1];
297 				new_event.bytes[1] = 0xff;
298 				adb_keymaybemouse(&new_event);
299 			}
300 			break;
301 
302 		case ADBADDR_MS:
303 			if(! (event->bytes[0] & 0x80)) /* 0 is button down */
304 				adb_ms_buttons |= 1;
305 			else
306 				adb_ms_buttons &= 0xfe;
307 			new_event.u.m.buttons = adb_ms_buttons;
308 			new_event.u.m.dx = ((signed int)(event->bytes[1] &
309 						0x3f)) - ((event->bytes[1] &
310 						0x40) ?  64 : 0);
311 			new_event.u.m.dy = ((signed int)(event->bytes[0] &
312 						0x3f)) - ((event->bytes[0] &
313 						0x40) ?  64 : 0);
314 			adb_dokeyupdown(&new_event);
315 			break;
316 
317 		default:		/* God only knows. */
318 			adb_dokeyupdown(event);
319 	}
320 
321 }
322 
323 
324 int adbopen(
325 	dev_t dev,
326 	int flag,
327 	int mode,
328 	struct proc *p)
329 {
330 	register int unit;
331 	int error = 0;
332 	int s;
333 
334 	unit = minor(dev);
335 	if(unit != 0)
336 		return(ENXIO);
337 
338 	s = splhigh();
339 	if (adb_isopen)
340 	{
341 		splx(s);
342 		return(EBUSY);
343 	}
344 	splx(s);
345 	adb_evq_tail = 0;
346 	adb_evq_len = 0;
347 	adb_isopen = 1;
348 	adb_ioproc = p;
349 
350 	return (error);
351 }
352 
353 
354 int adbclose(
355 	dev_t dev,
356 	int flag,
357 	int mode,
358 	struct proc *p)
359 {
360 	adb_isopen = 0;
361 	adb_ioproc = NULL;
362 	return (0);
363 }
364 
365 
366 int adbread(
367 	dev_t dev,
368 	struct uio *uio,
369 	int flag)
370 {
371 	int s, error;
372 	int willfit;
373 	int total;
374 	int firstmove;
375 	int moremove;
376 
377 	if (uio->uio_resid < sizeof(adb_event_t))
378 		return (EMSGSIZE);	/* close enough. */
379 
380 	s = splhigh();
381 	if(adb_evq_len == 0){
382 		splx(s);
383 		return(0);
384 	}
385 
386 	willfit = howmany(uio->uio_resid, sizeof(adb_event_t));
387 	total = (adb_evq_len < willfit) ? adb_evq_len : willfit;
388 
389 	firstmove = (adb_evq_tail + total > ADB_MAX_EVENTS)
390 		? (ADB_MAX_EVENTS - adb_evq_tail) : total;
391 
392 	error = uiomove((caddr_t)&adb_evq[adb_evq_tail],
393 		firstmove * sizeof(adb_event_t), uio);
394 	if(error) {
395 		splx(s);
396 		return(error);
397 	}
398 	moremove = total - firstmove;
399 
400 	if (moremove > 0){
401 		error = uiomove((caddr_t)&adb_evq[0],
402 			moremove * sizeof(adb_event_t), uio);
403 		if(error) {
404 			splx(s);
405 			return(error);
406 		}
407 	}
408 
409 	adb_evq_tail = (adb_evq_tail + total) % ADB_MAX_EVENTS;
410 	adb_evq_len -= total;
411 	splx(s);
412 	return (0);
413 }
414 
415 
416 int adbwrite(
417 	dev_t dev,
418 	struct uio *uio,
419 	int flag)
420 {
421 	return 0;
422 }
423 
424 
425 int adbioctl(
426 	dev_t dev,
427 	int cmd,
428 	caddr_t data,
429 	int flag,
430 	struct proc *p)
431 {
432 	switch(cmd){
433 		case ADBIOC_DEVSINFO: {
434 			adb_devinfo_t *di = (void *)data;
435 			int totaldevs;
436 			ADBDataBlock adbdata;
437 			int adbaddr;
438 			int i;
439 
440 			/* Initialize to no devices */
441 			for(i = 0; i < 16; i++)
442 				di->dev[i].addr = -1;
443 
444 			totaldevs = CountADBs();
445 			for(i = 1; i <= totaldevs; i++){
446 				adbaddr = GetIndADB(&adbdata, i);
447 					di->dev[adbaddr].addr = adbaddr;
448 					di->dev[adbaddr].default_addr =
449 						adbdata.origADBAddr;
450 					di->dev[adbaddr].handler_id =
451 						adbdata.devType;
452 			}
453 
454 			/* Must call ADB Manager to get devices now */
455 			break;
456 		}
457 
458 		case ADBIOC_GETREPEAT:{
459 			adb_rptinfo_t *ri = (void *)data;
460 
461 			ri->delay_ticks = adb_rptdelay;
462 			ri->interval_ticks = adb_rptinterval;
463 			break;
464 		}
465 
466 		case ADBIOC_SETREPEAT:{
467 			adb_rptinfo_t *ri = (void *)data;
468 
469 			adb_rptdelay = ri->delay_ticks;
470 			adb_rptinterval = ri->interval_ticks;
471 			break;
472 		}
473 
474 		case ADBIOC_RESET:
475 			adb_init();
476 			break;
477 
478 		case ADBIOC_LISTENCMD:{
479 			adb_listencmd_t *lc = (void *)data;
480 		}
481 
482 		default:
483 			return(EINVAL);
484 	}
485 	return(0);
486 }
487 
488 
489 int adbselect(
490 	dev_t dev,
491 	int rw,
492 	struct proc *p)
493 {
494 	switch (rw) {
495 		case FREAD:
496 			/* succeed if there is something to read */
497 			if (adb_evq_len > 0)
498 				return (1);
499 			selrecord(p, &adb_selinfo);
500 			break;
501 
502 		case FWRITE:
503 			return (1);	/* always fails => never blocks */
504 			break;
505 	}
506 
507 	return (0);
508 }
509