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.7 1998/06/07 17:09:49 dfr 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 /* 120 * Report ourselves 121 */ 122 printf("ppi%d: <generic parallel i/o> on ppbus %d\n", 123 dev->id_unit, dev->ppb->ppb_link->adapter_unit); 124 125 return (1); 126 } 127 128 static void 129 ppiintr(int unit) 130 { 131 return; 132 } 133 134 static int 135 ppiopen(dev_t dev, int flags, int fmt, struct proc *p) 136 { 137 u_int unit = minor(dev); 138 struct ppi_data *ppi = ppidata[unit]; 139 int res; 140 141 if (unit >= nppi) 142 return (ENXIO); 143 144 if (!(ppi->ppi_flags & HAVE_PPBUS)) 145 if ((res = ppb_request_bus(&ppi->ppi_dev, (flags & O_NONBLOCK) ? PPB_DONTWAIT : (PPB_WAIT | PPB_INTR)))) 146 return (res); 147 148 ppi->ppi_flags |= HAVE_PPBUS; 149 return (0); 150 } 151 152 static int 153 ppiclose(dev_t dev, int flags, int fmt, struct proc *p) 154 { 155 u_int unit = minor(dev); 156 struct ppi_data *ppi = ppidata[unit]; 157 158 if (ppi->ppi_flags & HAVE_PPBUS) 159 ppb_release_bus(&ppi->ppi_dev); 160 ppi->ppi_flags &= ~HAVE_PPBUS; 161 return (0); 162 } 163 164 static int 165 ppiioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 166 { 167 u_int unit = minor(dev); 168 struct ppi_data *ppi = ppidata[unit]; 169 int error = 0; 170 u_int8_t *val = (u_int8_t *)data; 171 172 switch (cmd) { 173 174 case PPIGDATA: /* get data register */ 175 *val = ppb_rdtr(&ppi->ppi_dev); 176 break; 177 case PPIGSTATUS: /* get status bits */ 178 *val = ppb_rstr(&ppi->ppi_dev); 179 break; 180 case PPIGCTRL: /* get control bits */ 181 *val = ppb_rctr(&ppi->ppi_dev); 182 break; 183 case PPIGEPP: /* get EPP bits */ 184 *val = ppb_repp(&ppi->ppi_dev); 185 break; 186 case PPIGECR: /* get ECP bits */ 187 *val = ppb_recr(&ppi->ppi_dev); 188 break; 189 case PPIGFIFO: /* read FIFO */ 190 *val = ppb_rfifo(&ppi->ppi_dev); 191 break; 192 193 case PPISDATA: /* set data register */ 194 ppb_wdtr(&ppi->ppi_dev, *val); 195 break; 196 case PPISSTATUS: /* set status bits */ 197 ppb_wstr(&ppi->ppi_dev, *val); 198 break; 199 case PPISCTRL: /* set control bits */ 200 ppb_wctr(&ppi->ppi_dev, *val); 201 break; 202 case PPISEPP: /* set EPP bits */ 203 ppb_wepp(&ppi->ppi_dev, *val); 204 break; 205 case PPISECR: /* set ECP bits */ 206 ppb_wecr(&ppi->ppi_dev, *val); 207 break; 208 case PPISFIFO: /* write FIFO */ 209 ppb_wfifo(&ppi->ppi_dev, *val); 210 break; 211 212 default: 213 error = ENOTTY; 214 break; 215 } 216 217 return (error); 218 } 219 220 #ifdef PPI_MODULE 221 222 MOD_DEV(ppi, LM_DT_CHAR, CDEV_MAJOR, &ppi_cdevsw); 223 224 static int 225 ppi_load(struct lkm_table *lkmtp, int cmd) 226 { 227 struct ppb_data *ppb; 228 struct ppb_device *dev; 229 int i; 230 231 for (ppb = ppb_next_bus(NULL); ppb; ppb = ppb_next_bus(ppb)) { 232 233 dev = ppiprobe(ppb); 234 ppiattach(dev); 235 236 ppb_attach_device(dev); 237 } 238 239 return (0); 240 } 241 242 static int 243 ppi_unload(struct lkm_table *lkmtp, int cmd) 244 { 245 int i; 246 247 for (i = nppi-1; i > 0; i--) { 248 ppb_remove_device(&ppidata[i]->ppi_dev); 249 free(ppidata[i], M_TEMP); 250 } 251 252 return (0); 253 } 254 255 int 256 ppi_mod(struct lkm_table *lkmtp, int cmd, int ver) 257 { 258 DISPATCH(lkmtp, cmd, ver, ppi_load, ppi_unload, lkm_nullcmd); 259 } 260 261 #endif /* PPI_MODULE */ 262 263 static ppi_devsw_installed = 0; 264 265 static void ppi_drvinit(void *unused) 266 { 267 dev_t dev; 268 269 if (!ppi_devsw_installed ) { 270 dev = makedev(CDEV_MAJOR, 0); 271 cdevsw_add(&dev, &ppi_cdevsw, NULL); 272 ppi_devsw_installed = 1; 273 } 274 } 275 276 SYSINIT(ppidev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ppi_drvinit,NULL) 277 278 #endif /* NPPI */ 279