1/*- 2 * Copyright (c) 1997, 1998, 1999 Nicolas Souchu 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 *
| 1/*- 2 * Copyright (c) 1997, 1998, 1999 Nicolas Souchu 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 *
|
26 * $FreeBSD: head/sys/dev/ppbus/ppbconf.c 50477 1999-08-28 01:08:13Z peter $
| 26 * $FreeBSD: head/sys/dev/ppbus/ppbconf.c 55939 2000-01-14 00:18:06Z nsouch $
|
27 * 28 */
| 27 * 28 */
|
| 29#include "opt_ppb_1284.h" 30
|
29#include <sys/param.h> 30#include <sys/systm.h>
| 31#include <sys/param.h> 32#include <sys/systm.h>
|
31#include <sys/linker_set.h>
| 33#include <sys/kernel.h> 34#include <sys/module.h> 35#include <sys/bus.h>
|
32#include <sys/malloc.h> 33
| 36#include <sys/malloc.h> 37
|
34#include <vm/vm.h> 35#include <vm/pmap.h> 36
| |
37#include <dev/ppbus/ppbconf.h> 38#include <dev/ppbus/ppb_1284.h> 39
| 38#include <dev/ppbus/ppbconf.h> 39#include <dev/ppbus/ppb_1284.h> 40
|
40#include "opt_ppb_1284.h"
| 41#include "ppbus_if.h" 42 43#define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev)) 44 45MALLOC_DEFINE(M_PPBUSDEV, "ppbusdev", "Parallel Port bus device");
|
41
| 46
|
42static LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */
| 47static devclass_t ppbus_devclass;
|
43 44/*
| 48 49/*
|
45 * Add a null driver so that the linker set always exists.
| 50 * Device methods
|
46 */
| 51 */
|
| 52static int ppbus_probe(device_t); 53static int ppbus_attach(device_t); 54static void ppbus_print_child(device_t bus, device_t dev); 55static int ppbus_read_ivar(device_t, device_t, int, uintptr_t *); 56static int ppbus_write_ivar(device_t, device_t, int, u_long); 57static int ppbus_setup_intr(device_t, device_t, struct resource *, int, 58 void (*)(void *), void *, void **); 59static int ppbus_teardown_intr(device_t, device_t, struct resource *, void *);
|
47
| 60
|
48static struct ppb_driver nulldriver = { 49 NULL, NULL, "null"
| 61static device_method_t ppbus_methods[] = { 62 /* device interface */ 63 DEVMETHOD(device_probe, ppbus_probe), 64 DEVMETHOD(device_attach, ppbus_attach), 65 66 /* bus interface */ 67 DEVMETHOD(bus_print_child, ppbus_print_child), 68 DEVMETHOD(bus_read_ivar, ppbus_read_ivar), 69 DEVMETHOD(bus_write_ivar, ppbus_write_ivar), 70 DEVMETHOD(bus_setup_intr, ppbus_setup_intr), 71 DEVMETHOD(bus_teardown_intr, ppbus_teardown_intr), 72 DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 73 74 { 0, 0 }
|
50};
| 75};
|
51DATA_SET(ppbdriver_set, nulldriver);
| |
52
| 76
|
| 77static driver_t ppbus_driver = { 78 "ppbus", 79 ppbus_methods, 80 sizeof(struct ppb_data), 81 }; 82 83static void 84ppbus_print_child(device_t bus, device_t dev) 85{ 86 struct ppb_device *ppbdev;
|
53
| 87
|
| 88 bus_print_child_header(bus, dev); 89 90 ppbdev = (struct ppb_device *)device_get_ivars(dev); 91 92 if (ppbdev->flags != 0) 93 printf(" flags 0x%x", ppbdev->flags); 94 95 printf(" on %s%d\n", device_get_name(bus), device_get_unit(bus)); 96 97 return; 98} 99 100static int 101ppbus_probe(device_t dev) 102{ 103 device_set_desc(dev, "Parallel port bus"); 104 105 return (0); 106} 107
|
54/*
| 108/*
|
55 * ppb_alloc_bus()
| 109 * ppb_add_device()
|
56 *
| 110 *
|
57 * Allocate area to store the ppbus description.
| 111 * Add a ppbus device, allocate/initialize the ivars
|
58 */
| 112 */
|
59struct ppb_data * 60ppb_alloc_bus(void)
| 113static void 114ppbus_add_device(device_t dev, const char *name, int unit)
|
61{
| 115{
|
62 struct ppb_data *ppb; 63 static int ppbdata_initted = 0; /* done-init flag */
| 116 struct ppb_device *ppbdev; 117 device_t child; 118 119 /* allocate ivars for the new ppbus child */ 120 ppbdev = malloc(sizeof(struct ppb_device), M_PPBUSDEV, M_NOWAIT); 121 if (!ppbdev) 122 return; 123 bzero(ppbdev, sizeof *ppbdev);
|
64
| 124
|
65 ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data), 66 M_TEMP, M_NOWAIT);
| 125 /* initialize the ivars */ 126 ppbdev->name = name;
|
67
| 127
|
68 /* 69 * Add the new parallel port bus to the list of existing ppbus. 70 */ 71 if (ppb) { 72 bzero(ppb, sizeof(struct ppb_data));
| 128 /* add the device as a child to the ppbus bus with the allocated 129 * ivars */ 130 child = device_add_child(dev, name, unit); 131 device_set_ivars(child, ppbdev);
|
73
| 132
|
74 if (!ppbdata_initted) { /* list not initialised */ 75 LIST_INIT(&ppbdata); 76 ppbdata_initted = 1; 77 } 78 LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain); 79 } else { 80 printf("ppb_alloc_bus: cannot malloc!\n");
| 133 return; 134} 135 136static int 137ppbus_read_ivar(device_t bus, device_t dev, int index, uintptr_t* val) 138 { 139 struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); 140 141 switch (index) { 142 case PPBUS_IVAR_MODE: 143 /* XXX yet device mode = ppbus mode = chipset mode */ 144 *val = (u_long)ppb_get_mode(bus); 145 ppbdev->mode = (u_short)*val; 146 break; 147 case PPBUS_IVAR_AVM: 148 *val = (u_long)ppbdev->avm; 149 break; 150 case PPBUS_IVAR_IRQ: 151 BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_IRQ, val); 152 break; 153 default: 154 return (ENOENT);
|
81 }
| 155 }
|
82 return(ppb);
| 156 157 return (0);
|
83}
| 158}
|
| 159 160static int 161ppbus_write_ivar(device_t bus, device_t dev, int index, u_long val) 162{ 163 struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
|
84
| 164
|
| 165 switch (index) { 166 case PPBUS_IVAR_MODE: 167 /* XXX yet device mode = ppbus mode = chipset mode */ 168 ppb_set_mode(bus,val); 169 ppbdev->mode = ppb_get_mode(bus); 170 break; 171 default: 172 return (ENOENT); 173 } 174 175 return (0); 176 } 177
|
85#define PPB_PNP_PRINTER 0 86#define PPB_PNP_MODEM 1 87#define PPB_PNP_NET 2 88#define PPB_PNP_HDC 3 89#define PPB_PNP_PCMCIA 4 90#define PPB_PNP_MEDIA 5 91#define PPB_PNP_FDC 6 92#define PPB_PNP_PORTS 7 93#define PPB_PNP_SCANNER 8 94#define PPB_PNP_DIGICAM 9 95 96#ifndef DONTPROBE_1284 97 98static char *pnp_tokens[] = { 99 "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA", 100 "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL }; 101 102#if 0 103static char *pnp_classes[] = { 104 "printer", "modem", "network device", 105 "hard disk", "PCMCIA", "multimedia device", 106 "floppy disk", "ports", "scanner", 107 "digital camera", "unknown device", NULL }; 108#endif 109 110/* 111 * search_token() 112 * 113 * Search the first occurence of a token within a string 114 * 115 * XXX should use strxxx() calls 116 */ 117static char * 118search_token(char *str, int slen, char *token) 119{ 120 char *p; 121 int tlen, i, j; 122 123#define UNKNOWN_LENGTH -1 124 125 if (slen == UNKNOWN_LENGTH) 126 /* get string's length */ 127 for (slen = 0, p = str; *p != '\0'; p++) 128 slen ++; 129 130 /* get token's length */ 131 for (tlen = 0, p = token; *p != '\0'; p++) 132 tlen ++; 133 134 if (tlen == 0) 135 return (str); 136 137 for (i = 0; i <= slen-tlen; i++) { 138 for (j = 0; j < tlen; j++) 139 if (str[i+j] != token[j]) 140 break; 141 if (j == tlen) 142 return (&str[i]); 143 } 144 145 return (NULL); 146} 147 148/* 149 * ppb_pnp_detect() 150 * 151 * Returns the class id. of the peripherial, -1 otherwise 152 */ 153static int
| 178#define PPB_PNP_PRINTER 0 179#define PPB_PNP_MODEM 1 180#define PPB_PNP_NET 2 181#define PPB_PNP_HDC 3 182#define PPB_PNP_PCMCIA 4 183#define PPB_PNP_MEDIA 5 184#define PPB_PNP_FDC 6 185#define PPB_PNP_PORTS 7 186#define PPB_PNP_SCANNER 8 187#define PPB_PNP_DIGICAM 9 188 189#ifndef DONTPROBE_1284 190 191static char *pnp_tokens[] = { 192 "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA", 193 "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL }; 194 195#if 0 196static char *pnp_classes[] = { 197 "printer", "modem", "network device", 198 "hard disk", "PCMCIA", "multimedia device", 199 "floppy disk", "ports", "scanner", 200 "digital camera", "unknown device", NULL }; 201#endif 202 203/* 204 * search_token() 205 * 206 * Search the first occurence of a token within a string 207 * 208 * XXX should use strxxx() calls 209 */ 210static char * 211search_token(char *str, int slen, char *token) 212{ 213 char *p; 214 int tlen, i, j; 215 216#define UNKNOWN_LENGTH -1 217 218 if (slen == UNKNOWN_LENGTH) 219 /* get string's length */ 220 for (slen = 0, p = str; *p != '\0'; p++) 221 slen ++; 222 223 /* get token's length */ 224 for (tlen = 0, p = token; *p != '\0'; p++) 225 tlen ++; 226 227 if (tlen == 0) 228 return (str); 229 230 for (i = 0; i <= slen-tlen; i++) { 231 for (j = 0; j < tlen; j++) 232 if (str[i+j] != token[j]) 233 break; 234 if (j == tlen) 235 return (&str[i]); 236 } 237 238 return (NULL); 239} 240 241/* 242 * ppb_pnp_detect() 243 * 244 * Returns the class id. of the peripherial, -1 otherwise 245 */ 246static int
|
154ppb_pnp_detect(struct ppb_data *ppb, struct ppb_device *pnpdev)
| 247ppb_pnp_detect(device_t bus)
|
155{ 156 char *token, *class = 0; 157 int i, len, error; 158 int class_id = -1; 159 char str[PPB_PnP_STRING_SIZE+1];
| 248{ 249 char *token, *class = 0; 250 int i, len, error; 251 int class_id = -1; 252 char str[PPB_PnP_STRING_SIZE+1];
|
| 253 int unit = device_get_unit(bus);
|
160
| 254
|
161 printf("Probing for PnP devices on ppbus%d:\n", 162 ppb->ppb_link->adapter_unit);
| 255 printf("Probing for PnP devices on ppbus%d:\n", unit);
|
163
| 256
|
164 if ((error = ppb_1284_read_id(pnpdev, PPB_NIBBLE, str,
| 257 if ((error = ppb_1284_read_id(bus, PPB_NIBBLE, str,
|
165 PPB_PnP_STRING_SIZE, &len))) 166 goto end_detect; 167 168#ifdef DEBUG_1284 169 printf("ppb: <PnP> %d characters: ", len); 170 for (i = 0; i < len; i++) 171 printf("%c(0x%x) ", str[i], str[i]); 172 printf("\n"); 173#endif 174 175 /* replace ';' characters by '\0' */ 176 for (i = 0; i < len; i++) 177 str[i] = (str[i] == ';') ? '\0' : str[i]; 178 179 if ((token = search_token(str, len, "MFG")) != NULL || 180 (token = search_token(str, len, "MANUFACTURER")) != NULL)
| 258 PPB_PnP_STRING_SIZE, &len))) 259 goto end_detect; 260 261#ifdef DEBUG_1284 262 printf("ppb: <PnP> %d characters: ", len); 263 for (i = 0; i < len; i++) 264 printf("%c(0x%x) ", str[i], str[i]); 265 printf("\n"); 266#endif 267 268 /* replace ';' characters by '\0' */ 269 for (i = 0; i < len; i++) 270 str[i] = (str[i] == ';') ? '\0' : str[i]; 271 272 if ((token = search_token(str, len, "MFG")) != NULL || 273 (token = search_token(str, len, "MANUFACTURER")) != NULL)
|
181 printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit,
| 274 printf("ppbus%d: <%s", unit,
|
182 search_token(token, UNKNOWN_LENGTH, ":") + 1); 183 else
| 275 search_token(token, UNKNOWN_LENGTH, ":") + 1); 276 else
|
184 printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit);
| 277 printf("ppbus%d: |
185 186 if ((token = search_token(str, len, "MDL")) != NULL || 187 (token = search_token(str, len, "MODEL")) != NULL) 188 printf(" %s", 189 search_token(token, UNKNOWN_LENGTH, ":") + 1); 190 else 191 printf(" unknown"); 192 193 if ((token = search_token(str, len, "VER")) != NULL) 194 printf("/%s", 195 search_token(token, UNKNOWN_LENGTH, ":") + 1); 196 197 if ((token = search_token(str, len, "REV")) != NULL) 198 printf(".%s", 199 search_token(token, UNKNOWN_LENGTH, ":") + 1); 200 201 printf(">"); 202 203 if ((token = search_token(str, len, "CLS")) != NULL) { 204 class = search_token(token, UNKNOWN_LENGTH, ":") + 1; 205 printf(" %s", class); 206 } 207 208 if ((token = search_token(str, len, "CMD")) != NULL || 209 (token = search_token(str, len, "COMMAND")) != NULL) 210 printf(" %s", 211 search_token(token, UNKNOWN_LENGTH, ":") + 1); 212 213 printf("\n"); 214 215 if (class) 216 /* identify class ident */ 217 for (i = 0; pnp_tokens[i] != NULL; i++) { 218 if (search_token(class, len, pnp_tokens[i]) != NULL) { 219 class_id = i; 220 goto end_detect; 221 } 222 } 223 224 class_id = PPB_PnP_UNKNOWN; 225 226end_detect: 227 return (class_id); 228} 229 230/* 231 * ppb_scan_bus() 232 * 233 * Scan the ppbus for IEEE1284 compliant devices 234 */ 235static int
| 278 279 if ((token = search_token(str, len, "MDL")) != NULL || 280 (token = search_token(str, len, "MODEL")) != NULL) 281 printf(" %s", 282 search_token(token, UNKNOWN_LENGTH, ":") + 1); 283 else 284 printf(" unknown"); 285 286 if ((token = search_token(str, len, "VER")) != NULL) 287 printf("/%s", 288 search_token(token, UNKNOWN_LENGTH, ":") + 1); 289 290 if ((token = search_token(str, len, "REV")) != NULL) 291 printf(".%s", 292 search_token(token, UNKNOWN_LENGTH, ":") + 1); 293 294 printf(">"); 295 296 if ((token = search_token(str, len, "CLS")) != NULL) { 297 class = search_token(token, UNKNOWN_LENGTH, ":") + 1; 298 printf(" %s", class); 299 } 300 301 if ((token = search_token(str, len, "CMD")) != NULL || 302 (token = search_token(str, len, "COMMAND")) != NULL) 303 printf(" %s", 304 search_token(token, UNKNOWN_LENGTH, ":") + 1); 305 306 printf("\n"); 307 308 if (class) 309 /* identify class ident */ 310 for (i = 0; pnp_tokens[i] != NULL; i++) { 311 if (search_token(class, len, pnp_tokens[i]) != NULL) { 312 class_id = i; 313 goto end_detect; 314 } 315 } 316 317 class_id = PPB_PnP_UNKNOWN; 318 319end_detect: 320 return (class_id); 321} 322 323/* 324 * ppb_scan_bus() 325 * 326 * Scan the ppbus for IEEE1284 compliant devices 327 */ 328static int
|
236ppb_scan_bus(struct ppb_data *ppb)
| 329ppb_scan_bus(device_t bus)
|
237{
| 330{
|
238 struct ppb_device pnpdev; /* temporary device to perform I/O */
| 331 struct ppb_data * ppb = (struct ppb_data *)device_get_softc(bus);
|
239 int error = 0;
| 332 int error = 0;
|
| 333 int unit = device_get_unit(bus);
|
240
| 334
|
241 /* initialize the pnpdev structure for future use */ 242 bzero(&pnpdev, sizeof(pnpdev)); 243 pnpdev.ppb = ppb; 244 245 if ((error = ppb_request_bus(&pnpdev, PPB_DONTWAIT))) { 246 if (bootverbose) 247 printf("ppb: cannot allocate ppbus!\n"); 248 249 return (error); 250 } 251
| |
252 /* try all IEEE1284 modes, for one device only 253 * 254 * XXX We should implement the IEEE1284.3 standard to detect 255 * daisy chained devices 256 */ 257
| 335 /* try all IEEE1284 modes, for one device only 336 * 337 * XXX We should implement the IEEE1284.3 standard to detect 338 * daisy chained devices 339 */ 340
|
258 error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, PPB_REQUEST_ID);
| 341 error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID);
|
259 260 if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284)) 261 goto end_scan; 262
| 342 343 if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284)) 344 goto end_scan; 345
|
263 ppb_1284_terminate(&pnpdev);
| 346 ppb_1284_terminate(bus);
|
264
| 347
|
265 printf("ppb%d: IEEE1284 device found ", ppb->ppb_link->adapter_unit);
| 348 printf("ppbus%d: IEEE1284 device found ", unit);
|
266
| 349
|
267 if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, 0))) {
| 350 if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 0))) {
|
268 printf("/NIBBLE");
| 351 printf("/NIBBLE");
|
269 ppb_1284_terminate(&pnpdev);
| 352 ppb_1284_terminate(bus);
|
270 } 271
| 353 } 354
|
272 if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, 0))) {
| 355 if (!(error = ppb_1284_negociate(bus, PPB_PS2, 0))) {
|
273 printf("/PS2");
| 356 printf("/PS2");
|
274 ppb_1284_terminate(&pnpdev);
| 357 ppb_1284_terminate(bus);
|
275 } 276
| 358 } 359
|
277 if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, 0))) {
| 360 if (!(error = ppb_1284_negociate(bus, PPB_ECP, 0))) {
|
278 printf("/ECP");
| 361 printf("/ECP");
|
279 ppb_1284_terminate(&pnpdev);
| 362 ppb_1284_terminate(bus);
|
280 } 281
| 363 } 364
|
282 if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, PPB_USE_RLE))) {
| 365 if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_USE_RLE))) {
|
283 printf("/ECP_RLE");
| 366 printf("/ECP_RLE");
|
284 ppb_1284_terminate(&pnpdev);
| 367 ppb_1284_terminate(bus);
|
285 } 286
| 368 } 369
|
287 if (!(error = ppb_1284_negociate(&pnpdev, PPB_EPP, 0))) {
| 370 if (!(error = ppb_1284_negociate(bus, PPB_EPP, 0))) {
|
288 printf("/EPP");
| 371 printf("/EPP");
|
289 ppb_1284_terminate(&pnpdev);
| 372 ppb_1284_terminate(bus);
|
290 } 291 292 /* try more IEEE1284 modes */ 293 if (bootverbose) {
| 373 } 374 375 /* try more IEEE1284 modes */ 376 if (bootverbose) {
|
294 if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE,
| 377 if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE,
|
295 PPB_REQUEST_ID))) { 296 printf("/NIBBLE_ID");
| 378 PPB_REQUEST_ID))) { 379 printf("/NIBBLE_ID");
|
297 ppb_1284_terminate(&pnpdev);
| 380 ppb_1284_terminate(bus);
|
298 } 299
| 381 } 382
|
300 if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2,
| 383 if (!(error = ppb_1284_negociate(bus, PPB_PS2,
|
301 PPB_REQUEST_ID))) { 302 printf("/PS2_ID");
| 384 PPB_REQUEST_ID))) { 385 printf("/PS2_ID");
|
303 ppb_1284_terminate(&pnpdev);
| 386 ppb_1284_terminate(bus);
|
304 } 305
| 387 } 388
|
306 if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP,
| 389 if (!(error = ppb_1284_negociate(bus, PPB_ECP,
|
307 PPB_REQUEST_ID))) { 308 printf("/ECP_ID");
| 390 PPB_REQUEST_ID))) { 391 printf("/ECP_ID");
|
309 ppb_1284_terminate(&pnpdev);
| 392 ppb_1284_terminate(bus);
|
310 } 311
| 393 } 394
|
312 if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP,
| 395 if (!(error = ppb_1284_negociate(bus, PPB_ECP,
|
313 PPB_REQUEST_ID | PPB_USE_RLE))) { 314 printf("/ECP_RLE_ID");
| 396 PPB_REQUEST_ID | PPB_USE_RLE))) { 397 printf("/ECP_RLE_ID");
|
315 ppb_1284_terminate(&pnpdev);
| 398 ppb_1284_terminate(bus);
|
316 } 317
| 399 } 400
|
318 if (!(error = ppb_1284_negociate(&pnpdev, PPB_COMPATIBLE,
| 401 if (!(error = ppb_1284_negociate(bus, PPB_COMPATIBLE,
|
319 PPB_EXTENSIBILITY_LINK))) { 320 printf("/Extensibility Link");
| 402 PPB_EXTENSIBILITY_LINK))) { 403 printf("/Extensibility Link");
|
321 ppb_1284_terminate(&pnpdev);
| 404 ppb_1284_terminate(bus);
|
322 } 323 } 324 325 printf("\n"); 326 327 /* detect PnP devices */
| 405 } 406 } 407 408 printf("\n"); 409 410 /* detect PnP devices */
|
328 ppb->class_id = ppb_pnp_detect(ppb, &pnpdev);
| 411 ppb->class_id = ppb_pnp_detect(bus);
|
329
| 412
|
330 ppb_release_bus(&pnpdev); 331
| |
332 return (0); 333 334end_scan:
| 413 return (0); 414 415end_scan:
|
335 ppb_release_bus(&pnpdev);
| |
336 return (error); 337} 338 339#endif /* !DONTPROBE_1284 */ 340
| 416 return (error); 417} 418 419#endif /* !DONTPROBE_1284 */ 420
|
341/* 342 * ppb_attachdevs() 343 * 344 * Called by ppcattach(), this function probes the ppbus and 345 * attaches found devices. 346 */ 347int 348ppb_attachdevs(struct ppb_data *ppb)
| 421static int 422ppbus_attach(device_t dev)
|
349{
| 423{
|
350 struct ppb_device *dev; 351 struct ppb_driver **p_drvpp, *p_drvp;
| 424 int i; 425 int unit, disabled; 426 char *name;
|
352
| 427
|
353 LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */ 354 p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items; 355 356#ifndef DONTPROBE_1284 357 /* detect IEEE1284 compliant devices */ 358 ppb_scan_bus(ppb); 359#endif /* !DONTPROBE_1284 */ 360
| |
361 /*
| 428 /*
|
362 * Blindly try all probes here. Later we should look at 363 * the parallel-port PnP standard, and intelligently seek 364 * drivers based on configuration first.
| 429 * Add all devices configured to be attached to ppbus0.
|
365 */
| 430 */
|
366 while ((p_drvp = *p_drvpp++) != NULL) { 367 if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) { 368 /* 369 * Add the device to the list of probed devices. 370 */ 371 LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 372 373 /* Call the device's attach routine */ 374 (void)p_drvp->attach(dev); 375 }
| 431 for (i = resource_query_string(-1, "at", "ppbus0"); 432 i != -1; 433 i = resource_query_string(i, "at", "ppbus0")) { 434 unit = resource_query_unit(i); 435 name = resource_query_name(i); 436 if (resource_int_value(name, unit, "disabled", &disabled) == 0) { 437 if (disabled) 438 continue; 439 } 440 ppbus_add_device(dev, name, unit);
|
376 }
| 441 }
|
377 return (0); 378}
| |
379
| 442
|
380/* 381 * ppb_next_bus() 382 * 383 * Return the next bus in ppbus queue 384 */ 385struct ppb_data * 386ppb_next_bus(struct ppb_data *ppb) 387{
| 443 /* 444 * and ppbus? 445 */ 446 for (i = resource_query_string(-1, "at", "ppbus"); 447 i != -1; 448 i = resource_query_string(i, "at", "ppbus")) { 449 unit = resource_query_unit(i); 450 name = resource_query_name(i); 451 if (resource_int_value(name, unit, "disabled", &disabled) == 0) { 452 if (disabled) 453 continue; 454 } 455 ppbus_add_device(dev, name, unit); 456 }
|
388
| 457
|
389 if (ppb == NULL) 390 return (ppbdata.lh_first);
| 458#ifndef DONTPROBE_1284 459 /* detect IEEE1284 compliant devices */ 460 ppb_scan_bus(dev); 461#endif /* !DONTPROBE_1284 */
|
391
| 462
|
392 return (ppb->ppb_chain.le_next); 393}
| 463 /* launch attachement of the added children */ 464 bus_generic_attach(dev);
|
394
| 465
|
395/* 396 * ppb_lookup_bus() 397 * 398 * Get ppb_data structure pointer according to the base address of the ppbus 399 */ 400struct ppb_data * 401ppb_lookup_bus(int base_port) 402{ 403 struct ppb_data *ppb; 404 405 for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) 406 if (ppb->ppb_link->base == base_port) 407 break; 408 409 return (ppb);
| 466 return 0;
|
410} 411
| 467} 468
|
412/* 413 * ppb_lookup_link() 414 * 415 * Get ppb_data structure pointer according to the unit value 416 * of the corresponding link structure 417 */ 418struct ppb_data * 419ppb_lookup_link(int unit)
| 469static int 470ppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags, 471 void (*ihand)(void *), void *arg, void **cookiep)
|
420{
| 472{
|
421 struct ppb_data *ppb;
| 473 int error; 474 struct ppb_data *ppb = DEVTOSOFTC(bus); 475 struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child);
|
422
| 476
|
423 for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) 424 if (ppb->ppb_link->adapter_unit == unit) 425 break;
| 477 /* a device driver must own the bus to register an interrupt */ 478 if (ppb->ppb_owner != child) 479 return (EINVAL);
|
426
| 480
|
427 return (ppb); 428}
| 481 if ((error = BUS_SETUP_INTR(device_get_parent(bus), child, r, flags, 482 ihand, arg, cookiep))) 483 return (error);
|
429
| 484
|
430/* 431 * ppb_attach_device() 432 * 433 * Called by loadable kernel modules to add a device 434 */ 435int 436ppb_attach_device(struct ppb_device *dev) 437{ 438 struct ppb_data *ppb = dev->ppb;
| 485 /* store the resource and the cookie for eventually forcing 486 * handler unregistration 487 */ 488 ppbdev->intr_cookie = *cookiep; 489 ppbdev->intr_resource = r;
|
439
| 490
|
440 /* add the device to the list of probed devices */ 441 LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 442
| |
443 return (0); 444} 445
| 491 return (0); 492} 493
|
446/* 447 * ppb_remove_device() 448 * 449 * Called by loadable kernel modules to remove a device 450 */ 451void 452ppb_remove_device(struct ppb_device *dev)
| 494static int 495ppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih)
|
453{
| 496{
|
| 497 struct ppb_data *ppb = DEVTOSOFTC(bus); 498 struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child); 499 500 /* a device driver must own the bus to unregister an interrupt */ 501 if ((ppb->ppb_owner != child) || (ppbdev->intr_cookie != ih) || 502 (ppbdev->intr_resource != r)) 503 return (EINVAL);
|
454
| 504
|
455 /* remove the device from the list of probed devices */ 456 LIST_REMOVE(dev, chain);
| 505 ppbdev->intr_cookie = 0; 506 ppbdev->intr_resource = 0;
|
457
| 507
|
458 return;
| 508 /* pass unregistration to the upper layer */ 509 return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, ih));
|
459} 460 461/* 462 * ppb_request_bus() 463 * 464 * Allocate the device to perform transfers. 465 * 466 * how : PPB_WAIT or PPB_DONTWAIT 467 */ 468int
| 510} 511 512/* 513 * ppb_request_bus() 514 * 515 * Allocate the device to perform transfers. 516 * 517 * how : PPB_WAIT or PPB_DONTWAIT 518 */ 519int
|
469ppb_request_bus(struct ppb_device *dev, int how)
| 520ppb_request_bus(device_t bus, device_t dev, int how)
|
470{ 471 int s, error = 0;
| 521{ 522 int s, error = 0;
|
472 struct ppb_data *ppb = dev->ppb;
| 523 struct ppb_data *ppb = DEVTOSOFTC(bus); 524 struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
|
473 474 while (!error) { 475 s = splhigh(); 476 if (ppb->ppb_owner) { 477 splx(s); 478 479 switch (how) { 480 case (PPB_WAIT | PPB_INTR): 481 error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0); 482 break; 483 484 case (PPB_WAIT | PPB_NOINTR): 485 error = tsleep(ppb, PPBPRI, "ppbreq", 0); 486 break; 487 488 default: 489 return (EWOULDBLOCK); 490 break; 491 } 492 493 } else { 494 ppb->ppb_owner = dev; 495 496 /* restore the context of the device 497 * The first time, ctx.valid is certainly false 498 * then do not change anything. This is usefull for 499 * drivers that do not set there operating mode 500 * during attachement 501 */
| 525 526 while (!error) { 527 s = splhigh(); 528 if (ppb->ppb_owner) { 529 splx(s); 530 531 switch (how) { 532 case (PPB_WAIT | PPB_INTR): 533 error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0); 534 break; 535 536 case (PPB_WAIT | PPB_NOINTR): 537 error = tsleep(ppb, PPBPRI, "ppbreq", 0); 538 break; 539 540 default: 541 return (EWOULDBLOCK); 542 break; 543 } 544 545 } else { 546 ppb->ppb_owner = dev; 547 548 /* restore the context of the device 549 * The first time, ctx.valid is certainly false 550 * then do not change anything. This is usefull for 551 * drivers that do not set there operating mode 552 * during attachement 553 */
|
502 if (dev->ctx.valid) 503 ppb_set_mode(dev, dev->ctx.mode);
| 554 if (ppbdev->ctx.valid) 555 ppb_set_mode(bus, ppbdev->ctx.mode);
|
504 505 splx(s); 506 return (0); 507 } 508 } 509 510 return (error); 511} 512 513/* 514 * ppb_release_bus() 515 * 516 * Release the device allocated with ppb_request_dev() 517 */ 518int
| 556 557 splx(s); 558 return (0); 559 } 560 } 561 562 return (error); 563} 564 565/* 566 * ppb_release_bus() 567 * 568 * Release the device allocated with ppb_request_dev() 569 */ 570int
|
519ppb_release_bus(struct ppb_device *dev)
| 571ppb_release_bus(device_t bus, device_t dev)
|
520{
| 572{
|
521 int s; 522 struct ppb_data *ppb = dev->ppb;
| 573 int s, error; 574 struct ppb_data *ppb = DEVTOSOFTC(bus); 575 struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
|
523
| 576
|
| 577 if (ppbdev->intr_resource != 0) 578 /* force interrupt handler unregistration when the ppbus is released */ 579 if ((error = BUS_TEARDOWN_INTR(bus, dev, ppbdev->intr_resource, 580 ppbdev->intr_cookie))) 581 return (error); 582
|
524 s = splhigh(); 525 if (ppb->ppb_owner != dev) { 526 splx(s); 527 return (EACCES); 528 } 529 530 ppb->ppb_owner = 0; 531 splx(s); 532 533 /* save the context of the device */
| 583 s = splhigh(); 584 if (ppb->ppb_owner != dev) { 585 splx(s); 586 return (EACCES); 587 } 588 589 ppb->ppb_owner = 0; 590 splx(s); 591 592 /* save the context of the device */
|
534 dev->ctx.mode = ppb_get_mode(dev);
| 593 ppbdev->ctx.mode = ppb_get_mode(bus);
|
535 536 /* ok, now the context of the device is valid */
| 594 595 /* ok, now the context of the device is valid */
|
537 dev->ctx.valid = 1;
| 596 ppbdev->ctx.valid = 1;
|
538 539 /* wakeup waiting processes */ 540 wakeup(ppb); 541 542 return (0); 543}
| 597 598 /* wakeup waiting processes */ 599 wakeup(ppb); 600 601 return (0); 602}
|
| 603 604DRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0);
|
| |