ppbconf.c revision 28219
1/*- 2 * Copyright (c) 1997 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$ 27 * 28 */ 29#include <sys/param.h> 30#include <sys/systm.h> 31#include <sys/errno.h> 32#include <sys/conf.h> 33#include <sys/proc.h> 34#include <sys/buf.h> 35#include <sys/kernel.h> 36#include <sys/malloc.h> 37#include <sys/uio.h> 38#include <sys/syslog.h> 39 40#include <machine/clock.h> 41#include <machine/lpt.h> 42 43#include <vm/vm.h> 44#include <vm/vm_param.h> 45#include <vm/pmap.h> 46 47#include <i386/isa/isa.h> 48#include <i386/isa/isa_device.h> 49 50#include <dev/ppbus/ppbconf.h> 51 52LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */ 53 54/* 55 * Add a null driver so that the linker set always exists. 56 */ 57 58static struct ppb_driver nulldriver = { 59 NULL, NULL, "null" 60}; 61DATA_SET(ppbdriver_set, nulldriver); 62 63 64/* 65 * Parallel Port Bus sleep/wakeup queue. 66 */ 67#define PRIPPB 28 /* PSOCK < PRIPPB < PWAIT XXX */ 68 69/* 70 * ppb_alloc_bus() 71 * 72 * Allocate area to store the ppbus description. 73 * This function is called by ppcattach(). 74 */ 75struct ppb_data * 76ppb_alloc_bus(void) 77{ 78 struct ppb_data *ppb; 79 static int ppbdata_initted = 0; /* done-init flag */ 80 81 ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data), 82 M_TEMP, M_NOWAIT); 83 84 /* 85 * Add the new parallel port bus to the list of existing ppbus. 86 */ 87 if (ppb) { 88 bzero(ppb, sizeof(struct ppb_data)); 89 90 if (!ppbdata_initted) { /* list not initialised */ 91 LIST_INIT(&ppbdata); 92 ppbdata_initted = 1; 93 } 94 LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain); 95 } else { 96 printf("ppb_alloc_bus: cannot malloc!\n"); 97 } 98 return(ppb); 99} 100 101/* 102 * ppb_attachdevs() 103 * 104 * Called by ppcattach(), this function probes the ppbus and 105 * attaches found devices. 106 */ 107int 108ppb_attachdevs(struct ppb_data *ppb) 109{ 110 int error; 111 struct ppb_device *dev; 112 struct ppb_driver **p_drvpp, *p_drvp; 113 114 LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */ 115 p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items; 116 117 /* 118 * Blindly try all probes here. Later we should look at 119 * the parallel-port PnP standard, and intelligently seek 120 * drivers based on configuration first. 121 */ 122 while ((p_drvp = *p_drvpp++) != NULL) { 123 if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) { 124 /* 125 * Add the device to the list of probed devices. 126 */ 127 LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); 128 129 /* Call the device's attach routine */ 130 (void)p_drvp->attach(dev); 131 } 132 } 133 return (0); 134} 135 136/* 137 * ppb_request_bus() 138 * 139 * Allocate the device to perform transfers. 140 * 141 * how : PPB_WAIT or PPB_DONTWAIT 142 */ 143int 144ppb_request_bus(struct ppb_device *dev, int how) 145{ 146 int s, error = 0; 147 struct ppb_data *ppb = dev->ppb; 148 149 /* 150 * During initialisation, ppb is null. 151 */ 152 if (!ppb) 153 return (0); 154 155 while (error != EINTR) { 156 s = splhigh(); 157 if (ppb->ppb_owner) { 158 splx(s); 159 160 switch (how) { 161 case (PPB_WAIT | PPB_INTR): 162 163 error = tsleep(ppb, PRIPPB | PCATCH, 164 "ppbreq", 0); 165 break; 166 case (PPB_WAIT): 167 error = tsleep(ppb, PRIPPB, "ppbreq", 0); 168 break; 169 default: 170 return EWOULDBLOCK; 171 break; 172 } 173 174 } else { 175 ppb->ppb_owner = dev; 176 177 splx(s); 178 return (0); 179 } 180 } 181 182 return (EINTR); 183} 184 185/* 186 * ppb_release_bus() 187 * 188 * Release the device allocated with ppb_request_dev() 189 */ 190int 191ppb_release_bus(struct ppb_device *dev) 192{ 193 int s; 194 struct ppb_data *ppb = dev->ppb; 195 196 /* 197 * During initialisation, ppb is null. 198 */ 199 if (!ppb) 200 return (0); 201 202 s = splhigh(); 203 if (ppb->ppb_owner != dev) { 204 splx(s); 205 return (EACCES); 206 } 207 208 ppb->ppb_owner = 0; 209 splx(s); 210 211 /* 212 * Wakeup waiting processes. 213 */ 214 wakeup(ppb); 215 216 return (0); 217} 218 219/* 220 * ppb_intr() 221 * 222 * Function called by ppcintr() when an intr occurs. 223 */ 224void 225ppb_intr(struct ppb_link *pl) 226{ 227 struct ppb_data *ppb = pl->ppbus; 228 229 /* 230 * Call chipset dependent code. 231 * Should be filled at chipset initialisation if needed. 232 */ 233 if (pl->adapter->intr_handler) 234 (*pl->adapter->intr_handler)(pl->adapter_unit); 235 236 /* 237 * Call upper handler iff the bus is owned by a device and 238 * this device has specified an interrupt handler. 239 */ 240 if (ppb->ppb_owner && ppb->ppb_owner->intr) 241 (*ppb->ppb_owner->intr)(ppb->ppb_owner->id_unit); 242 243 return; 244} 245 246/* 247 * ppb_reset_epp_timeout() 248 * 249 * Reset the EPP timeout bit in the status register. 250 */ 251int 252ppb_reset_epp_timeout(struct ppb_device *dev) 253{ 254 struct ppb_data *ppb = dev->ppb; 255 256 if (ppb->ppb_owner != dev) 257 return (EACCES); 258 259 (*ppb->ppb_link->adapter->reset_epp_timeout)(dev->id_unit); 260 261 return (0); 262} 263 264/* 265 * ppb_ecp_sync() 266 * 267 * Wait for the ECP FIFO to be empty. 268 */ 269int 270ppb_ecp_sync(struct ppb_device *dev) 271{ 272 struct ppb_data *ppb = dev->ppb; 273 274 if (ppb->ppb_owner != dev) 275 return (EACCES); 276 277 (*ppb->ppb_link->adapter->ecp_sync)(dev->id_unit); 278 279 return (0); 280} 281 282/* 283 * ppb_get_mode() 284 * 285 * Read the mode (SPP, EPP...) of the chipset. 286 */ 287int 288ppb_get_mode(struct ppb_device *dev) 289{ 290 return (dev->ppb->ppb_link->mode); 291} 292 293/* 294 * ppb_get_epp_protocol() 295 * 296 * Read the EPP protocol (1.9 or 1.7). 297 */ 298int 299ppb_get_epp_protocol(struct ppb_device *dev) 300{ 301 return (dev->ppb->ppb_link->epp_protocol); 302} 303 304/* 305 * ppb_get_irq() 306 * 307 * Return the irq, 0 if none. 308 */ 309int 310ppb_get_irq(struct ppb_device *dev) 311{ 312 return (dev->ppb->ppb_link->id_irq); 313} 314 315/* 316 * ppb_get_status() 317 * 318 * Read the status register and update the status info. 319 */ 320int 321ppb_get_status(struct ppb_device *dev, struct ppb_status *status) 322{ 323 struct ppb_data *ppb = dev->ppb; 324 register char r; 325 326 if (ppb->ppb_owner != dev) 327 return (EACCES); 328 329 r = status->status = ppb_rstr(dev); 330 331 status->timeout = r & TIMEOUT; 332 status->error = !(r & nFAULT); 333 status->select = r & SELECT; 334 status->paper_end = r & ERROR; 335 status->ack = !(r & nACK); 336 status->busy = !(r & nBUSY); 337 338 return (0); 339} 340