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