xref: /freebsd/sys/dev/ppbus/ppi.c (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
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