ppbconf.c revision 42475
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.9 1998/12/07 21:58:16 archie 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#include "opt_ppb_1284.h"
41
42LIST_HEAD(, ppb_data)	ppbdata;	/* list of existing ppbus */
43
44/*
45 * Add a null driver so that the linker set always exists.
46 */
47
48static struct ppb_driver nulldriver = {
49    NULL, NULL, "null"
50};
51DATA_SET(ppbdriver_set, nulldriver);
52
53
54/*
55 * ppb_alloc_bus()
56 *
57 * Allocate area to store the ppbus description.
58 */
59struct ppb_data *
60ppb_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
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
154ppb_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
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
236ppb_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("ppc%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#if 0
293	if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, PPB_REQUEST_ID))) {
294		printf("/NIBBLE_ID");
295		ppb_1284_terminate(&pnpdev);
296	}
297
298	if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, PPB_REQUEST_ID))) {
299		printf("/PS2_ID");
300		ppb_1284_terminate(&pnpdev);
301	}
302
303	if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, PPB_REQUEST_ID))) {
304		printf("/ECP_ID");
305		ppb_1284_terminate(&pnpdev);
306	}
307
308	if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP,
309					PPB_REQUEST_ID | PPB_USE_RLE))) {
310		printf("/ECP_RLE_ID");
311		ppb_1284_terminate(&pnpdev);
312	}
313#endif
314
315	if (!(error = ppb_1284_negociate(&pnpdev, PPB_COMPATIBLE,
316				PPB_EXTENSIBILITY_LINK))) {
317                printf("/Extensibility Link");
318		ppb_1284_terminate(&pnpdev);
319        }
320
321	printf(" in FORWARD_IDLE state\n");
322
323	/* detect PnP devices */
324	ppb->class_id = ppb_pnp_detect(ppb, &pnpdev);
325
326	ppb_release_bus(&pnpdev);
327
328	return (0);
329
330end_scan:
331	ppb_release_bus(&pnpdev);
332	return (error);
333}
334
335#endif /* !DONTPROBE_1284 */
336
337/*
338 * ppb_attachdevs()
339 *
340 * Called by ppcattach(), this function probes the ppbus and
341 * attaches found devices.
342 */
343int
344ppb_attachdevs(struct ppb_data *ppb)
345{
346	struct ppb_device *dev;
347	struct ppb_driver **p_drvpp, *p_drvp;
348
349	LIST_INIT(&ppb->ppb_devs);	/* initialise device/driver list */
350	p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items;
351
352#ifndef DONTPROBE_1284
353	/* detect IEEE1284 compliant devices */
354	ppb_scan_bus(ppb);
355#endif /* !DONTPROBE_1284 */
356
357	/*
358	 * Blindly try all probes here.  Later we should look at
359	 * the parallel-port PnP standard, and intelligently seek
360	 * drivers based on configuration first.
361	 */
362	while ((p_drvp = *p_drvpp++) != NULL) {
363	    if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) {
364		/*
365		 * Add the device to the list of probed devices.
366		 */
367		LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
368
369		/* Call the device's attach routine */
370		(void)p_drvp->attach(dev);
371	    }
372	}
373	return (0);
374}
375
376/*
377 * ppb_next_bus()
378 *
379 * Return the next bus in ppbus queue
380 */
381struct ppb_data *
382ppb_next_bus(struct ppb_data *ppb)
383{
384
385	if (ppb == NULL)
386		return (ppbdata.lh_first);
387
388	return (ppb->ppb_chain.le_next);
389}
390
391/*
392 * ppb_lookup_bus()
393 *
394 * Get ppb_data structure pointer according to the base address of the ppbus
395 */
396struct ppb_data *
397ppb_lookup_bus(int base_port)
398{
399	struct ppb_data *ppb;
400
401	for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
402		if (ppb->ppb_link->base == base_port)
403			break;
404
405	return (ppb);
406}
407
408/*
409 * ppb_lookup_link()
410 *
411 * Get ppb_data structure pointer according to the unit value
412 * of the corresponding link structure
413 */
414struct ppb_data *
415ppb_lookup_link(int unit)
416{
417	struct ppb_data *ppb;
418
419	for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
420		if (ppb->ppb_link->adapter_unit == unit)
421			break;
422
423	return (ppb);
424}
425
426/*
427 * ppb_attach_device()
428 *
429 * Called by loadable kernel modules to add a device
430 */
431int
432ppb_attach_device(struct ppb_device *dev)
433{
434	struct ppb_data *ppb = dev->ppb;
435
436	/* add the device to the list of probed devices */
437	LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
438
439	return (0);
440}
441
442/*
443 * ppb_remove_device()
444 *
445 * Called by loadable kernel modules to remove a device
446 */
447void
448ppb_remove_device(struct ppb_device *dev)
449{
450
451	/* remove the device from the list of probed devices */
452	LIST_REMOVE(dev, chain);
453
454	return;
455}
456
457/*
458 * ppb_request_bus()
459 *
460 * Allocate the device to perform transfers.
461 *
462 * how	: PPB_WAIT or PPB_DONTWAIT
463 */
464int
465ppb_request_bus(struct ppb_device *dev, int how)
466{
467	int s, error = 0;
468	struct ppb_data *ppb = dev->ppb;
469
470	while (!error) {
471		s = splhigh();
472		if (ppb->ppb_owner) {
473			splx(s);
474
475			switch (how) {
476			case (PPB_WAIT | PPB_INTR):
477				error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
478				break;
479
480			case (PPB_WAIT | PPB_NOINTR):
481				error = tsleep(ppb, PPBPRI, "ppbreq", 0);
482				break;
483
484			default:
485				return (EWOULDBLOCK);
486				break;
487			}
488
489		} else {
490			ppb->ppb_owner = dev;
491
492			/* restore the context of the device
493			 * The first time, ctx.valid is certainly false
494			 * then do not change anything. This is usefull for
495			 * drivers that do not set there operating mode
496			 * during attachement
497			 */
498			if (dev->ctx.valid)
499				ppb_set_mode(dev, dev->ctx.mode);
500
501			splx(s);
502			return (0);
503		}
504	}
505
506	return (error);
507}
508
509/*
510 * ppb_release_bus()
511 *
512 * Release the device allocated with ppb_request_dev()
513 */
514int
515ppb_release_bus(struct ppb_device *dev)
516{
517	int s;
518	struct ppb_data *ppb = dev->ppb;
519
520	s = splhigh();
521	if (ppb->ppb_owner != dev) {
522		splx(s);
523		return (EACCES);
524	}
525
526	ppb->ppb_owner = 0;
527	splx(s);
528
529	/* save the context of the device */
530	dev->ctx.mode = ppb_get_mode(dev);
531
532	/* ok, now the context of the device is valid */
533	dev->ctx.valid = 1;
534
535	/* wakeup waiting processes */
536	wakeup(ppb);
537
538	return (0);
539}
540