xref: /freebsd/sys/dev/ppbus/ppbconf.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
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  *	$Id: ppbconf.c,v 1.13 1999/01/14 06:22:02 jdp Exp $
27  *
28  */
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/linker_set.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 #include "opt_ppb_1284.h"
41 
42 static LIST_HEAD(, ppb_data)	ppbdata;	/* list of existing ppbus */
43 
44 /*
45  * Add a null driver so that the linker set always exists.
46  */
47 
48 static struct ppb_driver nulldriver = {
49     NULL, NULL, "null"
50 };
51 DATA_SET(ppbdriver_set, nulldriver);
52 
53 
54 /*
55  * ppb_alloc_bus()
56  *
57  * Allocate area to store the ppbus description.
58  */
59 struct ppb_data *
60 ppb_alloc_bus(void)
61 {
62 	struct ppb_data *ppb;
63 	static int ppbdata_initted = 0;		/* done-init flag */
64 
65 	ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data),
66 		M_TEMP, M_NOWAIT);
67 
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));
73 
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");
81 	}
82 	return(ppb);
83 }
84 
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 
98 static char *pnp_tokens[] = {
99 	"PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
100 	"FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
101 
102 #if 0
103 static 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  */
117 static char *
118 search_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  */
153 static int
154 ppb_pnp_detect(struct ppb_data *ppb, struct ppb_device *pnpdev)
155 {
156 	char *token, *class = 0;
157 	int i, len, error;
158 	int class_id = -1;
159 	char str[PPB_PnP_STRING_SIZE+1];
160 
161 	printf("Probing for PnP devices on ppbus%d:\n",
162 			ppb->ppb_link->adapter_unit);
163 
164 	if ((error = ppb_1284_read_id(pnpdev, 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)
181 		printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit,
182 			search_token(token, UNKNOWN_LENGTH, ":") + 1);
183 	else
184 		printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit);
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 
226 end_detect:
227 	return (class_id);
228 }
229 
230 /*
231  * ppb_scan_bus()
232  *
233  * Scan the ppbus for IEEE1284 compliant devices
234  */
235 static int
236 ppb_scan_bus(struct ppb_data *ppb)
237 {
238 	struct ppb_device pnpdev;	/* temporary device to perform I/O */
239 	int error = 0;
240 
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 
258 	error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, PPB_REQUEST_ID);
259 
260 	if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284))
261 		goto end_scan;
262 
263 	ppb_1284_terminate(&pnpdev);
264 
265 	printf("ppb%d: IEEE1284 device found ", ppb->ppb_link->adapter_unit);
266 
267 	if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, 0))) {
268 		printf("/NIBBLE");
269 		ppb_1284_terminate(&pnpdev);
270 	}
271 
272 	if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, 0))) {
273 		printf("/PS2");
274 		ppb_1284_terminate(&pnpdev);
275 	}
276 
277 	if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, 0))) {
278 		printf("/ECP");
279 		ppb_1284_terminate(&pnpdev);
280 	}
281 
282 	if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, PPB_USE_RLE))) {
283 		printf("/ECP_RLE");
284 		ppb_1284_terminate(&pnpdev);
285 	}
286 
287 	if (!(error = ppb_1284_negociate(&pnpdev, PPB_EPP, 0))) {
288 		printf("/EPP");
289 		ppb_1284_terminate(&pnpdev);
290 	}
291 
292 	/* try more IEEE1284 modes */
293 	if (bootverbose) {
294 		if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE,
295 				PPB_REQUEST_ID))) {
296 			printf("/NIBBLE_ID");
297 			ppb_1284_terminate(&pnpdev);
298 		}
299 
300 		if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2,
301 				PPB_REQUEST_ID))) {
302 			printf("/PS2_ID");
303 			ppb_1284_terminate(&pnpdev);
304 		}
305 
306 		if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP,
307 				PPB_REQUEST_ID))) {
308 			printf("/ECP_ID");
309 			ppb_1284_terminate(&pnpdev);
310 		}
311 
312 		if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP,
313 				PPB_REQUEST_ID | PPB_USE_RLE))) {
314 			printf("/ECP_RLE_ID");
315 			ppb_1284_terminate(&pnpdev);
316 		}
317 
318 		if (!(error = ppb_1284_negociate(&pnpdev, PPB_COMPATIBLE,
319 				PPB_EXTENSIBILITY_LINK))) {
320 			printf("/Extensibility Link");
321 			ppb_1284_terminate(&pnpdev);
322 		}
323 	}
324 
325 	printf("\n");
326 
327 	/* detect PnP devices */
328 	ppb->class_id = ppb_pnp_detect(ppb, &pnpdev);
329 
330 	ppb_release_bus(&pnpdev);
331 
332 	return (0);
333 
334 end_scan:
335 	ppb_release_bus(&pnpdev);
336 	return (error);
337 }
338 
339 #endif /* !DONTPROBE_1284 */
340 
341 /*
342  * ppb_attachdevs()
343  *
344  * Called by ppcattach(), this function probes the ppbus and
345  * attaches found devices.
346  */
347 int
348 ppb_attachdevs(struct ppb_data *ppb)
349 {
350 	struct ppb_device *dev;
351 	struct ppb_driver **p_drvpp, *p_drvp;
352 
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 	/*
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.
365 	 */
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 	    }
376 	}
377 	return (0);
378 }
379 
380 /*
381  * ppb_next_bus()
382  *
383  * Return the next bus in ppbus queue
384  */
385 struct ppb_data *
386 ppb_next_bus(struct ppb_data *ppb)
387 {
388 
389 	if (ppb == NULL)
390 		return (ppbdata.lh_first);
391 
392 	return (ppb->ppb_chain.le_next);
393 }
394 
395 /*
396  * ppb_lookup_bus()
397  *
398  * Get ppb_data structure pointer according to the base address of the ppbus
399  */
400 struct ppb_data *
401 ppb_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);
410 }
411 
412 /*
413  * ppb_lookup_link()
414  *
415  * Get ppb_data structure pointer according to the unit value
416  * of the corresponding link structure
417  */
418 struct ppb_data *
419 ppb_lookup_link(int unit)
420 {
421 	struct ppb_data *ppb;
422 
423 	for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
424 		if (ppb->ppb_link->adapter_unit == unit)
425 			break;
426 
427 	return (ppb);
428 }
429 
430 /*
431  * ppb_attach_device()
432  *
433  * Called by loadable kernel modules to add a device
434  */
435 int
436 ppb_attach_device(struct ppb_device *dev)
437 {
438 	struct ppb_data *ppb = dev->ppb;
439 
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 
446 /*
447  * ppb_remove_device()
448  *
449  * Called by loadable kernel modules to remove a device
450  */
451 void
452 ppb_remove_device(struct ppb_device *dev)
453 {
454 
455 	/* remove the device from the list of probed devices */
456 	LIST_REMOVE(dev, chain);
457 
458 	return;
459 }
460 
461 /*
462  * ppb_request_bus()
463  *
464  * Allocate the device to perform transfers.
465  *
466  * how	: PPB_WAIT or PPB_DONTWAIT
467  */
468 int
469 ppb_request_bus(struct ppb_device *dev, int how)
470 {
471 	int s, error = 0;
472 	struct ppb_data *ppb = dev->ppb;
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 			 */
502 			if (dev->ctx.valid)
503 				ppb_set_mode(dev, dev->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  */
518 int
519 ppb_release_bus(struct ppb_device *dev)
520 {
521 	int s;
522 	struct ppb_data *ppb = dev->ppb;
523 
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 */
534 	dev->ctx.mode = ppb_get_mode(dev);
535 
536 	/* ok, now the context of the device is valid */
537 	dev->ctx.valid = 1;
538 
539 	/* wakeup waiting processes */
540 	wakeup(ppb);
541 
542 	return (0);
543 }
544