1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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
29 #include <sys/param.h>
30 #include <sys/lock.h>
31 #include <sys/kernel.h>
32 #include <sys/module.h>
33 #include <sys/mutex.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36
37 #include <dev/ppbus/ppbconf.h>
38
39 #include "ppbus_if.h"
40
41 #include <dev/ppbus/ppbio.h>
42
43 MODULE_VERSION(ppbus, 1);
44
45 #define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev))
46
47 /*
48 * ppb_poll_bus()
49 *
50 * Polls the bus
51 *
52 * max is a delay in 10-milliseconds
53 */
54 int
ppb_poll_bus(device_t bus,int max,uint8_t mask,uint8_t status,int how)55 ppb_poll_bus(device_t bus, int max,
56 uint8_t mask, uint8_t status, int how)
57 {
58 struct ppb_data *ppb = DEVTOSOFTC(bus);
59 int i, j, error;
60 uint8_t r;
61
62 ppb_assert_locked(bus);
63
64 /* try at least up to 10ms */
65 for (j = 0; j < ((how & PPB_POLL) ? max : 1); j++) {
66 for (i = 0; i < 10000; i++) {
67 r = ppb_rstr(bus);
68 DELAY(1);
69 if ((r & mask) == status)
70 return (0);
71 }
72 }
73
74 if (!(how & PPB_POLL)) {
75 for (i = 0; max == PPB_FOREVER || i < max-1; i++) {
76 if ((ppb_rstr(bus) & mask) == status)
77 return (0);
78
79 /* wait 10 ms */
80 error = mtx_sleep((caddr_t)bus, ppb->ppc_lock, PPBPRI |
81 (how == PPB_NOINTR ? 0 : PCATCH), "ppbpoll", hz/100);
82 if (error != EWOULDBLOCK)
83 return (error);
84 }
85 }
86
87 return (EWOULDBLOCK);
88 }
89
90 /*
91 * ppb_get_epp_protocol()
92 *
93 * Return the chipset EPP protocol
94 */
95 int
ppb_get_epp_protocol(device_t bus)96 ppb_get_epp_protocol(device_t bus)
97 {
98 uintptr_t protocol;
99
100 ppb_assert_locked(bus);
101 BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_EPP_PROTO, &protocol);
102
103 return (protocol);
104 }
105
106 /*
107 * ppb_get_mode()
108 *
109 */
110 int
ppb_get_mode(device_t bus)111 ppb_get_mode(device_t bus)
112 {
113 struct ppb_data *ppb = DEVTOSOFTC(bus);
114
115 /* XXX yet device mode = ppbus mode = chipset mode */
116 ppb_assert_locked(bus);
117 return (ppb->mode);
118 }
119
120 /*
121 * ppb_set_mode()
122 *
123 * Set the operating mode of the chipset, return the previous mode
124 */
125 int
ppb_set_mode(device_t bus,int mode)126 ppb_set_mode(device_t bus, int mode)
127 {
128 struct ppb_data *ppb = DEVTOSOFTC(bus);
129 int old_mode = ppb_get_mode(bus);
130
131 ppb_assert_locked(bus);
132 if (PPBUS_SETMODE(device_get_parent(bus), mode))
133 return (-1);
134
135 /* XXX yet device mode = ppbus mode = chipset mode */
136 ppb->mode = (mode & PPB_MASK);
137
138 return (old_mode);
139 }
140
141 /*
142 * ppb_write()
143 *
144 * Write charaters to the port
145 */
146 int
ppb_write(device_t bus,char * buf,int len,int how)147 ppb_write(device_t bus, char *buf, int len, int how)
148 {
149
150 ppb_assert_locked(bus);
151 return (PPBUS_WRITE(device_get_parent(bus), buf, len, how));
152 }
153
154 /*
155 * ppb_reset_epp_timeout()
156 *
157 * Reset the EPP timeout bit in the status register
158 */
159 int
ppb_reset_epp_timeout(device_t bus)160 ppb_reset_epp_timeout(device_t bus)
161 {
162
163 ppb_assert_locked(bus);
164 return(PPBUS_RESET_EPP(device_get_parent(bus)));
165 }
166
167 /*
168 * ppb_ecp_sync()
169 *
170 * Wait for the ECP FIFO to be empty
171 */
172 int
ppb_ecp_sync(device_t bus)173 ppb_ecp_sync(device_t bus)
174 {
175
176 ppb_assert_locked(bus);
177 return (PPBUS_ECP_SYNC(device_get_parent(bus)));
178 }
179
180 /*
181 * ppb_get_status()
182 *
183 * Read the status register and update the status info
184 */
185 int
ppb_get_status(device_t bus,struct ppb_status * status)186 ppb_get_status(device_t bus, struct ppb_status *status)
187 {
188 uint8_t r;
189
190 ppb_assert_locked(bus);
191
192 r = status->status = ppb_rstr(bus);
193
194 status->timeout = r & TIMEOUT;
195 status->error = !(r & nFAULT);
196 status->select = r & SELECT;
197 status->paper_end = r & PERROR;
198 status->ack = !(r & nACK);
199 status->busy = !(r & nBUSY);
200
201 return (0);
202 }
203
204 void
ppb_lock(device_t bus)205 ppb_lock(device_t bus)
206 {
207 struct ppb_data *ppb = DEVTOSOFTC(bus);
208
209 mtx_lock(ppb->ppc_lock);
210 }
211
212 void
ppb_unlock(device_t bus)213 ppb_unlock(device_t bus)
214 {
215 struct ppb_data *ppb = DEVTOSOFTC(bus);
216
217 mtx_unlock(ppb->ppc_lock);
218 }
219
220 struct mtx *
ppb_get_lock(device_t bus)221 ppb_get_lock(device_t bus)
222 {
223 struct ppb_data *ppb = DEVTOSOFTC(bus);
224
225 return (ppb->ppc_lock);
226 }
227
228 void
_ppb_assert_locked(device_t bus,const char * file,int line)229 _ppb_assert_locked(device_t bus, const char *file, int line)
230 {
231
232 mtx_assert_(DEVTOSOFTC(bus)->ppc_lock, MA_OWNED, file, line);
233 }
234
235 void
ppb_init_callout(device_t bus,struct callout * c,int flags)236 ppb_init_callout(device_t bus, struct callout *c, int flags)
237 {
238 struct ppb_data *ppb = DEVTOSOFTC(bus);
239
240 callout_init_mtx(c, ppb->ppc_lock, flags);
241 }
242
243 int
ppb_sleep(device_t bus,void * wchan,int priority,const char * wmesg,int timo)244 ppb_sleep(device_t bus, void *wchan, int priority, const char *wmesg, int timo)
245 {
246 struct ppb_data *ppb = DEVTOSOFTC(bus);
247
248 return (mtx_sleep(wchan, ppb->ppc_lock, priority, wmesg, timo));
249 }
250