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