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