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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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