xref: /dragonfly/sys/dev/misc/atkbdc_layer/atkbdc_isa.c (revision 2efb75f3055c1746efc358d68dbc2bf526faaf61)
1 /*-
2  * (MPSAFE)
3  *
4  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
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 as
12  *    the first lines of this file unmodified.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/isa/atkbdc_isa.c,v 1.14.2.1 2000/03/31 12:52:05 yokota Exp $
29  */
30 
31 #include "opt_kbd.h"
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/bus.h>
37 #include <sys/malloc.h>
38 #include <sys/rman.h>
39 #include <sys/thread.h>
40 
41 #include <dev/misc/kbd/atkbdcreg.h>
42 
43 #include <bus/isa/isareg.h>
44 #include <bus/isa/isavar.h>
45 
46 #if 0
47 #define lwkt_gettoken(x)
48 #define lwkt_reltoken(x)
49 #endif
50 
51 MALLOC_DEFINE(M_ATKBDDEV, "atkbddev", "AT Keyboard device");
52 
53 /* children */
54 typedef struct atkbdc_device {
55           int flags;          /* configuration flags */
56           int irq;  /* ISA IRQ mask */
57           u_int32_t vendorid;
58           u_int32_t serial;
59           u_int32_t logicalid;
60           u_int32_t compatid;
61 } atkbdc_device_t;
62 
63 /* kbdc */
64 devclass_t atkbdc_devclass;
65 
66 static int          atkbdc_probe(device_t dev);
67 static int          atkbdc_attach(device_t dev);
68 static int          atkbdc_print_child(device_t bus, device_t dev);
69 static int          atkbdc_read_ivar(device_t bus, device_t dev, int index,
70                                          u_long *val);
71 static int          atkbdc_write_ivar(device_t bus, device_t dev, int index,
72                                           u_long val);
73 
74 static device_method_t atkbdc_methods[] = {
75           DEVMETHOD(device_probe,                 atkbdc_probe),
76           DEVMETHOD(device_attach,      atkbdc_attach),
77           DEVMETHOD(device_suspend,     bus_generic_suspend),
78           DEVMETHOD(device_resume,      bus_generic_resume),
79 
80           DEVMETHOD(bus_print_child,    atkbdc_print_child),
81           DEVMETHOD(bus_read_ivar,      atkbdc_read_ivar),
82           DEVMETHOD(bus_write_ivar,     atkbdc_write_ivar),
83           DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
84           DEVMETHOD(bus_release_resource,         bus_generic_release_resource),
85           DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
86           DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
87           DEVMETHOD(bus_setup_intr,     bus_generic_setup_intr),
88           DEVMETHOD(bus_teardown_intr,  bus_generic_teardown_intr),
89 
90           DEVMETHOD_END
91 };
92 
93 static driver_t atkbdc_driver = {
94           ATKBDC_DRIVER_NAME,
95           atkbdc_methods,
96           sizeof(atkbdc_softc_t *),
97 };
98 
99 static struct isa_pnp_id atkbdc_ids[] = {
100           { 0x0303d041, "Keyboard controller (i8042)" },    /* PNP0303 */
101           { 0x0703d041, "Keyboard controller (i8042)" },    /* PNP0307 */
102           { 0x0b03d041, "Keyboard controller (i8042)" },    /* PNP030B */
103           /* Japanese */
104           { 0x2003d041, "Keyboard controller (i8042)" },    /* PNP0320 */
105           { 0x2103d041, "Keyboard controller (i8042)" },    /* PNP0321 */
106           { 0x2203d041, "Keyboard controller (i8042)" },    /* PNP0322 */
107           { 0x2303d041, "Keyboard controller (i8042)" },    /* PNP0323 */
108           { 0x2403d041, "Keyboard controller (i8042)" },    /* PNP0324 */
109           { 0x2503d041, "Keyboard controller (i8042)" },    /* PNP0325 */
110           { 0x2603d041, "Keyboard controller (i8042)" },    /* PNP0326 */
111           { 0x2703d041, "Keyboard controller (i8042)" },    /* PNP0327 */
112           /* Korean */
113           { 0x4003d041, "Keyboard controller (i8042)" },    /* PNP0340 */
114           { 0x4103d041, "Keyboard controller (i8042)" },    /* PNP0341 */
115           { 0x4203d041, "Keyboard controller (i8042)" },    /* PNP0342 */
116           { 0x4303d041, "Keyboard controller (i8042)" },    /* PNP0343 */
117           { 0x4403d041, "Keyboard controller (i8042)" },    /* PNP0344 */
118           { 0 }
119 };
120 
121 extern int acpi_fadt_8042_nolegacy;
122 
123 static int
atkbdc_probe(device_t dev)124 atkbdc_probe(device_t dev)
125 {
126           device_t parent = device_get_parent(dev);
127           struct resource     *port0;
128           struct resource     *port1;
129           int                 error;
130           int                 rid;
131 #if defined(__x86_64__)
132           bus_space_tag_t     tag;
133           bus_space_handle_t ioh1;
134           volatile int        i;
135 #endif
136 
137           if (strcmp(device_get_name(parent), "acpi") != 0 &&
138               acpi_fadt_8042_nolegacy != 0) {
139                     device_t acpidev = devclass_find_unit("acpi", 0);
140 
141                     /*
142                      * If acpi didn't attach, we should go ahead with the legacy
143                      * i8042 probing.
144                      */
145                     if (acpidev != NULL && device_is_attached(acpidev)) {
146                               /* We should find i8042 via the ACPI namespace. */
147                               return ENXIO;
148                     }
149           }
150 
151           /* check PnP IDs */
152           if (ISA_PNP_PROBE(parent, dev, atkbdc_ids) == ENXIO)
153                     return ENXIO;
154 
155           device_set_desc(dev, "Keyboard controller (i8042)");
156 
157           rid = 0;
158           port0 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
159                                            RF_ACTIVE);
160           if (port0 == NULL)
161                     return ENXIO;
162           /* XXX */
163           if (bus_get_resource_start(dev, SYS_RES_IOPORT, 1) <= 0) {
164                     bus_set_resource(dev, SYS_RES_IOPORT, 1,
165                         rman_get_start(port0) + KBD_STATUS_PORT, 1, -1);
166           }
167           rid = 1;
168           port1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
169                                            RF_ACTIVE);
170           if (port1 == NULL) {
171                     bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
172                     return ENXIO;
173           }
174 
175 #if defined(__x86_64__)
176           /*
177            * Check if we really have AT keyboard controller. Poll status
178            * register until we get "all clear" indication. If no such
179            * indication comes, it probably means that there is no AT
180            * keyboard controller present. Give up in such case. Check relies
181            * on the fact that reading from non-existing in/out port returns
182            * 0xff on i386. May or may not be true on other platforms.
183            */
184           tag = rman_get_bustag(port0);
185           ioh1 = rman_get_bushandle(port1);
186           for (i = 65536; i != 0; --i) {
187                     if ((bus_space_read_1(tag, ioh1, 0) & 0x2) == 0)
188                               break;
189                     DELAY(16);
190           }
191           if (i == 0) {
192                     bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
193                     bus_release_resource(dev, SYS_RES_IOPORT, 1, port1);
194                     return ENXIO;
195           }
196 #endif
197 
198           error = atkbdc_probe_unit(device_get_unit(dev), port0, port1);
199 
200           bus_release_resource(dev, SYS_RES_IOPORT, 0, port0);
201           bus_release_resource(dev, SYS_RES_IOPORT, 1, port1);
202 
203           return error;
204 }
205 
206 static void
atkbdc_add_device(device_t dev,const char * name,int unit)207 atkbdc_add_device(device_t dev, const char *name, int unit)
208 {
209           atkbdc_device_t     *kdev;
210           device_t  child;
211           int                 t;
212 
213           if (resource_int_value(name, unit, "disabled", &t) == 0 && t != 0)
214                     return;
215 
216           kdev = kmalloc(sizeof(struct atkbdc_device), M_ATKBDDEV,
217                               M_WAITOK | M_ZERO);
218 
219           if (resource_int_value(name, unit, "irq", &t) == 0)
220                     kdev->irq = t;
221           else
222                     kdev->irq = -1;
223 
224           if (resource_int_value(name, unit, "flags", &t) == 0)
225                     kdev->flags = t;
226           else
227                     kdev->flags = 0;
228 
229           child = device_add_child(dev, name, unit);
230           device_set_ivars(child, kdev);
231 }
232 
233 static int
atkbdc_attach(device_t dev)234 atkbdc_attach(device_t dev)
235 {
236           atkbdc_softc_t      *sc;
237           int                 unit;
238           int                 error;
239           int                 rid;
240           int                 i;
241 
242           lwkt_gettoken(&kbd_token);
243           unit = device_get_unit(dev);
244           sc = *(atkbdc_softc_t **)device_get_softc(dev);
245           if (sc == NULL) {
246                     /*
247                      * We have to maintain two copies of the kbdc_softc struct,
248                      * as the low-level console needs to have access to the
249                      * keyboard controller before kbdc is probed and attached.
250                      * kbdc_soft[] contains the default entry for that purpose.
251                      * See atkbdc.c. XXX
252                      */
253                     sc = atkbdc_get_softc(unit);
254                     if (sc == NULL) {
255                               lwkt_reltoken(&kbd_token);
256                               return ENOMEM;
257                     }
258           }
259 
260           rid = 0;
261           sc->port0 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
262                                                RF_ACTIVE);
263           if (sc->port0 == NULL) {
264                     lwkt_reltoken(&kbd_token);
265                     return ENXIO;
266           }
267           rid = 1;
268           sc->port1 = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
269                                                RF_ACTIVE);
270           if (sc->port1 == NULL) {
271                     bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0);
272                     lwkt_reltoken(&kbd_token);
273                     return ENXIO;
274           }
275 
276           error = atkbdc_attach_unit(unit, sc, sc->port0, sc->port1);
277           if (error) {
278                     bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port0);
279                     bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->port1);
280                     lwkt_reltoken(&kbd_token);
281                     return error;
282           }
283           *(atkbdc_softc_t **)device_get_softc(dev) = sc;
284 
285           /*
286            * Add all devices configured to be attached to atkbdc0.
287            */
288           for (i = resource_query_string(-1, "at", device_get_nameunit(dev));
289                i != -1;
290                i = resource_query_string(i, "at", device_get_nameunit(dev))) {
291                     atkbdc_add_device(dev, resource_query_name(i),
292                                           resource_query_unit(i));
293           }
294 
295           /*
296            * and atkbdc?
297            */
298           for (i = resource_query_string(-1, "at", device_get_name(dev));
299                i != -1;
300                i = resource_query_string(i, "at", device_get_name(dev))) {
301                     atkbdc_add_device(dev, resource_query_name(i),
302                                           resource_query_unit(i));
303           }
304 
305           bus_generic_attach(dev);
306 
307           lwkt_reltoken(&kbd_token);
308           return 0;
309 }
310 
311 static int
atkbdc_print_child(device_t bus,device_t dev)312 atkbdc_print_child(device_t bus, device_t dev)
313 {
314           atkbdc_device_t *kbdcdev;
315           int retval = 0;
316 
317           kbdcdev = (atkbdc_device_t *)device_get_ivars(dev);
318 
319           retval += bus_print_child_header(bus, dev);
320           if (kbdcdev->flags != 0)
321                     retval += kprintf(" flags 0x%x", kbdcdev->flags);
322           if (kbdcdev->irq != -1)
323                     retval += kprintf(" irq %d", kbdcdev->irq);
324           retval += bus_print_child_footer(bus, dev);
325 
326           return (retval);
327 }
328 
329 static int
atkbdc_read_ivar(device_t bus,device_t dev,int index,u_long * val)330 atkbdc_read_ivar(device_t bus, device_t dev, int index, u_long *val)
331 {
332           atkbdc_device_t *ivar;
333 
334           lwkt_gettoken(&kbd_token);
335           ivar = (atkbdc_device_t *)device_get_ivars(dev);
336           switch (index) {
337           case KBDC_IVAR_IRQ:
338                     *val = (u_long)ivar->irq;
339                     break;
340           case KBDC_IVAR_FLAGS:
341                     *val = (u_long)ivar->flags;
342                     break;
343           case KBDC_IVAR_VENDORID:
344                     *val = (u_long)ivar->vendorid;
345                     break;
346           case KBDC_IVAR_SERIAL:
347                     *val = (u_long)ivar->serial;
348                     break;
349           case KBDC_IVAR_LOGICALID:
350                     *val = (u_long)ivar->logicalid;
351                     break;
352           case KBDC_IVAR_COMPATID:
353                     *val = (u_long)ivar->compatid;
354                     break;
355           default:
356                     lwkt_reltoken(&kbd_token);
357                     return ENOENT;
358           }
359 
360           lwkt_reltoken(&kbd_token);
361           return 0;
362 }
363 
364 static int
atkbdc_write_ivar(device_t bus,device_t dev,int index,u_long val)365 atkbdc_write_ivar(device_t bus, device_t dev, int index, u_long val)
366 {
367           atkbdc_device_t *ivar;
368 
369           lwkt_gettoken(&kbd_token);
370           ivar = (atkbdc_device_t *)device_get_ivars(dev);
371           switch (index) {
372           case KBDC_IVAR_IRQ:
373                     ivar->irq = (int)val;
374                     break;
375           case KBDC_IVAR_FLAGS:
376                     ivar->flags = (int)val;
377                     break;
378           case KBDC_IVAR_VENDORID:
379                     ivar->vendorid = (u_int32_t)val;
380                     break;
381           case KBDC_IVAR_SERIAL:
382                     ivar->serial = (u_int32_t)val;
383                     break;
384           case KBDC_IVAR_LOGICALID:
385                     ivar->logicalid = (u_int32_t)val;
386                     break;
387           case KBDC_IVAR_COMPATID:
388                     ivar->compatid = (u_int32_t)val;
389                     break;
390           default:
391                     lwkt_reltoken(&kbd_token);
392                     return ENOENT;
393           }
394 
395           lwkt_reltoken(&kbd_token);
396           return 0;
397 }
398 
399 DRIVER_MODULE(atkbdc, isa, atkbdc_driver, atkbdc_devclass, NULL, NULL);
400 DRIVER_MODULE(atkbdc, acpi, atkbdc_driver, atkbdc_devclass, NULL, NULL);
401