xref: /freebsd/sys/dev/ppbus/ppb_base.c (revision 2ad872c5794e4c26fdf6ed219ad3f09ca0d5304a)
1 /*-
2  * Copyright (c) 1997, 1998 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: ppb_base.c,v 1.5 1998/09/13 18:26:26 nsouch Exp $
27  *
28  */
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <machine/clock.h>
33 
34 #include <dev/ppbus/ppbconf.h>
35 
36 /*
37  * ppb_intr()
38  *
39  * Function called by ppcintr() when an intr occurs.
40  */
41 void
42 ppb_intr(struct ppb_link *pl)
43 {
44 	struct ppb_data *ppb = pl->ppbus;
45 
46 	/*
47 	 * Call chipset dependent code.
48 	 * Should be filled at chipset initialisation if needed.
49 	 */
50 	if (pl->adapter->intr_handler)
51 		(*pl->adapter->intr_handler)(pl->adapter_unit);
52 
53 	/*
54 	 * Call upper handler iff the bus is owned by a device and
55 	 * this device has specified an interrupt handler.
56 	 */
57 	if (ppb->ppb_owner && ppb->ppb_owner->intr)
58 		(*ppb->ppb_owner->intr)(ppb->ppb_owner->id_unit);
59 
60 	return;
61 }
62 
63 /*
64  * ppb_poll_device()
65  *
66  * Polls the device
67  *
68  * max is a delay in 10-milliseconds
69  */
70 int
71 ppb_poll_device(struct ppb_device *dev, int max,
72 		char mask, char status, int how)
73 {
74 	int i, j, error;
75 	char r;
76 
77 	/* try at least up to 10ms */
78 	for (j = 0; j < ((how & PPB_POLL) ? max : 1); j++) {
79 		for (i = 0; i < 10000; i++) {
80 			r = ppb_rstr(dev);
81 			DELAY(1);
82 			if ((r & mask) == status)
83 				return (0);
84 		}
85 	}
86 
87 	if (!(how & PPB_POLL)) {
88 	   for (i = 0; max == PPB_FOREVER || i < max-1; i++) {
89 		if ((ppb_rstr(dev) & mask) == status)
90 			return (0);
91 
92 		switch (how) {
93 		case PPB_NOINTR:
94 			/* wait 10 ms */
95 			tsleep((caddr_t)dev, PPBPRI, "ppbpoll", hz/100);
96 			break;
97 
98 		case PPB_INTR:
99 		default:
100 			/* wait 10 ms */
101 			if ((error = tsleep((caddr_t)dev, PPBPRI | PCATCH,
102 					"ppbpoll", hz/100)) != EWOULDBLOCK)
103 				return (error);
104 			break;
105 		}
106 	   }
107 	}
108 
109 	return (EWOULDBLOCK);
110 }
111 
112 /*
113  * ppb_set_mode()
114  *
115  * Set the operating mode of the chipset
116  */
117 int
118 ppb_set_mode(struct ppb_device *dev, int mode)
119 {
120 	struct ppb_data *ppb = dev->ppb;
121 	int old_mode = ppb_get_mode(dev);
122 
123 	if ((*ppb->ppb_link->adapter->setmode)(
124 			ppb->ppb_link->adapter_unit, mode))
125 		return (-1);
126 
127 	/* XXX yet device mode = ppbus mode = chipset mode */
128 	dev->mode = ppb->mode = (mode & PPB_MASK);
129 
130 	return (old_mode);
131 }
132 
133 /*
134  * ppb_write()
135  *
136  * Write charaters to the port
137  */
138 int
139 ppb_write(struct ppb_device *dev, char *buf, int len, int how)
140 {
141 	struct ppb_data *ppb = dev->ppb;
142 
143 	return (ppb->ppb_link->adapter->write(ppb->ppb_link->adapter_unit,
144 						buf, len, how));
145 }
146 
147 /*
148  * ppb_reset_epp_timeout()
149  *
150  * Reset the EPP timeout bit in the status register
151  */
152 int
153 ppb_reset_epp_timeout(struct ppb_device *dev)
154 {
155 	struct ppb_data *ppb = dev->ppb;
156 
157 	if (ppb->ppb_owner != dev)
158 		return (EACCES);
159 
160 	(*ppb->ppb_link->adapter->reset_epp_timeout)(ppb->ppb_link->adapter_unit);
161 
162 	return (0);
163 }
164 
165 /*
166  * ppb_ecp_sync()
167  *
168  * Wait for the ECP FIFO to be empty
169  */
170 int
171 ppb_ecp_sync(struct ppb_device *dev)
172 {
173 	struct ppb_data *ppb = dev->ppb;
174 
175 	if (ppb->ppb_owner != dev)
176 		return (EACCES);
177 
178 	(*ppb->ppb_link->adapter->ecp_sync)(ppb->ppb_link->adapter_unit);
179 
180 	return (0);
181 }
182 
183 /*
184  * ppb_get_status()
185  *
186  * Read the status register and update the status info
187  */
188 int
189 ppb_get_status(struct ppb_device *dev, struct ppb_status *status)
190 {
191 	struct ppb_data *ppb = dev->ppb;
192 	register char r;
193 
194 	if (ppb->ppb_owner != dev)
195 		return (EACCES);
196 
197 	r = status->status = ppb_rstr(dev);
198 
199 	status->timeout	= r & TIMEOUT;
200 	status->error	= !(r & nFAULT);
201 	status->select	= r & SELECT;
202 	status->paper_end = r & PERROR;
203 	status->ack	= !(r & nACK);
204 	status->busy	= !(r & nBUSY);
205 
206 	return (0);
207 }
208