ppbconf.c revision 28863
1138627Stakawata/*-
2138627Stakawata * Copyright (c) 1997 Nicolas Souchu
3138627Stakawata * All rights reserved.
4138627Stakawata *
5138627Stakawata * Redistribution and use in source and binary forms, with or without
6138627Stakawata * modification, are permitted provided that the following conditions
7138627Stakawata * are met:
8138627Stakawata * 1. Redistributions of source code must retain the above copyright
9138627Stakawata *    notice, this list of conditions and the following disclaimer.
10138627Stakawata * 2. Redistributions in binary form must reproduce the above copyright
11138627Stakawata *    notice, this list of conditions and the following disclaimer in the
12138627Stakawata *    documentation and/or other materials provided with the distribution.
13138627Stakawata *
14138627Stakawata * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15138627Stakawata * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16138627Stakawata * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17138627Stakawata * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18138627Stakawata * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19138627Stakawata * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20138627Stakawata * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21138627Stakawata * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22138627Stakawata * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23138627Stakawata * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24138627Stakawata * SUCH DAMAGE.
25138627Stakawata *
26138627Stakawata *	$Id: ppbconf.c,v 1.2 1997/08/16 14:05:35 msmith Exp $
27138627Stakawata *
28138627Stakawata */
29138627Stakawata#include <sys/param.h>
30138627Stakawata#include <sys/systm.h>
31138627Stakawata#include <sys/errno.h>
32138627Stakawata#include <sys/conf.h>
33138627Stakawata#include <sys/proc.h>
34138627Stakawata#include <sys/buf.h>
35138627Stakawata#include <sys/kernel.h>
36138627Stakawata#include <sys/malloc.h>
37138627Stakawata#include <sys/uio.h>
38138627Stakawata#include <sys/syslog.h>
39138627Stakawata
40138627Stakawata#include <machine/clock.h>
41138774Sscottl
42138774Sscottl#include <vm/vm.h>
43138774Sscottl#include <vm/vm_param.h>
44138627Stakawata#include <vm/pmap.h>
45138627Stakawata
46138627Stakawata#include <dev/ppbus/ppbconf.h>
47138627Stakawata#include <dev/ppbus/ppb_1284.h>
48138627Stakawata
49138627StakawataLIST_HEAD(, ppb_data)	ppbdata;	/* list of existing ppbus */
50138627Stakawata
51138627Stakawata/*
52138627Stakawata * Add a null driver so that the linker set always exists.
53138627Stakawata */
54138627Stakawata
55138627Stakawatastatic struct ppb_driver nulldriver = {
56138627Stakawata    NULL, NULL, "null"
57138627Stakawata};
58138627StakawataDATA_SET(ppbdriver_set, nulldriver);
59138627Stakawata
60138627Stakawata
61138627Stakawata/*
62138627Stakawata * ppb_alloc_bus()
63138627Stakawata *
64138627Stakawata * Allocate area to store the ppbus description.
65138627Stakawata * This function is called by ppcattach().
66138627Stakawata */
67138627Stakawatastruct ppb_data *
68138627Stakawatappb_alloc_bus(void)
69138627Stakawata{
70138627Stakawata	struct ppb_data *ppb;
71138627Stakawata	static int ppbdata_initted = 0;		/* done-init flag */
72138627Stakawata
73138627Stakawata	ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data),
74138627Stakawata		M_TEMP, M_NOWAIT);
75138627Stakawata
76138627Stakawata	/*
77138627Stakawata	 * Add the new parallel port bus to the list of existing ppbus.
78138627Stakawata	 */
79138627Stakawata	if (ppb) {
80138627Stakawata		bzero(ppb, sizeof(struct ppb_data));
81138627Stakawata
82138627Stakawata		if (!ppbdata_initted) {		/* list not initialised */
83138627Stakawata		    LIST_INIT(&ppbdata);
84138627Stakawata		    ppbdata_initted = 1;
85138627Stakawata		}
86138627Stakawata		LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain);
87138627Stakawata	} else {
88138627Stakawata		printf("ppb_alloc_bus: cannot malloc!\n");
89138627Stakawata	}
90138627Stakawata	return(ppb);
91138627Stakawata}
92138627Stakawata
93138627Stakawatastatic char *pnp_tokens[] = {
94138627Stakawata	"PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
95138627Stakawata	"FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
96138627Stakawata
97138627Stakawatastatic char *pnp_classes[] = {
98138627Stakawata	"printer", "modem", "network device",
99138627Stakawata	"hard disk", "PCMCIA", "multimedia device",
100138627Stakawata	"floppy disk", "ports", "scanner",
101138627Stakawata	"digital camera", "unknown device", NULL };
102138627Stakawata
103138627Stakawata/*
104138627Stakawata * search_token()
105138627Stakawata *
106138627Stakawata * Search the first occurence of a token within a string
107138627Stakawata */
108138627Stakawatastatic char *
109138627Stakawatasearch_token(char *str, int slen, char *token)
110138627Stakawata{
111138627Stakawata	char *p;
112138627Stakawata	int tlen, i, j;
113138627Stakawata
114138627Stakawata#define UNKNOWN_LENGTH	-1
115138627Stakawata
116138627Stakawata	if (slen == UNKNOWN_LENGTH)
117138627Stakawata		/* get string's length */
118138627Stakawata		for (slen = 0, p = str; *p != '\0'; p++)
119138627Stakawata			slen ++;
120138627Stakawata
121138627Stakawata	/* get token's length */
122138627Stakawata	for (tlen = 0, p = token; *p != '\0'; p++)
123138627Stakawata		tlen ++;
124138627Stakawata
125138627Stakawata	if (tlen == 0)
126138627Stakawata		return (str);
127138627Stakawata
128138627Stakawata	for (i = 0; i <= slen-tlen; i++) {
129138627Stakawata		for (j = 0; j < tlen; j++)
130138627Stakawata			if (str[i+j] != token[j])
131138627Stakawata				break;
132138627Stakawata		if (j == tlen)
133138627Stakawata			return (&str[i]);
134138627Stakawata	}
135138627Stakawata
136138627Stakawata	return (NULL);
137138627Stakawata}
138138627Stakawata
139138627Stakawata/*
140138627Stakawata * ppb_pnp_detect()
141138627Stakawata *
142138627Stakawata * Returns the class id. of the peripherial, -1 otherwise
143138627Stakawata */
144138627Stakawatastatic int
145138627Stakawatappb_pnp_detect(struct ppb_data *ppb)
146138627Stakawata{
147138627Stakawata	char *token, *q, *class = 0;
148138627Stakawata	int i, len, error;
149138627Stakawata	char str[PPB_PnP_STRING_SIZE+1];
150138627Stakawata
151138627Stakawata	struct ppb_device pnpdev;	/* temporary device to perform I/O */
152138627Stakawata
153138627Stakawata	/* initialize the pnpdev structure for future use */
154138627Stakawata	bzero(&pnpdev, sizeof(pnpdev));
155138627Stakawata
156138627Stakawata	pnpdev.ppb = ppb;
157138627Stakawata
158138627Stakawata#ifdef PnP_DEBUG
159138627Stakawata	printf("ppb: <PnP> probing PnP devices on ppbus%d...\n",
160138627Stakawata		ppb->ppb_link->adapter_unit);
161138627Stakawata#endif
162138627Stakawata
163138627Stakawata	ppb_wctr(&pnpdev, nINIT | SELECTIN);
164138627Stakawata
165138627Stakawata	/* select NIBBLE_1284_REQUEST_ID mode */
166138627Stakawata	if ((error = nibble_1284_mode(&pnpdev, NIBBLE_1284_REQUEST_ID))) {
167138627Stakawata#ifdef PnP_DEBUG
168138627Stakawata		printf("ppb: <PnP> nibble_1284_mode()=%d\n", error);
169138627Stakawata#endif
170138627Stakawata		return (-1);
171138627Stakawata	}
172138627Stakawata
173138627Stakawata	len = 0;
174138627Stakawata	for (q = str; !(ppb_rstr(&pnpdev) & ERROR); q++) {
175138627Stakawata		if ((error = nibble_1284_inbyte(&pnpdev, q))) {
176138627Stakawata#ifdef PnP_DEBUG
177138627Stakawata			printf("ppb: <PnP> nibble_1284_inbyte()=%d\n", error);
178138627Stakawata#endif
179138627Stakawata			return (-1);
180138627Stakawata		}
181138627Stakawata		if (len++ >= PPB_PnP_STRING_SIZE) {
182138627Stakawata			printf("ppb: <PnP> not space left!\n");
183138627Stakawata			return (-1);
184138627Stakawata		}
185138627Stakawata	}
186138627Stakawata	*q = '\0';
187138627Stakawata
188138627Stakawata	nibble_1284_sync(&pnpdev);
189138627Stakawata
190138627Stakawata#ifdef PnP_DEBUG
191138627Stakawata	printf("ppb: <PnP> %d characters: ", len);
192138627Stakawata	for (i = 0; i < len; i++)
193138627Stakawata		printf("0x%x ", str[i]);
194138627Stakawata	printf("\n");
195138627Stakawata#endif
196138627Stakawata
197138627Stakawata	/* replace ';' characters by '\0' */
198138627Stakawata	for (i = 0; i < len; i++)
199138627Stakawata		str[i] = (str[i] == ';') ? '\0' : str[i];
200138627Stakawata
201138627Stakawata	if ((token = search_token(str, len, "MFG")) != NULL)
202138627Stakawata		printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit,
203138627Stakawata			search_token(token, UNKNOWN_LENGTH, ":") + 1);
204138627Stakawata	else
205138627Stakawata		printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit);
206138627Stakawata
207138627Stakawata	if ((token = search_token(str, len, "MDL")) != NULL)
208138627Stakawata		printf(" %s",
209138627Stakawata			search_token(token, UNKNOWN_LENGTH, ":") + 1);
210138627Stakawata	else
211138627Stakawata		printf(" unknown");
212138627Stakawata
213138627Stakawata	if ((token = search_token(str, len, "VER")) != NULL)
214138627Stakawata		printf("/%s",
215138627Stakawata			search_token(token, UNKNOWN_LENGTH, ":") + 1);
216138627Stakawata
217138627Stakawata	if ((token = search_token(str, len, "REV")) != NULL)
218138627Stakawata		printf(".%s",
219138627Stakawata			search_token(token, UNKNOWN_LENGTH, ":") + 1);
220138627Stakawata
221138627Stakawata	printf(">");
222138627Stakawata
223138627Stakawata	if ((token = search_token(str, len, "CLS")) != NULL) {
224138627Stakawata		class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
225138627Stakawata		printf(" %s", class);
226138627Stakawata	}
227138627Stakawata
228138627Stakawata	if ((token = search_token(str, len, "CMD")) != NULL)
229138627Stakawata		printf(" %s",
230138627Stakawata			search_token(token, UNKNOWN_LENGTH, ":") + 1);
231138627Stakawata
232138627Stakawata	printf("\n");
233138627Stakawata
234138627Stakawata	if (class)
235138627Stakawata		/* identify class ident */
236138627Stakawata		for (i = 0; pnp_tokens[i] != NULL; i++) {
237138627Stakawata			if (search_token(class, len, pnp_tokens[i]) != NULL) {
238138627Stakawata				return (i);
239138627Stakawata				break;
240138627Stakawata			}
241138627Stakawata		}
242138627Stakawata
243138627Stakawata	return (PPB_PnP_UNKNOWN);
244138627Stakawata}
245138627Stakawata
246138627Stakawata/*
247138627Stakawata * ppb_attachdevs()
248138627Stakawata *
249138627Stakawata * Called by ppcattach(), this function probes the ppbus and
250138627Stakawata * attaches found devices.
251138627Stakawata */
252138627Stakawataint
253138627Stakawatappb_attachdevs(struct ppb_data *ppb)
254138627Stakawata{
255138627Stakawata	int error;
256138627Stakawata	struct ppb_device *dev;
257138627Stakawata	struct ppb_driver **p_drvpp, *p_drvp;
258138774Sscottl
259138774Sscottl	LIST_INIT(&ppb->ppb_devs);	/* initialise device/driver list */
260138627Stakawata	p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items;
261138627Stakawata
262138627Stakawata	/* detect PnP devices */
263138627Stakawata	ppb->class_id = ppb_pnp_detect(ppb);
264138627Stakawata
265138627Stakawata	/*
266138627Stakawata	 * Blindly try all probes here.  Later we should look at
267138627Stakawata	 * the parallel-port PnP standard, and intelligently seek
268138627Stakawata	 * drivers based on configuration first.
269138627Stakawata	 */
270138627Stakawata	while ((p_drvp = *p_drvpp++) != NULL) {
271138627Stakawata	    if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) {
272138627Stakawata		/*
273138627Stakawata		 * Add the device to the list of probed devices.
274138627Stakawata		 */
275138627Stakawata		LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
276138627Stakawata
277138627Stakawata		/* Call the device's attach routine */
278138627Stakawata		(void)p_drvp->attach(dev);
279138627Stakawata	    }
280138627Stakawata	}
281138627Stakawata	return (0);
282138627Stakawata}
283138627Stakawata
284138627Stakawata/*
285138627Stakawata * ppb_next_bus()
286138627Stakawata *
287138627Stakawata * Return the next bus in ppbus queue
288138627Stakawata */
289138627Stakawatastruct ppb_data *
290138627Stakawatappb_next_bus(struct ppb_data *ppb)
291138627Stakawata{
292138627Stakawata
293138627Stakawata	if (ppb == NULL)
294138627Stakawata		return (ppbdata.lh_first);
295138627Stakawata
296138627Stakawata	return (ppb->ppb_chain.le_next);
297138627Stakawata}
298138627Stakawata
299138627Stakawata/*
300138627Stakawata * ppb_lookup_bus()
301138627Stakawata *
302138627Stakawata * Get ppb_data structure pointer according to the base address of the ppbus
303138627Stakawata */
304138627Stakawatastruct ppb_data *
305138627Stakawatappb_lookup_bus(int base_port)
306138627Stakawata{
307138627Stakawata	struct ppb_data *ppb;
308138627Stakawata
309138627Stakawata	for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next)
310138627Stakawata		if (ppb->ppb_link->base == base_port)
311138627Stakawata			break;
312138627Stakawata
313138627Stakawata	return (ppb);
314138627Stakawata}
315138627Stakawata
316138627Stakawata/*
317138627Stakawata * ppb_attach_device()
318138627Stakawata *
319138627Stakawata * Called by loadable kernel modules to add a device
320138627Stakawata */
321138627Stakawataint
322138627Stakawatappb_attach_device(struct ppb_device *dev)
323138627Stakawata{
324138627Stakawata	struct ppb_data *ppb = dev->ppb;
325138627Stakawata
326138627Stakawata	/* add the device to the list of probed devices */
327138627Stakawata	LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain);
328138627Stakawata
329138627Stakawata	return (0);
330138627Stakawata}
331138627Stakawata
332138627Stakawata/*
333138627Stakawata * ppb_remove_device()
334138627Stakawata *
335138627Stakawata * Called by loadable kernel modules to remove a device
336138627Stakawata */
337138627Stakawatavoid
338138627Stakawatappb_remove_device(struct ppb_device *dev)
339138627Stakawata{
340138627Stakawata
341138627Stakawata	/* remove the device from the list of probed devices */
342138627Stakawata	LIST_REMOVE(dev, chain);
343138627Stakawata
344138627Stakawata	return;
345138627Stakawata}
346138627Stakawata
347138627Stakawata/*
348138627Stakawata * ppb_request_bus()
349138627Stakawata *
350138627Stakawata * Allocate the device to perform transfers.
351138627Stakawata *
352138627Stakawata * how	: PPB_WAIT or PPB_DONTWAIT
353138627Stakawata */
354138627Stakawataint
355138627Stakawatappb_request_bus(struct ppb_device *dev, int how)
356138627Stakawata{
357138627Stakawata	int s, error = 0;
358138627Stakawata	struct ppb_data *ppb = dev->ppb;
359138627Stakawata
360138627Stakawata	while (!error) {
361138627Stakawata		s = splhigh();
362138627Stakawata		if (ppb->ppb_owner) {
363138627Stakawata			splx(s);
364138627Stakawata
365138627Stakawata			switch (how) {
366138627Stakawata			case (PPB_WAIT | PPB_INTR):
367138627Stakawata				error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
368138627Stakawata				break;
369138627Stakawata
370138627Stakawata			case (PPB_WAIT | PPB_NOINTR):
371138627Stakawata				error = tsleep(ppb, PPBPRI, "ppbreq", 0);
372138627Stakawata				break;
373138627Stakawata
374138627Stakawata			default:
375138627Stakawata				return (EWOULDBLOCK);
376138627Stakawata				break;
377138627Stakawata			}
378138627Stakawata
379138627Stakawata		} else {
380138627Stakawata			ppb->ppb_owner = dev;
381138627Stakawata
382138627Stakawata			splx(s);
383138627Stakawata			return (0);
384138627Stakawata		}
385138627Stakawata	}
386138627Stakawata
387138627Stakawata	return (error);
388138627Stakawata}
389138627Stakawata
390138627Stakawata/*
391138627Stakawata * ppb_release_bus()
392138627Stakawata *
393138627Stakawata * Release the device allocated with ppb_request_dev()
394138627Stakawata */
395138627Stakawataint
396138627Stakawatappb_release_bus(struct ppb_device *dev)
397138627Stakawata{
398138627Stakawata	int s;
399138627Stakawata	struct ppb_data *ppb = dev->ppb;
400138627Stakawata
401138627Stakawata	s = splhigh();
402138627Stakawata	if (ppb->ppb_owner != dev) {
403138627Stakawata		splx(s);
404138627Stakawata		return (EACCES);
405138627Stakawata	}
406138627Stakawata
407138627Stakawata	ppb->ppb_owner = 0;
408138627Stakawata	splx(s);
409138627Stakawata
410138627Stakawata	/* wakeup waiting processes */
411138627Stakawata	wakeup(ppb);
412138627Stakawata
413138627Stakawata	return (0);
414138627Stakawata}
415138627Stakawata