lk201.cc Source File

Back to the index.

lk201.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2018 Anders Gavare. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  * derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *
28  * COMMENT: LK201 keyboard and mouse, used by the dc7085 and scc controllers
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "console.h"
36 #include "devices.h"
37 #include "machine.h"
38 #include "misc.h"
39 
40 #include "thirdparty/dc7085.h" /* for port names */
41 #include "thirdparty/lk201.h"
42 
43 
44 // #define debug fatal
45 
46 
47 /*
48  * lk201_convert_ascii_to_keybcode():
49  *
50  * Converts ascii console input to LK201 keyboard scan codes, and adds
51  * those scancodes using the add_to_rx_queue() function.
52  */
53 void lk201_convert_ascii_to_keybcode(struct lk201_data *d, unsigned char ch)
54 {
55  int i, found=-1, shifted = 0, controlled = 0;
56 
57  if (d->keyb_buf_pos > 0 && d->keyb_buf_pos < (int)sizeof(d->keyb_buf)) {
58  /* Escape sequence: */
59  d->keyb_buf[d->keyb_buf_pos] = ch;
60  d->keyb_buf_pos ++;
61 
62  if (d->keyb_buf_pos == 2) {
63  if (ch == '[')
64  return;
65  d->keyb_buf_pos = 0;
66  /* not esc+[, output as normal key */
67  } else {
68  /* Inside an esc+[ sequence */
69 
70  switch (ch) {
71  case 'A': found = 0xaa; /* Up */ break;
72  case 'B': found = 0xa9; /* Down */ break;
73  case 'C': found = 0xa8; /* Right */ break;
74  case 'D': found = 0xa7; /* Left */ break;
75  /* TODO: pageup, pagedown, ... */
76  default:
77  ;
78  }
79 
80  d->keyb_buf_pos = 0;
81  }
82  } else
83  d->keyb_buf_pos = 0;
84 
85  if (found == -1) {
86  switch (ch) {
87  case '\b':
88  found = 0xbc;
89  break;
90  case '\n':
91  case '\r':
92  found = 0xbd;
93  break;
94  case '\t':
95  found = 0xbe;
96  break;
97  case 27: /* esc */
98  d->keyb_buf[0] = 27;
99  d->keyb_buf_pos = 1;
100  return;
101  default:
102  if (ch >= 1 && ch <= 26) {
103  ch = 'a' + ch - 1;
104  controlled = 1;
105  }
106 
107  shifted = 0;
108  for (i=0; i<256; i++) {
109  /* Skip numeric digits, so that the normal
110  digits are used instead. */
111  if (i >= 0x92 && i<=0xa0)
112  continue;
113 
114  if (unshiftedAscii[i] == ch) {
115  found = i;
116  break;
117  }
118  }
119 
120  if (found == -1) {
121  /* unshift ch: */
122  if (ch >= 'A' && ch <= 'Z')
123  ch = ch + ('a' - 'A');
124  for (i=0; i<256; i++)
125  if (shiftedAscii[i] == ch) {
126  found = i;
127  shifted = 1;
128  break;
129  }
130  }
131  }
132  }
133 
134  if (!shifted)
136  else {
139  }
140 
141  if (controlled)
143 
144  /* Send the actual scan code: */
145  d->add_to_rx_queue(d->add_data, found, DCKBD_PORT);
146 
147  /* Release the key: */
149 }
150 
151 
152 /*
153  * lk201_send_mouse_update_sequence():
154  *
155  * mouse_x, _y, _buttons contains the coordinates on the host's display, the
156  * "goal" of where we want to move.
157  *
158  * d->mouse_x, _y, _buttons contain the last values transmitted to the
159  * emulated machine.
160  */
161 static int lk201_send_mouse_update_sequence(struct lk201_data *d, int mouse_x,
162  int mouse_y, int mouse_buttons, int mouse_fb_nr)
163 {
164  int xsign, xdelta, ysign, ydelta, m;
165 
166  xdelta = mouse_x - d->mouse_x;
167  ydelta = mouse_y - d->mouse_y;
168 
169  /* If no change, then don't send any update! */
170  if (xdelta == 0 && ydelta == 0 && d->mouse_buttons == mouse_buttons)
171  return 0;
172 
173  m = 20;
174 
175  if (xdelta > m)
176  xdelta = m;
177  if (xdelta < -m)
178  xdelta = -m;
179  if (ydelta > m)
180  ydelta = m;
181  if (ydelta < -m)
182  ydelta = -m;
183 
184  d->mouse_x += xdelta;
185  d->mouse_y += ydelta;
186  d->mouse_buttons = mouse_buttons;
187 
188  /*
189  * TODO: Update d->mouse_framebuffer_nr some way!
190  */
191 
192  xsign = xdelta < 0? 1 : 0;
193  ysign = ydelta < 0? 1 : 0;
194 
195  switch (d->mouse_mode) {
196 
197  case 0:
198  /* Do nothing (before the mouse is initialized) */
199  return 0;
200 
201  case MOUSE_INCREMENTAL:
202  if (xdelta < 0)
203  xdelta = -xdelta;
204  if (ydelta < 0)
205  ydelta = -ydelta;
206 
207  /* Reverse sign of x: (this is needed for some reason) */
208  xsign ^= 1;
209 
211  MOUSE_X_SIGN*xsign + MOUSE_Y_SIGN*ysign +
212  (mouse_buttons & 7), DCMOUSE_PORT);
213  d->add_to_rx_queue(d->add_data, xdelta, DCMOUSE_PORT);
214  d->add_to_rx_queue(d->add_data, ydelta, DCMOUSE_PORT);
215  break;
216 
217  default:
218  /* TODO: prompt mode and perhaps more stuff */
219  fatal("[ lk201: mouse mode 0x%02x unknown: TODO ]\n",
220  d->mouse_mode);
221  exit(1);
222  }
223 
224  return 1;
225 }
226 
227 
228 /*
229  * lk201_tick():
230  *
231  * This function should be called "every now and then".
232  * If a key is available from the keyboard, add it to the rx queue.
233  * If other bits are set, an interrupt might need to be caused.
234  */
235 void lk201_tick(struct machine *machine, struct lk201_data *d)
236 {
237  int mouse_x, mouse_y, mouse_buttons, mouse_fb_nr;
238 
240  unsigned char ch = console_readchar(d->console_handle);
241  if (d->use_fb)
243  else {
244  /*
245  * This is ugly, but necessary because different
246  * machines seem to use different ports for their
247  * serial console:
248  *
249  * DEC MIPSMATE 5100 uses the keyboard port.
250  * DECstation 3100 (PMAX) and 5000/2000 (3MAX) use
251  * the printer port.
252  * Others seem to use the comm port.
253  */
254  if (machine->machine_type == MACHINE_PMAX) {
255  switch (machine->machine_subtype) {
258  ch, DCKBD_PORT);
259  break;
263  ch, DCPRINTER_PORT);
264  break;
265  default:
267  ch, DCCOMM_PORT);
268  }
269  } else {
271  ch, DCCOMM_PORT);
272  }
273  }
274  }
275 
276  /* Don't do mouse updates if we're running in serial console mode: */
277  if (!d->use_fb)
278  return;
279 
280  console_getmouse(&mouse_x, &mouse_y, &mouse_buttons,
281  &mouse_fb_nr);
282 
283  lk201_send_mouse_update_sequence(d, mouse_x, mouse_y,
284  mouse_buttons, mouse_fb_nr);
285 }
286 
287 
288 void lk201_tx_data(struct lk201_data *d, int port, int idata)
289 {
290  switch (port) {
291  case DCKBD_PORT: /* port 0 */
292  if (!d->use_fb) {
293  /* Simply print the character to stdout: */
294  console_putchar(d->console_handle, idata);
295  } else {
296  debug("[ lk201: writing data to KBD: 0x%02x ]\n", idata);
297  switch (idata) {
298  case LK_LED_DISABLE: /* 0x11 */
299  break;
300  case LK_LED_ENABLE: /* 0x13 */
301  break;
302  case LK_BELL_ENABLE: /* 0x23 */
303  break;
304  case 0x41:
305  d->add_to_rx_queue(d->add_data, 0xa, DCKBD_PORT);
306  d->add_to_rx_queue(d->add_data, 0xb, DCKBD_PORT);
307  d->add_to_rx_queue(d->add_data, 0xc, DCKBD_PORT);
308  d->add_to_rx_queue(d->add_data, 0xd, DCKBD_PORT);
309  break;
310  case LED_1:
311  case LED_2:
312  break;
313  case LED_3:
314  break;
315  case LED_4:
316  break;
317  case LK_KBD_ENABLE: /* 0x8b */
318  break;
319  case LED_ALL: /* 0x8f */
320  break;
321  case LK_RING_BELL: /* 0xa7 */
322  break;
323  case 0xab: /* Get Keyboard ID: */
324  /*
325  * First byte:
326  * 1 = LK201
327  * 2 = LK401
328  * 3 = LK443
329  * 4 = LK421
330  *
331  * TODO: What about the second byte? 0x22 or
332  * 0x00?
333  */
334  d->add_to_rx_queue(d->add_data, 0x01, DCKBD_PORT);
335  d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT);
336  break;
337  case LK_DEFAULTS: /* 0xd3 */
338  /* TODO? */
339  break;
340  case 0xfd: /* Keyboard self-test: */
341  /* Suitable return values according to
342  Mach/PMAX source code: */
344  0x01, DCKBD_PORT);
346  0x00, DCKBD_PORT);
348  0x00, DCKBD_PORT);
350  0x00, DCKBD_PORT);
351  break;
352  default:
353  debug("[ lk201: unimplemented keyboard control: 0x%x ]\n",
354  idata);
355  }
356  }
357  break;
358  case DCMOUSE_PORT: /* port 1 */
359  debug("[ lk201: writing data to MOUSE: 0x%x ", idata);
360  switch (idata) {
361  case MOUSE_INCREMENTAL:
363  break;
364  case MOUSE_SELF_TEST:
365  /*
366  * Mouse self-test:
367  *
368  * TODO: Find out if this is correct. The lowest
369  * four bits of the second byte should be
370  * 0x2, according to NetBSD/pmax. But the
371  * other bits and bytes?
372  */
373  debug("(mouse self-test request)");
375  0xa0 | d->mouse_revision, DCMOUSE_PORT);
376  d->add_to_rx_queue(d->add_data, 0x02, DCMOUSE_PORT);
377  d->add_to_rx_queue(d->add_data, 0x00, DCMOUSE_PORT);
378  d->add_to_rx_queue(d->add_data, 0x00, DCMOUSE_PORT);
379  break;
380  default:
381  debug("UNKNOWN byte; TODO");
382  }
383  debug(" ]\n");
384  break;
385  case DCCOMM_PORT: /* port 2 */
386  case DCPRINTER_PORT: /* port 3 */
387  /* Simply print the character to stdout: */
388  console_putchar(d->console_handle, idata);
389  }
390 }
391 
392 
393 /*
394  * lk201_init():
395  *
396  * Initialize lk201 keyboard/mouse settings.
397  */
398 void lk201_init(struct lk201_data *d, int use_fb,
399  void (*add_to_rx_queue)(void *,int,int),
400  int console_handle, void *add_data)
401 {
402  memset(d, 0, sizeof(struct lk201_data));
403 
405  d->add_data = add_data;
406 
407  d->use_fb = use_fb;
408  d->mouse_mode = 0;
409  d->mouse_revision = 0; /* 0..15 */
410  d->console_handle = console_handle;
411 
412  /*
413  * Power up self-test result, as per
414  * https://www.netbsd.org/docs/Hardware/Machines/DEC/lk201.html#power_up
415  */
416  if (d->use_fb) {
417  d->add_to_rx_queue(d->add_data, 0x01, DCKBD_PORT);
418  d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT);
419  d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT);
420  d->add_to_rx_queue(d->add_data, 0x00, DCKBD_PORT);
421  }
422 }
423 
424 
#define LED_ALL
Definition: lk201.h:156
void fatal(const char *fmt,...)
Definition: main.cc:152
void console_getmouse(int *x, int *y, int *buttons, int *fb_nr)
Definition: console.cc:497
int mouse_x
Definition: devices.h:522
#define MOUSE_INCREMENTAL
Definition: lk201.h:176
#define DCMOUSE_PORT
Definition: dc7085.h:157
int machine_type
Definition: machine.h:111
#define MOUSE_Y_SIGN
Definition: lk201.h:189
void add_to_rx_queue(void *e, int ch, int line_no)
Definition: dev_dc7085.cc:74
#define MACHINE_PMAX
Definition: machine.h:213
#define DCCOMM_PORT
Definition: dc7085.h:158
void console_putchar(int handle, int ch)
Definition: console.cc:405
int console_readchar(int handle)
Definition: console.cc:385
void lk201_tick(struct machine *machine, struct lk201_data *d)
Definition: lk201.cc:235
#define LK_RING_BELL
Definition: lk201.h:151
#define MACHINE_DEC_PMAX_3100
Definition: machine.h:265
void lk201_tx_data(struct lk201_data *d, int port, int idata)
Definition: lk201.cc:288
void * add_data
Definition: devices.h:515
#define DCPRINTER_PORT
Definition: dc7085.h:159
#define LK_LED_ENABLE
Definition: lk201.h:149
int mouse_buttons
Definition: devices.h:522
int console_charavail(int handle)
Definition: console.cc:336
#define LK_BELL_ENABLE
Definition: lk201.h:148
int mouse_revision
Definition: devices.h:521
#define LK_KBD_ENABLE
Definition: lk201.h:147
#define DCKBD_PORT
Definition: dc7085.h:156
#define LED_1
Definition: lk201.h:152
#define MOUSE_X_SIGN
Definition: lk201.h:188
#define KEY_SHIFT
Definition: lk201.h:129
#define MOUSE_SELF_TEST
Definition: lk201.h:175
#define LK_LED_DISABLE
Definition: lk201.h:150
int keyb_buf_pos
Definition: devices.h:518
#define MACHINE_DEC_MIPSMATE_5100
Definition: machine.h:273
int console_handle
Definition: devices.h:512
#define LED_4
Definition: lk201.h:155
#define MACHINE_DEC_3MAX_5000
Definition: machine.h:266
#define debug
Definition: dev_adb.cc:57
int mouse_y
Definition: devices.h:522
#define KEY_UP
Definition: lk201.h:133
unsigned char keyb_buf[8]
Definition: devices.h:517
void lk201_init(struct lk201_data *d, int use_fb, void(*add_to_rx_queue)(void *, int, int), int console_handle, void *add_data)
Definition: lk201.cc:398
#define MOUSE_START_FRAME
Definition: lk201.h:187
void(* add_to_rx_queue)(void *, int, int)
Definition: devices.h:514
#define KEY_CONTROL
Definition: lk201.h:130
int use_fb
Definition: devices.h:511
#define LK_DEFAULTS
Definition: lk201.h:144
int machine_subtype
Definition: machine.h:112
int mouse_mode
Definition: devices.h:520
void lk201_convert_ascii_to_keybcode(struct lk201_data *d, unsigned char ch)
Definition: lk201.cc:53
#define LED_2
Definition: lk201.h:153
#define LED_3
Definition: lk201.h:154

Generated on Fri Dec 7 2018 19:52:23 for GXemul by doxygen 1.8.13