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