1/* $NetBSD: ppbus_base.c,v 1.23 2023/02/13 22:44:52 andvar Exp $ */
2
3/*-
4 * Copyright (c) 1997, 1998, 1999 Nicolas Souchu
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * FreeBSD: src/sys/dev/ppbus/ppb_base.c,v 1.10.2.1 2000/08/01 23:26:26 n_hibma Exp
29 *
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: ppbus_base.c,v 1.23 2023/02/13 22:44:52 andvar Exp $");
34
35#include "opt_ppbus_1284.h"
36#include "opt_ppbus.h"
37
38#include <sys/param.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41#include <sys/proc.h>
42#include <sys/systm.h>
43
44#include <dev/ppbus/ppbus_1284.h>
45#include <dev/ppbus/ppbus_conf.h>
46#include <dev/ppbus/ppbus_base.h>
47#include <dev/ppbus/ppbus_device.h>
48#include <dev/ppbus/ppbus_io.h>
49#include <dev/ppbus/ppbus_var.h>
50
51#ifndef DONTPROBE_1284
52/* Utility functions */
53static char * search_token(char *, int, const char *);
54#endif
55
56/* Perform general ppbus I/O request */
57int
58ppbus_io(device_t dev, int iop, u_char * addr, int cnt, u_char byte)
59{
60	struct ppbus_softc * bus = device_private(dev);
61	return (bus->ppbus_io(device_parent(dev), iop, addr, cnt, byte));
62}
63
64/* Execute microsequence */
65int
66ppbus_exec_microseq(device_t dev, struct ppbus_microseq ** sequence)
67{
68	struct ppbus_softc * bus = device_private(dev);
69	return (bus->ppbus_exec_microseq(device_parent(dev), sequence));
70}
71
72/* Read instance variables of ppbus */
73int
74ppbus_read_ivar(device_t dev, int index, unsigned int * val)
75
76{
77	struct ppbus_softc * bus = device_private(dev);
78
79	switch (index) {
80	case PPBUS_IVAR_INTR:
81	case PPBUS_IVAR_EPP_PROTO:
82	case PPBUS_IVAR_DMA:
83		return (bus->ppbus_read_ivar(device_parent(dev), index, val));
84
85	case PPBUS_IVAR_IEEE:
86		*val = (bus->sc_use_ieee == PPBUS_ENABLE_IEEE) ? 1 : 0;
87		break;
88
89	default:
90		return (ENOENT);
91	}
92
93	return 0;
94}
95
96/* Write an instance variable */
97int
98ppbus_write_ivar(device_t dev, int index, unsigned int * val)
99{
100	struct ppbus_softc * bus = device_private(dev);
101
102	switch (index) {
103	case PPBUS_IVAR_INTR:
104	case PPBUS_IVAR_EPP_PROTO:
105	case PPBUS_IVAR_DMA:
106		return (bus->ppbus_write_ivar(device_parent(dev), index, val));
107
108	case PPBUS_IVAR_IEEE:
109		bus->sc_use_ieee = ((*val != 0) ? PPBUS_ENABLE_IEEE :
110			PPBUS_DISABLE_IEEE);
111		break;
112
113	default:
114		return (ENOENT);
115	}
116
117	return 0;
118}
119
120/* Polls the bus for a max of 10-milliseconds */
121int
122ppbus_poll_bus(device_t dev, int maxp, char mask, char status,
123	int how)
124{
125	int i, j, error;
126	char r;
127
128	/* try at least up to 10ms */
129	for (j = 0; j < ((how & PPBUS_POLL) ? maxp : 1); j++) {
130		for (i = 0; i < 10000; i++) {
131			r = ppbus_rstr(dev);
132			DELAY(1);
133			if ((r & mask) == status)
134				return (0);
135		}
136	}
137
138	if (!(how & PPBUS_POLL)) {
139	   for (i = 0; maxp == PPBUS_FOREVER || i < maxp-1; i++) {
140		if ((ppbus_rstr(dev) & mask) == status)
141			return (0);
142
143		switch (how) {
144		case PPBUS_NOINTR:
145			/* wait 10 ms */
146			kpause("ppbuspoll", false, hz / 100, NULL);
147			break;
148
149		case PPBUS_INTR:
150		default:
151			/* wait 10 ms */
152			error = kpause("ppbuspoll", true, hz / 100, NULL);
153			if (error != EWOULDBLOCK) {
154				return error;
155			}
156			break;
157		}
158	   }
159	}
160
161	return (EWOULDBLOCK);
162}
163
164/* Get operating mode of the chipset */
165int
166ppbus_get_mode(device_t dev)
167{
168	struct ppbus_softc * bus = device_private(dev);
169
170	return (bus->sc_mode);
171}
172
173/* Set the operating mode of the chipset, return 0 on success. */
174int
175ppbus_set_mode(device_t dev, int mode, int options)
176{
177	struct ppbus_softc * bus = device_private(dev);
178	int error = 0;
179
180	/* If no mode change, do nothing */
181	if(bus->sc_mode == mode)
182		return error;
183
184	/* Do necessary negotiations */
185	if(bus->sc_use_ieee == PPBUS_ENABLE_IEEE) {
186		/* Cannot negotiate standard mode */
187		if(!(mode & (PPBUS_FAST | PPBUS_COMPATIBLE))) {
188 			error = ppbus_1284_negotiate(dev, mode, options);
189		}
190		/* Termination is unnecessary for standard<->fast */
191		else if(!(bus->sc_mode & (PPBUS_FAST | PPBUS_COMPATIBLE))) {
192			ppbus_1284_terminate(dev);
193		}
194	}
195
196	if(!error) {
197		/* Set mode and update mode of ppbus to actual mode */
198		error = bus->ppbus_setmode(device_parent(dev), mode);
199		bus->sc_mode = bus->ppbus_getmode(device_parent(dev));
200	}
201
202	/* Update host state if necessary */
203	if(!(error) && (bus->sc_use_ieee == PPBUS_ENABLE_IEEE)) {
204		switch(mode) {
205		case PPBUS_COMPATIBLE:
206		case PPBUS_FAST:
207		case PPBUS_EPP:
208		case PPBUS_ECP:
209			ppbus_1284_set_state(dev, PPBUS_FORWARD_IDLE);
210			break;
211
212		case PPBUS_NIBBLE:
213		case PPBUS_PS2:
214			ppbus_1284_set_state(dev, PPBUS_REVERSE_IDLE);
215			break;
216		}
217	}
218
219	return error;
220}
221
222/* Write characters to the port */
223int
224ppbus_write(device_t dev, char * buf, int len, int how, size_t * cnt)
225{
226	struct ppbus_softc * bus = device_private(dev);
227
228	if(bus->sc_use_ieee == PPBUS_ENABLE_IEEE) {
229		if(bus->sc_1284_state != PPBUS_FORWARD_IDLE) {
230			printf("%s(%s): bus not in forward idle mode.\n",
231				__func__, device_xname(dev));
232			return ENODEV;
233		}
234	}
235
236	return (bus->ppbus_write(device_parent(bus->sc_dev), buf, len, how, cnt));
237}
238
239/* Read characters from the port */
240int
241ppbus_read(device_t dev, char * buf, int len, int how, size_t * cnt)
242{
243	struct ppbus_softc * bus = device_private(dev);
244
245	if(bus->sc_use_ieee == PPBUS_ENABLE_IEEE) {
246		if(bus->sc_1284_state != PPBUS_REVERSE_IDLE) {
247			printf("%s(%s): bus not in reverse idle mode.\n",
248				__func__, device_xname(dev));
249			return ENODEV;
250		}
251	}
252
253	return (bus->ppbus_read(device_parent(dev), buf, len, how, cnt));
254}
255
256/* Reset the EPP timeout bit in the status register */
257int
258ppbus_reset_epp_timeout(device_t dev)
259{
260	struct ppbus_softc * bus = device_private(dev);
261
262	if(bus->sc_capabilities & PPBUS_HAS_EPP) {
263		bus->ppbus_reset_epp_timeout(device_parent(dev));
264		return 0;
265	}
266	else {
267		return ENODEV;
268	}
269}
270
271/* Wait for the ECP FIFO to be empty */
272int
273ppbus_ecp_sync(device_t dev)
274{
275	struct ppbus_softc * bus = device_private(dev);
276
277	if(bus->sc_capabilities & PPBUS_HAS_ECP) {
278		bus->ppbus_ecp_sync(device_parent(dev));
279		return 0;
280	}
281	else {
282		return ENODEV;
283	}
284}
285
286/* Allocate DMA for use with ppbus */
287int
288ppbus_dma_malloc(device_t dev, void ** buf, bus_addr_t * addr,
289	bus_size_t size)
290{
291	struct ppbus_softc * ppbus = device_private(dev);
292
293	if(ppbus->sc_capabilities & PPBUS_HAS_DMA)
294		return (ppbus->ppbus_dma_malloc(device_parent(dev), buf, addr,
295			size));
296	else
297		return ENODEV;
298}
299
300/* Free memory allocated with ppbus_dma_malloc() */
301int
302ppbus_dma_free(device_t dev, void ** buf, bus_addr_t * addr,
303	bus_size_t size)
304{
305	struct ppbus_softc * ppbus = device_private(dev);
306
307	if(ppbus->sc_capabilities & PPBUS_HAS_DMA) {
308		ppbus->ppbus_dma_free(device_parent(dev), buf, addr, size);
309		return 0;
310	}
311	else {
312		return ENODEV;
313	}
314}
315
316/* Install a handler to be called by hardware interrupt handler */
317int ppbus_add_handler(device_t dev, void (*func)(void *), void *arg)
318{
319	struct ppbus_softc * bus = device_private(dev);
320
321	if(bus->sc_capabilities & PPBUS_HAS_INTR)
322		return bus->ppbus_add_handler(device_parent(dev), func, arg);
323	else
324		return ENODEV;
325}
326
327/* Remove a handler registered with ppbus_add_handler() */
328int ppbus_remove_handler(device_t dev, void (*func)(void *))
329{
330	struct ppbus_softc * bus = device_private(dev);
331
332	if(bus->sc_capabilities & PPBUS_HAS_INTR)
333		return bus->ppbus_remove_handler(device_parent(dev), func);
334	else
335		return ENODEV;
336}
337
338/*
339 * ppbus_get_status()
340 *
341 * Read the status register and update the status info
342 */
343int
344ppbus_get_status(device_t dev, struct ppbus_status * status)
345{
346	register char r = status->status = ppbus_rstr(dev);
347
348	status->timeout	= r & TIMEOUT;
349	status->error	= !(r & nFAULT);
350	status->select	= r & SELECT;
351	status->paper_end = r & PERROR;
352	status->ack	= !(r & nACK);
353	status->busy	= !(r & nBUSY);
354
355	return (0);
356}
357
358/* Allocate the device to perform transfers */
359int
360ppbus_request_bus(device_t dev, device_t busdev, int how,
361	unsigned int timeout)
362{
363	struct ppbus_softc * bus = device_private(dev);
364	unsigned int counter = timeout;
365	bool intr = (how & PPBUS_INTR) != 0;
366	int error;
367
368	/* Loop until lock acquired (if PPBUS_WAIT) or an error occurs */
369	for(;;) {
370		if (mutex_tryenter(&(bus->sc_lock)))
371			break;
372
373		if(how & PPBUS_WAIT) {
374			error = kpause("ppbusreq", intr, hz / 2, NULL);
375			counter -= (hz/2);
376			if(!(error))
377				continue;
378			else if(error != EWOULDBLOCK)
379				goto end;
380			if(counter == 0) {
381				error = ETIMEDOUT;
382				goto end;
383			}
384		}
385		else {
386			error = EWOULDBLOCK;
387			goto end;
388		}
389	}
390
391	/* Set bus owner or return error if bus is taken */
392	if(bus->ppbus_owner == NULL) {
393		bus->ppbus_owner = busdev;
394		error = 0;
395	}
396	else {
397		error = EBUSY;
398	}
399
400	/* Release lock */
401	mutex_exit(&(bus->sc_lock));
402
403end:
404	return error;
405}
406
407/* Release the device allocated with ppbus_request_bus() */
408int
409ppbus_release_bus(device_t dev, device_t busdev, int how,
410	unsigned int timeout)
411{
412	struct ppbus_softc * bus = device_private(dev);
413	unsigned int counter = timeout;
414	bool intr = (how & PPBUS_INTR) != 0;
415	int error;
416
417	/* Loop until lock acquired (if PPBUS_WAIT) or an error occurs */
418	for(;;) {
419		if (mutex_tryenter(&(bus->sc_lock)))
420			break;
421
422		if(how & PPBUS_WAIT) {
423			error = kpause("ppbusrel", intr, hz / 2, NULL);
424			counter -= (hz/2);
425			if(!(error))
426				continue;
427			else if(error != EWOULDBLOCK)
428				goto end;
429			if(counter == 0) {
430				error = ETIMEDOUT;
431				goto end;
432			}
433		}
434		else {
435			error = EWOULDBLOCK;
436			goto end;
437		}
438	}
439
440	/* If the device is the owner, release bus */
441	if(bus->ppbus_owner != busdev) {
442		error = EINVAL;
443	}
444	else {
445		bus->ppbus_owner = NULL;
446		error = 0;
447	}
448
449	/* Release lock */
450	mutex_exit(&(bus->sc_lock));
451
452end:
453	return error;
454}
455
456
457/* IEEE 1284-based probes */
458
459#ifndef DONTPROBE_1284
460
461static const char *pnp_tokens[] = {
462	"PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
463	"FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
464
465/* ??? */
466#if 0
467static char *pnp_classes[] = {
468	"printer", "modem", "network device",
469	"hard disk", "PCMCIA", "multimedia device",
470	"floppy disk", "ports", "scanner",
471	"digital camera", "unknown device", NULL };
472#endif
473
474/*
475 * Search the first occurrence of a token within a string
476 * XXX should use strxxx() calls
477 */
478static char *
479search_token(char *str, int slen, const char *token)
480{
481	const char *p;
482	int tlen, i, j;
483
484#define UNKNOWN_LENGTH  -1
485
486	if (slen == UNKNOWN_LENGTH)
487	       /* get string's length */
488	       for (slen = 0, p = str; *p != '\0'; p++)
489		       slen++;
490
491       /* get token's length */
492       for (tlen = 0, p = token; *p != '\0'; p++)
493	       tlen++;
494
495       if (tlen == 0)
496	       return (str);
497
498       for (i = 0; i <= slen-tlen; i++) {
499	       for (j = 0; j < tlen; j++)
500		       if (str[i+j] != token[j])
501			       break;
502	       if (j == tlen)
503		       return (&str[i]);
504       }
505
506	return (NULL);
507}
508
509/* Stores the class ID of the peripheral in soft config data */
510void
511ppbus_pnp_detect(device_t dev)
512{
513	struct ppbus_softc * bus = device_private(dev);
514	int i;
515	int error;
516	size_t len = 0;
517	size_t str_sz = 0;
518	char * str = NULL;
519	char * class = NULL;
520	char * token;
521
522#ifdef PPBUS_VERBOSE
523	printf("%s: Probing for PnP devices.\n", device_xname(dev));
524#endif
525
526	error = ppbus_1284_read_id(dev, PPBUS_NIBBLE, &str, &str_sz, &len);
527	if(str_sz != len) {
528#ifdef DEBUG_1284
529		printf("%s(%s): device returned less characters than expected "
530			"in device ID.\n", __func__, device_xname(dev));
531#endif
532	}
533	if(error) {
534		printf("%s: Error getting device ID (errno = %d)\n",
535			device_xname(dev), error);
536		goto end_detect;
537	}
538
539#ifdef DEBUG_1284
540	printf("%s: <PnP> %zu characters: ", device_xname(dev), len);
541	for (i = 0; i < len; i++)
542		printf("%c(0x%x) ", str[i], str[i]);
543	printf("\n");
544#endif
545
546	/* replace ';' characters by '\0' */
547	for (i = 0; i < len; i++)
548		if(str[i] == ';') str[i] = '\0';
549		/* str[i] = (str[i] == ';') ? '\0' : str[i]; */
550
551	if ((token = search_token(str, len, "MFG")) != NULL ||
552		(token = search_token(str, len, "MANUFACTURER")) != NULL)
553		printf("%s: <%s", device_xname(dev),
554			search_token(token, UNKNOWN_LENGTH, ":") + 1);
555	else
556		printf("%s: <unknown", device_xname(dev));
557
558	if ((token = search_token(str, len, "MDL")) != NULL ||
559		(token = search_token(str, len, "MODEL")) != NULL)
560		printf(" %s",
561			search_token(token, UNKNOWN_LENGTH, ":") + 1);
562
563	if ((token = search_token(str, len, "REV")) != NULL)
564		printf(".%s",
565			search_token(token, UNKNOWN_LENGTH, ":") + 1);
566
567	printf(">");
568
569	if ((token = search_token(str, len, "CLS")) != NULL) {
570		class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
571		printf(" %s", class);
572	}
573
574	if ((token = search_token(str, len, "CMD")) != NULL ||
575		(token = search_token(str, len, "COMMAND")) != NULL)
576		printf(" %s",
577			search_token(token, UNKNOWN_LENGTH, ":") + 1);
578
579	printf("\n");
580
581	if (class) {
582		/* identify class ident */
583		for (i = 0; pnp_tokens[i] != NULL; i++) {
584			if (search_token(class, len, pnp_tokens[i]) != NULL) {
585				bus->sc_class_id = i;
586				goto end_detect;
587			}
588		}
589	}
590	bus->sc_class_id = PPBUS_PNP_UNKNOWN;
591
592end_detect:
593	if(str)
594		free(str, M_DEVBUF);
595        return;
596}
597
598/* Scan the ppbus for IEEE1284 compliant devices */
599int
600ppbus_scan_bus(device_t dev)
601{
602	struct ppbus_softc * bus = device_private(dev);
603	int error;
604
605	/* Try IEEE1284 modes, one device only (no IEEE1284.3 support) */
606
607	error = ppbus_1284_negotiate(dev, PPBUS_NIBBLE, 0);
608	if (error && bus->sc_1284_state == PPBUS_ERROR
609	    && bus->sc_1284_error == PPBUS_NOT_IEEE1284)
610		return (error);
611	ppbus_1284_terminate(dev);
612
613#if defined(PPBUS_VERBOSE) || defined(PPBUS_DEBUG)
614	/* IEEE1284 supported, print info */
615	printf("%s: IEEE1284 negotiation: modes %s",
616	    device_xname(dev), "NIBBLE");
617
618	error = ppbus_1284_negotiate(dev, PPBUS_PS2, 0);
619	if (!error)
620		printf("/PS2");
621	ppbus_1284_terminate(dev);
622
623	error = ppbus_1284_negotiate(dev, PPBUS_ECP, 0);
624	if (!error)
625		printf("/ECP");
626	ppbus_1284_terminate(dev);
627
628	error = ppbus_1284_negotiate(dev, PPBUS_ECP, PPBUS_USE_RLE);
629	if (!error)
630		printf("/ECP_RLE");
631	ppbus_1284_terminate(dev);
632
633	error = ppbus_1284_negotiate(dev, PPBUS_EPP, 0);
634	if (!error)
635		printf("/EPP");
636	ppbus_1284_terminate(dev);
637
638	printf("\n");
639#endif /* PPBUS_VERBOSE || PPBUS_DEBUG */
640
641	return 0;
642}
643
644#endif /* !DONTPROBE_1284 */
645
646