1 /*- 2 * Copyright (c) 1997, 1998 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 * $Id: ppbconf.c,v 1.7 1998/09/13 18:26:26 nsouch Exp $ 27 * 28 */ 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 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 40 LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */ 41 42 /* 43 * Add a null driver so that the linker set always exists. 44 */ 45 46 static struct ppb_driver nulldriver = { 47 NULL, NULL, "null" 48 }; 49 DATA_SET(ppbdriver_set, nulldriver); 50 51 52 /* 53 * ppb_alloc_bus() 54 * 55 * Allocate area to store the ppbus description. 56 */ 57 struct ppb_data * 58 ppb_alloc_bus(void) 59 { 60 struct ppb_data *ppb; 61 static int ppbdata_initted = 0; /* done-init flag */ 62 63 ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data), 64 M_TEMP, M_NOWAIT); 65 66 /* 67 * Add the new parallel port bus to the list of existing ppbus. 68 */ 69 if (ppb) { 70 bzero(ppb, sizeof(struct ppb_data)); 71 72 if (!ppbdata_initted) { /* list not initialised */ 73 LIST_INIT(&ppbdata); 74 ppbdata_initted = 1; 75 } 76 LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain); 77 } else { 78 printf("ppb_alloc_bus: cannot malloc!\n"); 79 } 80 return(ppb); 81 } 82 83 static char *pnp_tokens[] = { 84 "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA", 85 "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL }; 86 87 static char *pnp_classes[] = { 88 "printer", "modem", "network device", 89 "hard disk", "PCMCIA", "multimedia device", 90 "floppy disk", "ports", "scanner", 91 "digital camera", "unknown device", NULL }; 92 93 /* 94 * search_token() 95 * 96 * Search the first occurence of a token within a string 97 * 98 * XXX should use strxxx() calls 99 */ 100 static char * 101 search_token(char *str, int slen, char *token) 102 { 103 char *p; 104 int tlen, i, j; 105 106 #define UNKNOWN_LENGTH -1 107 108 if (slen == UNKNOWN_LENGTH) 109 /* get string's length */ 110 for (slen = 0, p = str; *p != '\0'; p++) 111 slen ++; 112 113 /* get token's length */ 114 for (tlen = 0, p = token; *p != '\0'; p++) 115 tlen ++; 116 117 if (tlen == 0) 118 return (str); 119 120 for (i = 0; i <= slen-tlen; i++) { 121 for (j = 0; j < tlen; j++) 122 if (str[i+j] != token[j]) 123 break; 124 if (j == tlen) 125 return (&str[i]); 126 } 127 128 return (NULL); 129 } 130 131 /* 132 * ppb_pnp_detect() 133 * 134 * Returns the class id. of the peripherial, -1 otherwise 135 */ 136 static int 137 ppb_pnp_detect(struct ppb_data *ppb) 138 { 139 char *token, *q, *class = 0; 140 int i, len, error; 141 int class_id = -1; 142 char str[PPB_PnP_STRING_SIZE+1]; 143 struct ppb_device pnpdev; /* temporary device to perform I/O */ 144 145 /* initialize the pnpdev structure for future use */ 146 bzero(&pnpdev, sizeof(pnpdev)); 147 148 pnpdev.ppb = ppb; 149 150 if (bootverbose) 151 printf("ppb: <PnP> probing devices on ppbus %d...\n", 152 ppb->ppb_link->adapter_unit); 153 154 if (ppb_request_bus(&pnpdev, PPB_DONTWAIT)) { 155 if (bootverbose) 156 printf("ppb: <PnP> cannot allocate ppbus!\n"); 157 return (-1); 158 } 159 160 if ((error = ppb_1284_negociate(&pnpdev, NIBBLE_1284_REQUEST_ID))) { 161 if (bootverbose) 162 printf("ppb: <PnP> ppb_1284_negociate()=%d\n", error); 163 164 goto end_detect; 165 } 166 167 len = 0; 168 for (q=str; !(ppb_rstr(&pnpdev) & PERROR); q++) { 169 if ((error = nibble_1284_inbyte(&pnpdev, q))) { 170 if (bootverbose) { 171 *q = '\0'; 172 printf("ppb: <PnP> len=%d, %s\n", len, str); 173 printf("ppb: <PnP> nibble_1284_inbyte()=%d\n", 174 error); 175 } 176 goto end_detect; 177 } 178 179 if (len++ >= PPB_PnP_STRING_SIZE) { 180 printf("ppb: <PnP> not space left!\n"); 181 goto end_detect; 182 } 183 } 184 *q = '\0'; 185 186 nibble_1284_sync(&pnpdev); 187 188 if (bootverbose) { 189 printf("ppb: <PnP> %d characters: ", len); 190 for (i = 0; i < len; i++) 191 printf("0x%x ", str[i]); 192 printf("\n"); 193 } 194 195 /* replace ';' characters by '\0' */ 196 for (i = 0; i < len; i++) 197 str[i] = (str[i] == ';') ? '\0' : str[i]; 198 199 if ((token = search_token(str, len, "MFG")) != NULL) 200 printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit, 201 search_token(token, UNKNOWN_LENGTH, ":") + 1); 202 else 203 printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit); 204 205 if ((token = search_token(str, len, "MDL")) != NULL) 206 printf(" %s", 207 search_token(token, UNKNOWN_LENGTH, ":") + 1); 208 else 209 printf(" unknown"); 210 211 if ((token = search_token(str, len, "VER")) != NULL) 212 printf("/%s", 213 search_token(token, UNKNOWN_LENGTH, ":") + 1); 214 215 if ((token = search_token(str, len, "REV")) != NULL) 216 printf(".%s", 217 search_token(token, UNKNOWN_LENGTH, ":") + 1); 218 219 printf(">"); 220 221 if ((token = search_token(str, len, "CLS")) != NULL) { 222 class = search_token(token, UNKNOWN_LENGTH, ":") + 1; 223 printf(" %s", class); 224 } 225 226 if ((token = search_token(str, len, "CMD")) != NULL) 227 printf(" %s", 228 search_token(token, UNKNOWN_LENGTH, ":") + 1); 229 230 printf("\n"); 231 232 if (class) 233 /* identify class ident */ 234 for (i = 0; pnp_tokens[i] != NULL; i++) { 235 if (search_token(class, len, pnp_tokens[i]) != NULL) { 236 class_id = i; 237 goto end_detect; 238 } 239 } 240 241 class_id = PPB_PnP_UNKNOWN; 242 243 end_detect: 244 if ((error = ppb_1284_terminate(&pnpdev, VALID_STATE)) && bootverbose) 245 printf("ppb: ppb_1284_terminate()=%d\n", error); 246 247 ppb_release_bus(&pnpdev); 248 return (class_id); 249 } 250 251 /* 252 * ppb_attachdevs() 253 * 254 * Called by ppcattach(), this function probes the ppbus and 255 * attaches found devices. 256 */ 257 int 258 ppb_attachdevs(struct ppb_data *ppb) 259 { 260 int error; 261 struct ppb_device *dev; 262 struct ppb_driver **p_drvpp, *p_drvp; 263 264 LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */ 265 p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items; 266 267 /* XXX wait for ieee1284 good support */ 268 #if 0 269 /* detect PnP devices */ 270 ppb->class_id = ppb_pnp_detect(ppb); 271 #endif 272 273 /* 274 * Blindly try all probes here. Later we should look at 275 * the parallel-port PnP standard, and intelligently seek 276 * drivers based on configuration first. 277 */ 278 while ((p_drvp = *p_drvpp++) != NULL) { 279 if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) { 280 /* 281 * Add the device to the list of probed devices. 282 */ 283 LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 284 285 /* Call the device's attach routine */ 286 (void)p_drvp->attach(dev); 287 } 288 } 289 return (0); 290 } 291 292 /* 293 * ppb_next_bus() 294 * 295 * Return the next bus in ppbus queue 296 */ 297 struct ppb_data * 298 ppb_next_bus(struct ppb_data *ppb) 299 { 300 301 if (ppb == NULL) 302 return (ppbdata.lh_first); 303 304 return (ppb->ppb_chain.le_next); 305 } 306 307 /* 308 * ppb_lookup_bus() 309 * 310 * Get ppb_data structure pointer according to the base address of the ppbus 311 */ 312 struct ppb_data * 313 ppb_lookup_bus(int base_port) 314 { 315 struct ppb_data *ppb; 316 317 for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) 318 if (ppb->ppb_link->base == base_port) 319 break; 320 321 return (ppb); 322 } 323 324 /* 325 * ppb_lookup_link() 326 * 327 * Get ppb_data structure pointer according to the unit value 328 * of the corresponding link structure 329 */ 330 struct ppb_data * 331 ppb_lookup_link(int unit) 332 { 333 struct ppb_data *ppb; 334 335 for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) 336 if (ppb->ppb_link->adapter_unit == unit) 337 break; 338 339 return (ppb); 340 } 341 342 /* 343 * ppb_attach_device() 344 * 345 * Called by loadable kernel modules to add a device 346 */ 347 int 348 ppb_attach_device(struct ppb_device *dev) 349 { 350 struct ppb_data *ppb = dev->ppb; 351 352 /* add the device to the list of probed devices */ 353 LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 354 355 return (0); 356 } 357 358 /* 359 * ppb_remove_device() 360 * 361 * Called by loadable kernel modules to remove a device 362 */ 363 void 364 ppb_remove_device(struct ppb_device *dev) 365 { 366 367 /* remove the device from the list of probed devices */ 368 LIST_REMOVE(dev, chain); 369 370 return; 371 } 372 373 /* 374 * ppb_request_bus() 375 * 376 * Allocate the device to perform transfers. 377 * 378 * how : PPB_WAIT or PPB_DONTWAIT 379 */ 380 int 381 ppb_request_bus(struct ppb_device *dev, int how) 382 { 383 int s, error = 0; 384 struct ppb_data *ppb = dev->ppb; 385 386 while (!error) { 387 s = splhigh(); 388 if (ppb->ppb_owner) { 389 splx(s); 390 391 switch (how) { 392 case (PPB_WAIT | PPB_INTR): 393 error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0); 394 break; 395 396 case (PPB_WAIT | PPB_NOINTR): 397 error = tsleep(ppb, PPBPRI, "ppbreq", 0); 398 break; 399 400 default: 401 return (EWOULDBLOCK); 402 break; 403 } 404 405 } else { 406 ppb->ppb_owner = dev; 407 408 /* restore the context of the device 409 * The first time, ctx.valid is certainly false 410 * then do not change anything. This is usefull for 411 * drivers that do not set there operating mode 412 * during attachement 413 */ 414 if (dev->ctx.valid) 415 ppb_set_mode(dev, dev->ctx.mode); 416 417 splx(s); 418 return (0); 419 } 420 } 421 422 return (error); 423 } 424 425 /* 426 * ppb_release_bus() 427 * 428 * Release the device allocated with ppb_request_dev() 429 */ 430 int 431 ppb_release_bus(struct ppb_device *dev) 432 { 433 int s; 434 struct ppb_data *ppb = dev->ppb; 435 436 s = splhigh(); 437 if (ppb->ppb_owner != dev) { 438 splx(s); 439 return (EACCES); 440 } 441 442 ppb->ppb_owner = 0; 443 splx(s); 444 445 /* save the context of the device */ 446 dev->ctx.mode = ppb_get_mode(dev); 447 448 /* ok, now the context of the device is valid */ 449 dev->ctx.valid = 1; 450 451 /* wakeup waiting processes */ 452 wakeup(ppb); 453 454 return (0); 455 } 456