FreeBSD/Linux Kernel Cross Reference
sys/chips/dtop_hdw.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: dtop_hdw.c,v $
29 * Revision 2.10 93/11/17 16:11:05 dbg
30 * Import kern/time_out.h for 'hz'.
31 * [93/06/10 dbg]
32 *
33 * Revision 2.9 93/05/15 19:39:04 mrt
34 * machparam.h -> machspl.h
35 *
36 * Revision 2.8 93/05/10 20:07:34 rvb
37 * Fixed types.
38 * [93/05/06 09:59:47 af]
39 *
40 * Revision 2.7 93/03/26 17:58:31 mrt
41 * Rid of dev_t.
42 * [93/03/19 af]
43 *
44 * Revision 2.6 93/02/01 09:55:33 danner
45 * Made all printfs conditional
46 * [93/01/25 danner]
47 *
48 * Revision 2.5 93/01/14 17:15:48 danner
49 * Prototyped handler.
50 * [93/01/14 danner]
51 *
52 * Now that we know how to be heard on the bus, added bell
53 * and .. leds. From jtp@hut.fi.
54 * [92/12/14 af]
55 * Proper spl typing.
56 * [92/11/30 af]
57 *
58 * Revision 2.4 92/05/22 15:47:43 jfriedl
59 * Poll every 16usecs, as per specs.
60 * [92/05/20 22:41:35 af]
61 *
62 * Revision 2.2.1.1 92/05/04 11:19:55 af
63 * Fixed interrupt routine & spls.
64 * Since t_addr is now used to check for presence of
65 * a given line, make sure it is non-zero.
66 * [92/05/04 af]
67 *
68 * Revision 2.2 92/03/02 18:32:29 rpd
69 * Created, from DEC specs.
70 * [92/01/19 af]
71 *
72 */
73 /*
74 * File: dtop_hdw.c
75 * Author: Alessandro Forin, Carnegie Mellon University
76 * Date: 1/92
77 *
78 * Hardware-level operations for the Desktop serial line
79 * bus (i2c aka ACCESS).
80 */
81
82 #include <dtop.h>
83 #if NDTOP > 0
84 #include <bm.h>
85 #include <platforms.h>
86
87 #include <machine/machspl.h> /* spl definitions */
88 #include <mach/std_types.h>
89 #include <kern/kern_io.h>
90 #include <kern/time_out.h> /* hz */
91 #include <device/io_req.h>
92 #include <device/tty.h>
93
94 #include <chips/busses.h>
95 #include <chips/serial_defs.h>
96 #include <chips/screen_defs.h>
97 #include <chips/lk201.h>
98 #include <mips/PMAX/tc.h>
99
100 #include <chips/dtop.h>
101
102 #define DTOP_MAX_POLL 0x7fff /* about half a sec */
103
104 #ifdef MAXINE
105
106 typedef volatile unsigned int *data_reg_t; /* uC */
107 #define DTOP_GET_BYTE(data) (((*(data)) >> 8) & 0xff)
108 #define DTOP_PUT_BYTE(data,c) { *(data) = (c) << 8; }
109
110 typedef volatile unsigned int *poll_reg_t; /* SIR */
111 #define DTOP_RX_AVAIL(poll) (*(poll) & 1)
112 #define DTOP_TX_AVAIL(poll) (*(poll) & 2)
113
114 #else
115
116 define how to get/put DTOP packets on this box
117
118 #endif
119
120 /*
121 * Driver status
122 */
123
124 struct dtop_softc {
125 data_reg_t data;
126 poll_reg_t poll;
127 char polling_mode;
128 char probed_once;
129 short bad_pkts;
130
131 struct dtop_ds {
132 int (*handler)(dtop_device_t,
133 dtop_message_t,
134 int,
135 unsigned char);
136 dtop_device status;
137 } device[(DTOP_ADDR_DEFAULT - DTOP_ADDR_FIRST) >> 1];
138
139 # define DTOP_DEVICE_NO(address) (((address)-DTOP_ADDR_FIRST)>>1)
140
141 } dtop_softc_data[NDTOP];
142
143 typedef struct dtop_softc *dtop_softc_t;
144
145 dtop_softc_t dtop_softc[NDTOP];
146
147 /*
148 * Definition of the driver for the auto-configuration program.
149 */
150
151 boolean_t
152 dtop_probe(
153 vm_offset_t addr,
154 struct bus_device *ui);
155
156 static void
157 dtop_attach(
158 struct bus_device *ui);
159
160 vm_offset_t dtop_std[NDTOP] = { 0 };
161 struct bus_device *dtop_info[NDTOP];
162 struct bus_driver dtop_driver =
163 { dtop_probe, 0, dtop_attach, 0, dtop_std, "dtop", dtop_info,};
164
165
166 int dtop_print_debug = 0;
167
168 void dtop_param(
169 struct tty *tp,
170 int line); /* forward */
171
172 void
173 dtop_start(
174 struct tty *tp);
175
176 void dtop_putc(
177 int unit,
178 int line,
179 int c);
180
181 int dtop_getc(
182 int unit,
183 int line,
184 boolean_t wait,
185 boolean_t raw);
186
187 void dtop_pollc(
188 int unit,
189 boolean_t on);
190
191 int dtop_mctl(
192 int dev,
193 int bits,
194 int how);
195
196 void dtop_softCAR(
197 int unit,
198 int line,
199 int on);
200
201 void dtop_ring_bell(
202 int unit);
203
204 void dtop_leds(
205 int unit,
206 unsigned int mask);
207
208 int dtop_get_packet(
209 dtop_softc_t dtop,
210 dtop_message_t pkt);
211
212 /*
213 * Adapt/Probe/Attach functions
214 */
215
216 void
217 set_dtop_address(
218 int dtopunit,
219 data_reg_t poll_reg)
220 {
221
222 dtop_std[dtopunit] = (vm_offset_t)poll_reg;
223
224 /* Do this here */
225 console_probe = dtop_probe;
226 console_param = dtop_param;
227 console_start = dtop_start;
228 console_putc = dtop_putc;
229 console_getc = dtop_getc;
230 console_pollc = dtop_pollc;
231 console_mctl = dtop_mctl;
232 console_softCAR = dtop_softCAR;
233
234 }
235
236 boolean_t
237 dtop_probe(
238 vm_offset_t addr,
239 struct bus_device *ui)
240 {
241 int dtopunit = ui->unit, i;
242 dtop_softc_t dtop;
243
244 dtop = &dtop_softc_data[dtopunit];
245 dtop_softc[dtopunit] = dtop;
246
247 dtop->poll = (poll_reg_t)dtop_std[dtopunit];
248 dtop->data = (data_reg_t) addr;
249
250 for (i = 0; i < DTOP_MAX_DEVICES; i++)
251 dtop->device[i].handler = dtop_null_device_handler;
252
253 /* a lot more needed here, fornow: */
254 dtop->device[DTOP_DEVICE_NO(0x6a)].handler = dtop_locator_handler;
255 dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.type =
256 DEV_MOUSE;
257 dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.relative =
258 1;
259 dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.button_code[0] =
260 KEY_LEFT_BUTTON;
261 dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.button_code[1] =
262 KEY_RIGHT_BUTTON;
263 dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.button_code[2] =
264 KEY_MIDDLE_BUTTON;
265 dtop->device[DTOP_DEVICE_NO(0x6a)].status.locator.n_coords =
266 2;
267
268 dtop->device[DTOP_DEVICE_NO(0x6c)].handler = dtop_keyboard_handler;
269 dtop->device[DTOP_DEVICE_NO(0x6c)].status.keyboard.poll_frequency =
270 (hz * 5) / 100; /* x0.01 secs */
271 dtop->device[DTOP_DEVICE_NO(0x6c)].status.keyboard.bell_volume =
272 DTOP_CLICK_VOLUME_MAX;
273
274 return TRUE;
275 }
276
277 static void
278 dtop_attach(
279 struct bus_device *ui)
280 {
281 int i;
282
283 /* Initialize all the console ttys */
284 for (i = 0; i < 4; i++)
285 ttychars(console_tty[i]);
286 /* Mark keyboard and mouse present */
287 for (i = 0; i < 2; i++)
288 console_tty[i]->t_addr = (char*)1;
289 }
290
291 /*
292 * Polled I/O (debugger)
293 */
294 void dtop_pollc(
295 int unit,
296 boolean_t on)
297 {
298 dtop_softc_t dtop;
299
300 dtop = dtop_softc[unit];
301 if (on) {
302 dtop->polling_mode++;
303 #if NBM > 0
304 screen_on_off(unit, TRUE);
305 #endif /* NBM > 0 */
306 } else
307 dtop->polling_mode--;
308 }
309
310 /*
311 * Interrupt routine
312 */
313 void dtop_intr(
314 int unit,
315 spl_t spllevel,
316 boolean_t recvd)
317 {
318
319 if (recvd) {
320 dtop_message msg;
321 int devno;
322 dtop_softc_t dtop;
323
324 ssaver_bump(unit);
325
326 #ifdef mips
327 splx(spllevel);
328 #endif
329
330 dtop = dtop_softc[unit];
331 if (dtop_get_packet(dtop, &msg) < 0) {
332 if (dtop_print_debug)
333 printf("%s", "dtop: overrun (or stray)\n");
334 return;
335 }
336
337 devno = DTOP_DEVICE_NO(msg.src_address);
338 if (devno < 0 || devno > 15) return; /* sanity */
339
340 (void) (*dtop->device[devno].handler)
341 (&dtop->device[devno].status, &msg,
342 DTOP_EVENT_RECEIVE_PACKET, 0);
343
344 } else {
345 /* fornow xmit is not intr based */
346 (*tc_enable_interrupt)( dtop_info[unit]->adaptor, FALSE, TRUE);
347 }
348 }
349
350 void
351 dtop_start(
352 struct tty *tp)
353 {
354 /* no, we do not need a char out first */
355 }
356
357 #if TEST
358 dtop_w_test(n, a,b,c,d,e,f,g,h)
359 {
360 int *p = (int*)0xbc2a0000;
361
362 if (n <= 0) return;
363
364 a <<= 8; *p = a;
365 if (--n == 0) goto out;
366 delay(20);
367 b <<= 8; *p = b;
368 if (--n == 0) goto out;
369 delay(20);
370 c <<= 8; *p = c;
371 if (--n == 0) goto out;
372 delay(20);
373 d <<= 8; *p = d;
374 if (--n == 0) goto out;
375 delay(20);
376 e <<= 8; *p = e;
377 if (--n == 0) goto out;
378 delay(20);
379 f <<= 8; *p = f;
380 if (--n == 0) goto out;
381 delay(20);
382 g <<= 8; *p = g;
383 if (--n == 0) goto out;
384 delay(20);
385 h <<= 8; *p = h;
386 out:
387 delay(10000);
388 {
389 int buf[100];
390
391 delay(20);
392 a = *p;
393 buf[0] = a;
394 c = 1;
395 for (n = 0; n < 100; n++) {
396 delay(20);
397 b = *p;
398 if (b != a) {
399 buf[c++] = b;
400 b = a;
401 }
402 }
403 for (n = 0; n < c; n++)
404 db_printf("%x ", ((buf[n])>>8)&0xff);
405 }
406 return c;
407 }
408 #endif
409
410 /*
411 * Take a packet off dtop interface
412 * A packet MUST be there, this is not checked for.
413 */
414 #define DTOP_ESC_CHAR 0xf8
415 int dtop_escape(int c)
416 {
417 /* I donno much about this stuff.. */
418 switch (c) {
419 case 0xe8: return 0xf8;
420 case 0xe9: return 0xf9;
421 case 0xea: return 0xfa;
422 case 0xeb: return 0xfb;
423 default: /* printf("{esc %x}", c); */
424 return c;
425 }
426 }
427
428 int dtop_get_packet(
429 dtop_softc_t dtop,
430 dtop_message_t pkt)
431 {
432 register poll_reg_t poll;
433 register data_reg_t data;
434 register int max, i, len;
435 register unsigned char c;
436
437 poll = dtop->poll;
438 data = dtop->data;
439
440 /*
441 * The interface does not handle us the first byte,
442 * which is our address and cannot ever be anything
443 * else but 0x50. This is a good thing, it makes
444 * the average packet exactly one word long, too.
445 */
446 pkt->src_address = DTOP_GET_BYTE(data);
447
448 for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
449 delay(16);
450 if (max == DTOP_MAX_POLL) goto bad;
451 pkt->code.bits = DTOP_GET_BYTE(data);
452
453 /*
454 * Now get data and checksum
455 */
456 len = pkt->code.val.len + 1;
457 c = 0;
458 for (i = 0; i < len; i++) {
459
460 again: for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(poll); max++)
461 delay(16);
462 if (max == DTOP_MAX_POLL) goto bad;
463 if (c == DTOP_ESC_CHAR) {
464 c = dtop_escape(DTOP_GET_BYTE(data) & 0xff);
465 } else {
466 c = DTOP_GET_BYTE(data);
467 if (c == DTOP_ESC_CHAR)
468 goto again;
469 }
470
471 pkt->body[i] = c;
472 }
473 return len;
474 bad:
475 dtop->bad_pkts++;
476 return -1;
477 }
478
479 /* Conversely... */
480 boolean_t
481 dtop_put_packet(
482 dtop_softc_t dtop,
483 dtop_message_t pkt)
484 {
485 register int i, max;
486 register unsigned char *cp;
487 register spl_t spl;
488 register unsigned char c;
489
490 spl = spltty();
491 pkt->src_address = pkt->dest_address;
492 i = 0;
493 cp = (unsigned char *)&pkt->src_address;
494 while (i < pkt->code.val.len + 2) {
495 for (max = 0; max < DTOP_MAX_POLL && !DTOP_TX_AVAIL(dtop->poll);
496 max++);
497 if (max == DTOP_MAX_POLL)
498 goto bad;
499 DTOP_PUT_BYTE(dtop->data, *cp);
500 cp++;
501 i++;
502 }
503 for (max = 0; (max < DTOP_MAX_POLL) && !DTOP_RX_AVAIL(dtop->poll); max++)
504 delay(16);
505 if (max == DTOP_MAX_POLL)
506 goto bad;
507 c = DTOP_GET_BYTE(dtop->data);
508 if (c == DTOP_ESC_CHAR) {
509 for (max = 0; (max < DTOP_MAX_POLL)
510 && !DTOP_RX_AVAIL(dtop->poll); max++)
511 delay(16);
512 if (max == DTOP_MAX_POLL)
513 goto bad;
514 c = DTOP_GET_BYTE(dtop->data);
515 }
516 splx(spl);
517 switch (c) {
518 case 0xfb: /* XMT, ok */
519 break;
520 default:
521 return FALSE;
522 }
523 return TRUE;
524 bad:
525 splx(spl);
526 return FALSE;
527 }
528
529
530 /*
531 * Get a char from a specific DTOP line
532 * [this is only used for console&screen purposes]
533 */
534 int
535 dtop_getc(
536 int unit,
537 int line,
538 boolean_t wait,
539 boolean_t raw)
540 {
541 register int c;
542 dtop_softc_t dtop;
543
544 dtop = dtop_softc[unit];
545 again:
546 c = -1;
547
548 /*
549 * Try rconsole first
550 */
551 if (rcline && line == SCREEN_LINE_KEYBOARD) {
552 c = scc_getc( 0, rcline, FALSE, raw);
553 if (c != -1) return c;
554 }
555
556 /*
557 * Now check keyboard
558 */
559 if (DTOP_RX_AVAIL(dtop->poll)) {
560
561 dtop_message msg;
562 struct dtop_ds *ds;
563
564 if (dtop_get_packet(dtop, &msg) >= 0) {
565
566 ds = &dtop->device[DTOP_DEVICE_NO(msg.src_address)];
567 if (ds->handler == dtop_keyboard_handler) {
568
569 c = dtop_keyboard_handler(
570 &ds->status, &msg,
571 DTOP_EVENT_RECEIVE_PACKET, -1);
572
573 if (c > 0) return c;
574
575 c = -1;
576 }
577 }
578 }
579
580 if (wait && (c == -1)) {
581 delay(100);
582 goto again;
583 }
584
585 return c;
586 }
587
588 /*
589 * Put a char on a specific DTOP line
590 */
591 void
592 dtop_putc(
593 int unit,
594 int line,
595 int c)
596 {
597 if (rcline && line == rcline) {
598 scc_putc(0, rcline, c);
599 }
600 /* dprintf("%c", c); */
601 }
602
603 void dtop_param(
604 struct tty *tp,
605 int line)
606 {
607 if (tp->t_ispeed == 0)
608 ttymodem(tp, 0);
609 else
610 /* called too early to invoke ttymodem, sigh */
611 tp->t_state |= TS_CARR_ON;
612 }
613
614 /*
615 * Modem control functions, we don't need 'em
616 */
617 int dtop_mctl(
618 int dev,
619 int bits,
620 int how)
621 {
622 return 0;
623 }
624
625 void dtop_softCAR(
626 int unit,
627 int line,
628 int on)
629 {
630 }
631
632 /* Some keyboard specific stuff, probably belongs elsewhere */
633
634 boolean_t
635 dtop_kbd_probe(
636 int unit)
637 {
638 if (dtop_std[unit]) {
639 lk201_probe(unit);
640 return TRUE;
641 }
642 return FALSE;
643 }
644
645 io_return_t
646 dtop_set_status(
647 int unit,
648 int flavor,
649 dev_status_t status,
650 natural_t status_count)
651 {
652 dtop_device_t dev;
653
654 dev = &dtop_softc[unit]->device[DTOP_DEVICE_NO(0x6c)].status;
655
656 switch (flavor) {
657 case LK201_SEND_CMD: {
658 register lk201_cmd_t *cmd = (lk201_cmd_t *)status;
659 unsigned int cnt;
660
661 if ((status_count < (sizeof(*cmd)/sizeof(int))) ||
662 ((cnt = cmd->len) > 2))
663 return D_INVALID_SIZE;
664 switch (cmd->command) {
665 case LK_CMD_ENB_BELL:
666 cmd->params[0] ^= 0x7;
667 if (dtop_print_debug)
668 printf("LK_CMD_ENB_BELL %d\n", cmd->params[0]);
669 dev->keyboard.bell_volume = cmd->params[0] & 0x7;
670 break;
671 case LK_CMD_DIS_BELL:
672 dev->keyboard.bell_volume = 0;
673 break;
674 case LK_CMD_BELL:
675 dtop_ring_bell(unit);
676 break;
677 case LK_CMD_LEDS_ON:
678 cmd->params[0] &= ~0x80;
679 if (dtop_print_debug)
680 printf("LK_CMD_LEDS_ON %d %x\n",
681 cmd->params[0], cmd->params[0]);
682 dev->keyboard.led_status |= cmd->params[0];
683 dtop_leds(unit, dev->keyboard.led_status);
684 break;
685 case LK_CMD_LEDS_OFF:
686 cmd->params[0] &= ~0x80;
687 dev->keyboard.led_status &= ~cmd->params[0];
688 dtop_leds(unit, dev->keyboard.led_status);
689 break;
690 case LK_CMD_ENB_KEYCLK:
691 case LK_CMD_DIS_KEYCLK:
692 case LK_CMD_SOUND_CLK:
693 case LK_CMD_DIS_CTLCLK:
694 case LK_CMD_ENB_CTLCLK:
695 break;
696 default:
697 break;
698 }
699 break;
700 }
701 default:
702 break;
703 }
704 return lk201_set_status(unit, flavor, status, status_count);
705 }
706
707 void dtop_kbd_reset(
708 int unit)
709 {
710 lk201_reset(unit);
711 }
712
713 #define DTOP_BITS(p, len) (((p) << 7) | (len))
714
715 void dtop_ring_bell(
716 int unit)
717 {
718 dtop_message msg;
719 dtop_device_t dev;
720 int vol;
721
722 dev = &dtop_softc[unit]->device[DTOP_DEVICE_NO(0x6c)].status;
723 vol = dev->keyboard.bell_volume;
724
725 if (dtop_print_debug)
726 printf("dtop_ring_bell: %d\n", vol);
727 msg.dest_address = DTOP_ADDR_KBD;
728 msg.code.bits = DTOP_BITS(1, 2);
729 msg.body[0] = DTOP_KMSG_BELL;
730 msg.body[1] = vol;
731 if (!dtop_put_packet(dtop_softc[unit], &msg)) {
732 if (dtop_print_debug)
733 printf("dtop_ring_bell: dtop_put_packet failed\n");
734 }
735 }
736
737 void dtop_leds(
738 int unit,
739 unsigned int mask)
740 {
741 dtop_message msg;
742
743 if (dtop_print_debug)
744 printf("dtop_leds %x\n", mask);
745 msg.dest_address = DTOP_ADDR_KBD;
746 msg.code.bits = DTOP_BITS(1, 2);
747 msg.body[0] = DTOP_KMSG_LED;
748 msg.body[1] = mask;
749 if (!dtop_put_packet(dtop_softc[unit], &msg)) {
750 if (dtop_print_debug)
751 printf("dtop_leds: dtop_put_packet failed\n");
752 }
753 }
754
755
756
757 #endif /* NDTOP > 0 */
Cache object: e11c1aac2fc3f76d90c47c63ce5dcf11
|