1 /*- 2 * Copyright (c) 1997, 1998 Nicolas Souchu, Michael Smith 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: ppi.c,v 1.6 1998/01/02 09:30:39 msmith Exp $ 27 * 28 */ 29 #include "ppi.h" 30 31 #if NPPI > 0 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/conf.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/fcntl.h> 39 40 #include <dev/ppbus/ppbconf.h> 41 #include <dev/ppbus/ppi.h> 42 43 44 struct ppi_data { 45 46 int ppi_unit; 47 int ppi_flags; 48 #define HAVE_PPBUS (1<<0) 49 50 struct ppb_device ppi_dev; 51 }; 52 53 #define MAXPPI 8 /* XXX not much better! */ 54 static int nppi = 0; 55 static struct ppi_data *ppidata[MAXPPI]; 56 57 /* 58 * Make ourselves visible as a ppbus driver 59 */ 60 61 static struct ppb_device *ppiprobe(struct ppb_data *ppb); 62 static int ppiattach(struct ppb_device *dev); 63 static void ppiintr(int unit); 64 65 static struct ppb_driver ppidriver = { 66 ppiprobe, ppiattach, "ppi" 67 }; 68 DATA_SET(ppbdriver_set, ppidriver); 69 70 static d_open_t ppiopen; 71 static d_close_t ppiclose; 72 static d_ioctl_t ppiioctl; 73 74 #define CDEV_MAJOR 82 75 static struct cdevsw ppi_cdevsw = 76 { ppiopen, ppiclose, noread, nowrite, /* 82 */ 77 ppiioctl, nullstop, nullreset, nodevtotty, 78 seltrue, nommap, nostrat, "ppi", NULL, -1 }; 79 80 /* 81 * ppiprobe() 82 */ 83 static struct ppb_device * 84 ppiprobe(struct ppb_data *ppb) 85 { 86 struct ppi_data *ppi; 87 88 ppi = (struct ppi_data *) malloc(sizeof(struct ppi_data), 89 M_TEMP, M_NOWAIT); 90 if (!ppi) { 91 printf("ppi: cannot malloc!\n"); 92 return 0; 93 } 94 bzero(ppi, sizeof(struct ppi_data)); 95 96 ppidata[nppi] = ppi; 97 98 /* 99 * ppi dependent initialisation. 100 */ 101 ppi->ppi_unit = nppi; 102 103 /* 104 * ppbus dependent initialisation. 105 */ 106 ppi->ppi_dev.id_unit = ppi->ppi_unit; 107 ppi->ppi_dev.ppb = ppb; 108 ppi->ppi_dev.intr = ppiintr; 109 110 /* Ok, go to next device on next probe */ 111 nppi ++; 112 113 return &ppi->ppi_dev; 114 } 115 116 static int 117 ppiattach(struct ppb_device *dev) 118 { 119 struct ppi_data *ppi = ppidata[dev->id_unit]; 120 121 /* 122 * Report ourselves 123 */ 124 printf("ppi%d: <generic parallel i/o> on ppbus %d\n", 125 dev->id_unit, dev->ppb->ppb_link->adapter_unit); 126 127 return (1); 128 } 129 130 static void 131 ppiintr(int unit) 132 { 133 return; 134 } 135 136 static int 137 ppiopen(dev_t dev, int flags, int fmt, struct proc *p) 138 { 139 u_int unit = minor(dev); 140 struct ppi_data *ppi = ppidata[unit]; 141 int res; 142 143 if (unit >= nppi) 144 return (ENXIO); 145 146 if (!(ppi->ppi_flags & HAVE_PPBUS)) 147 if ((res = ppb_request_bus(&ppi->ppi_dev, (flags & O_NONBLOCK) ? PPB_DONTWAIT : (PPB_WAIT | PPB_INTR)))) 148 return (res); 149 150 ppi->ppi_flags |= HAVE_PPBUS; 151 return (0); 152 } 153 154 static int 155 ppiclose(dev_t dev, int flags, int fmt, struct proc *p) 156 { 157 u_int unit = minor(dev); 158 struct ppi_data *ppi = ppidata[unit]; 159 160 if (ppi->ppi_flags & HAVE_PPBUS) 161 ppb_release_bus(&ppi->ppi_dev); 162 ppi->ppi_flags &= ~HAVE_PPBUS; 163 return (0); 164 } 165 166 static int 167 ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 168 { 169 u_int unit = minor(dev); 170 struct ppi_data *ppi = ppidata[unit]; 171 int error = 0; 172 u_int8_t *val = (u_int8_t *)data; 173 174 switch (cmd) { 175 176 case PPIGDATA: /* get data register */ 177 *val = ppb_rdtr(&ppi->ppi_dev); 178 break; 179 case PPIGSTATUS: /* get status bits */ 180 *val = ppb_rstr(&ppi->ppi_dev); 181 break; 182 case PPIGCTRL: /* get control bits */ 183 *val = ppb_rctr(&ppi->ppi_dev); 184 break; 185 case PPIGEPP: /* get EPP bits */ 186 *val = ppb_repp(&ppi->ppi_dev); 187 break; 188 case PPIGECR: /* get ECP bits */ 189 *val = ppb_recr(&ppi->ppi_dev); 190 break; 191 case PPIGFIFO: /* read FIFO */ 192 *val = ppb_rfifo(&ppi->ppi_dev); 193 break; 194 195 case PPISDATA: /* set data register */ 196 ppb_wdtr(&ppi->ppi_dev, *val); 197 break; 198 case PPISSTATUS: /* set status bits */ 199 ppb_wstr(&ppi->ppi_dev, *val); 200 break; 201 case PPISCTRL: /* set control bits */ 202 ppb_wctr(&ppi->ppi_dev, *val); 203 break; 204 case PPISEPP: /* set EPP bits */ 205 ppb_wepp(&ppi->ppi_dev, *val); 206 break; 207 case PPISECR: /* set ECP bits */ 208 ppb_wecr(&ppi->ppi_dev, *val); 209 break; 210 case PPISFIFO: /* write FIFO */ 211 ppb_wfifo(&ppi->ppi_dev, *val); 212 break; 213 214 default: 215 error = ENOTTY; 216 break; 217 } 218 219 return (error); 220 } 221 222 #ifdef PPI_MODULE 223 224 MOD_DEV(ppi, LM_DT_CHAR, CDEV_MAJOR, &ppi_cdevsw); 225 226 static int 227 ppi_load(struct lkm_table *lkmtp, int cmd) 228 { 229 struct ppb_data *ppb; 230 struct ppb_device *dev; 231 int i; 232 233 for (ppb = ppb_next_bus(NULL); ppb; ppb = ppb_next_bus(ppb)) { 234 235 dev = ppiprobe(ppb); 236 ppiattach(dev); 237 238 ppb_attach_device(dev); 239 } 240 241 return (0); 242 } 243 244 static int 245 ppi_unload(struct lkm_table *lkmtp, int cmd) 246 { 247 int i; 248 249 for (i = nppi-1; i > 0; i--) { 250 ppb_remove_device(&ppidata[i]->ppi_dev); 251 free(ppidata[i], M_TEMP); 252 } 253 254 return (0); 255 } 256 257 int 258 ppi_mod(struct lkm_table *lkmtp, int cmd, int ver) 259 { 260 DISPATCH(lkmtp, cmd, ver, ppi_load, ppi_unload, lkm_nullcmd); 261 } 262 263 #endif /* PPI_MODULE */ 264 265 static ppi_devsw_installed = 0; 266 267 static void ppi_drvinit(void *unused) 268 { 269 dev_t dev; 270 271 if (!ppi_devsw_installed ) { 272 dev = makedev(CDEV_MAJOR, 0); 273 cdevsw_add(&dev, &ppi_cdevsw, NULL); 274 ppi_devsw_installed = 1; 275 } 276 } 277 278 SYSINIT(ppidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ppi_drvinit,NULL) 279 280 #endif /* NPPI */ 281