1/* $NetBSD: lk201_ws.c,v 1.7 2005/12/11 12:21:20 christos Exp $ */
2
3/*
4 * Copyright (c) 1998
5 *	Matthias Drochner.  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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: lk201_ws.c,v 1.7 2005/12/11 12:21:20 christos Exp $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34
35#include <dev/wscons/wsconsio.h>
36
37#include <dev/dec/lk201reg.h>
38#include <dev/dec/lk201var.h>
39#include <dev/dec/wskbdmap_lk201.h> /* for {MIN,MAX}_LK201_KEY */
40
41#define send(lks, c) ((*((lks)->attmt.sendchar))((lks)->attmt.cookie, c))
42
43int
44lk201_init(struct lk201_state *lks)
45{
46	int i;
47
48	send(lks, LK_LED_ENABLE);
49	send(lks, LK_LED_ALL);
50
51	/*
52	 * set all keys to updown mode; autorepeat is
53	 * done by wskbd software
54	 */
55	for (i = 1; i <= 14; i++)
56		send(lks, LK_CMD_MODE(LK_UPDOWN, i));
57
58	send(lks, LK_CL_ENABLE);
59	send(lks, LK_PARAM_VOLUME(3));
60	lks->kcvol = (8 - 3) * 100 / 8;
61
62	lks->bellvol = -1; /* not yet set */
63
64	for (i = 0; i < LK_KLL; i++)
65		lks->down_keys_list[i] = -1;
66	send(lks, LK_KBD_ENABLE);
67
68	send(lks, LK_LED_DISABLE);
69	send(lks, LK_LED_ALL);
70	lks->leds_state = 0;
71
72	return (0);
73}
74
75int
76lk201_decode(struct lk201_state *lks, int datain, u_int *type, int *dataout)
77{
78	int i, freeslot;
79
80	switch (datain) {
81	    case LK_KEY_UP:
82		for (i = 0; i < LK_KLL; i++)
83			lks->down_keys_list[i] = -1;
84		*type = WSCONS_EVENT_ALL_KEYS_UP;
85		return (1);
86	    case LK_POWER_UP:
87		printf("lk201_decode: powerup detected\n");
88		lk201_init(lks);
89		return (0);
90	    case LK_KDOWN_ERROR:
91	    case LK_POWER_ERROR:
92	    case LK_OUTPUT_ERROR:
93	    case LK_INPUT_ERROR:
94		printf("lk201_decode: error %x\n", datain);
95		/* FALLTHRU */
96	    case LK_KEY_REPEAT: /* autorepeat handled by wskbd */
97	    case LK_MODE_CHANGE: /* ignore silently */
98		return (0);
99	}
100
101	if (datain < MIN_LK201_KEY || datain > MAX_LK201_KEY) {
102		printf("lk201_decode: %x\n", datain);
103		return (0);
104	}
105
106	*dataout = datain - MIN_LK201_KEY;
107
108	freeslot = -1;
109	for (i = 0; i < LK_KLL; i++) {
110		if (lks->down_keys_list[i] == datain) {
111			*type = WSCONS_EVENT_KEY_UP;
112			lks->down_keys_list[i] = -1;
113			return (1);
114		}
115		if (lks->down_keys_list[i] == -1 && freeslot == -1)
116			freeslot = i;
117	}
118
119	if (freeslot == -1) {
120		printf("lk201_decode: down(%d) no free slot\n", datain);
121		return (0);
122	}
123
124	*type = WSCONS_EVENT_KEY_DOWN;
125	lks->down_keys_list[freeslot] = datain;
126	return (1);
127}
128
129void
130lk201_bell(struct lk201_state *lks, struct wskbd_bell_data *bell)
131{
132	unsigned int vol;
133
134	if (bell->which & WSKBD_BELL_DOVOLUME) {
135		vol = 8 - bell->volume * 8 / 100;
136		if (vol > 7)
137			vol = 7;
138	} else
139		vol = 3;
140
141	if (vol != lks->bellvol) {
142		send(lks, LK_BELL_ENABLE);
143		send(lks, LK_PARAM_VOLUME(vol));
144		lks->bellvol = vol;
145	}
146	send(lks, LK_RING_BELL);
147}
148
149void
150lk201_set_leds(struct lk201_state *lks, int leds)
151{
152	int newleds;
153
154	newleds = 0;
155	if (leds & WSKBD_LED_SCROLL)
156		newleds |= LK_LED_WAIT;
157	if (leds & WSKBD_LED_CAPS)
158		newleds |= LK_LED_LOCK;
159
160	send(lks, LK_LED_DISABLE);
161	send(lks, (0x80 | (~newleds & 0x0f)));
162
163	send(lks, LK_LED_ENABLE);
164	send(lks, (0x80 | (newleds & 0x0f)));
165
166	lks->leds_state = leds;
167}
168
169void
170lk201_set_keyclick(struct lk201_state *lks, int vol)
171{
172	unsigned int newvol;
173
174	if (vol == 0)
175		send(lks, LK_CL_DISABLE);
176	else {
177		newvol = 8 - vol * 8 / 100;
178		if (newvol > 7)
179			newvol = 7;
180
181		send(lks, LK_CL_ENABLE);
182		send(lks, LK_PARAM_VOLUME(newvol));
183	}
184
185	lks->kcvol = vol;
186}
187