pcii.c revision 141121
1254721Semaste/*-
2254721Semaste * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
3254721Semaste * All rights reserved.
4254721Semaste *
5254721Semaste * Redistribution and use in source and binary forms, with or without
6254721Semaste * modification, are permitted provided that the following conditions
7254721Semaste * are met:
8254721Semaste * 1. Redistributions of source code must retain the above copyright
9254721Semaste *    notice, this list of conditions and the following disclaimer as
10254721Semaste *    the first lines of this file unmodified.
11254721Semaste * 2. Redistributions in binary form must reproduce the above copyright
12254721Semaste *    notice, this list of conditions and the following disclaimer in the
13254721Semaste *    documentation and/or other materials provided with the distribution.
14254721Semaste *
15254721Semaste * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16254721Semaste * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17254721Semaste * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18254721Semaste * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19254721Semaste * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20254721Semaste * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21254721Semaste * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22254721Semaste * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23254721Semaste * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24254721Semaste * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25254721Semaste *
26254721Semaste * Supported hardware:
27254721Semaste *	"B&C Microsystems PC488A-0"
28254721Semaste *
29254721Semaste * A whole lot of wonderful things could be written for GPIB, but for now
30254721Semaste * I have just written it such that it is possible to capture data in the
31254721Semaste * mode known as "unaddressed listen only mode".  This is what many plotters
32254721Semaste * and printers do on GPIB.  This is enough to capture some output from
33254721Semaste * various test instruments.
34254721Semaste *
35254721Semaste * If you are interested in working on this, send me email.
36254721Semaste */
37254721Semaste
38254721Semaste#include <sys/cdefs.h>
39254721Semaste__FBSDID("$FreeBSD: head/sys/dev/ieee488/pcii.c 141121 2005-02-01 16:59:23Z phk $");
40254721Semaste
41254721Semaste#include <sys/param.h>
42254721Semaste#include <sys/systm.h>
43254721Semaste#include <sys/conf.h>
44254721Semaste#include <sys/malloc.h>
45254721Semaste#include <sys/kernel.h>
46254721Semaste#include <sys/module.h>
47254721Semaste#include <sys/bus.h>
48254721Semaste#include <sys/mutex.h>
49254721Semaste#include <sys/uio.h>
50254721Semaste#include <machine/bus.h>
51254721Semaste#include <machine/resource.h>
52254721Semaste#include <sys/rman.h>
53254721Semaste
54254721Semaste/* ---> upd7210.h at some point. */
55254721Semaste
56254721Semastestruct upd7210 {
57254721Semaste	bus_space_handle_t	reg_handle[8];
58254721Semaste	bus_space_tag_t		reg_tag[8];
59254721Semaste	u_int			reg_offset[8];
60254721Semaste
61254721Semaste	/* private stuff */
62254721Semaste	struct mtx		mutex;
63254721Semaste	uint8_t			rreg[8];
64254721Semaste	uint8_t			wreg[8];
65254721Semaste
66254721Semaste	int			busy;
67254721Semaste	u_char			*buf;
68254721Semaste	size_t			bufsize;
69254721Semaste	u_int			buf_wp;
70254721Semaste	u_int			buf_rp;
71254721Semaste	struct cdev		*cdev;
72254721Semaste};
73254721Semaste
74254721Semastestatic void upd7210intr(void *);
75254721Semastestatic void upd7210attach(struct upd7210 *);
76254721Semaste
77254721Semaste
78254721Semaste/* ----> pcii.c */
79254721Semaste
80254721Semastestruct pcii_softc {
81254721Semaste	int foo;
82254721Semaste	struct resource	*port[8];
83254721Semaste	struct resource	*irq;
84254721Semaste	void *intr_handler;
85254721Semaste	struct upd7210	upd7210;
86254721Semaste};
87254721Semaste
88254721Semaste#define HERE() printf("pcii HERE %s:%d\n", __FILE__, __LINE__)
89254721Semaste
90254721Semastestatic devclass_t pcii_devclass;
91254721Semaste
92254721Semastestatic int	pcii_probe(device_t dev);
93254721Semastestatic int	pcii_attach(device_t dev);
94254721Semaste
95254721Semastestatic device_method_t pcii_methods[] = {
96254721Semaste	DEVMETHOD(device_probe,		pcii_probe),
97254721Semaste	DEVMETHOD(device_attach,	pcii_attach),
98254721Semaste	DEVMETHOD(device_suspend,	bus_generic_suspend),
99254721Semaste	DEVMETHOD(device_resume,	bus_generic_resume),
100254721Semaste
101254721Semaste	{ 0, 0 }
102254721Semaste};
103254721Semaste
104254721Semastestatic driver_t pcii_driver = {
105254721Semaste	"pcii",
106254721Semaste	pcii_methods,
107254721Semaste	sizeof(struct pcii_softc *),
108254721Semaste};
109254721Semaste
110254721Semastestatic int
111254721Semastepcii_probe(device_t dev)
112254721Semaste{
113254721Semaste	struct resource	*port;
114254721Semaste	int rid;
115254721Semaste	u_long start, count;
116254721Semaste	int i, j, error = 0;
117254721Semaste
118254721Semaste	device_set_desc(dev, "PCII IEEE-4888 controller");
119254721Semaste
120254721Semaste	rid = 0;
121254721Semaste	if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0)
122254721Semaste		return ENXIO;
123254721Semaste	if ((start & 0x3ff) != 0x2e1)
124254721Semaste		return (ENXIO);
125254721Semaste	count = 1;
126254721Semaste	if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0)
127254721Semaste		return ENXIO;
128254721Semaste	for (i = 0; i < 8; i++) {
129254721Semaste		j = bus_set_resource(dev, SYS_RES_IOPORT, i,
130254721Semaste		    start + 0x400 * i, 1);
131254721Semaste		if (j) {
132254721Semaste			error = ENXIO;
133254721Semaste			break;
134254721Semaste		}
135254721Semaste		rid = i;
136254721Semaste		port = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
137254721Semaste		    &rid, RF_ACTIVE);
138254721Semaste		if (port == NULL)
139254721Semaste			return (ENXIO);
140254721Semaste		else
141254721Semaste			bus_release_resource(dev, SYS_RES_IOPORT, i, port);
142254721Semaste	}
143254721Semaste
144254721Semaste	rid = 0;
145254721Semaste	port = bus_alloc_resource_any(dev,
146254721Semaste	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
147254721Semaste	if (port == NULL)
148254721Semaste		return (ENXIO);
149254721Semaste	bus_release_resource(dev, SYS_RES_IRQ, rid, port);
150254721Semaste
151254721Semaste	return (error);
152254721Semaste}
153254721Semaste
154254721Semastestatic int
155254721Semastepcii_attach(device_t dev)
156254721Semaste{
157254721Semaste	struct pcii_softc *sc;
158254721Semaste	int		unit;
159254721Semaste	int		rid;
160254721Semaste	int i, error = 0;
161254721Semaste
162254721Semaste	unit = device_get_unit(dev);
163254721Semaste	sc = device_get_softc(dev);
164254721Semaste	memset(sc, 0, sizeof *sc);
165254721Semaste
166254721Semaste	device_set_desc(dev, "PCII IEEE-4888 controller");
167254721Semaste
168254721Semaste	for (rid = 0; rid < 8; rid++) {
169254721Semaste		sc->port[rid] = bus_alloc_resource_any(dev,
170254721Semaste		    SYS_RES_IOPORT, &rid, RF_ACTIVE);
171254721Semaste		if (sc->port[rid] == NULL) {
172254721Semaste			error = ENXIO;
173254721Semaste			break;
174254721Semaste		}
175254721Semaste		sc->upd7210.reg_tag[rid] = rman_get_bustag(sc->port[rid]);
176254721Semaste		sc->upd7210.reg_handle[rid] = rman_get_bushandle(sc->port[rid]);
177254721Semaste	}
178254721Semaste	if (!error) {
179254721Semaste		rid = 0;
180254721Semaste		sc->irq = bus_alloc_resource_any(dev,
181254721Semaste		    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
182254721Semaste		if (sc->irq == NULL) {
183254721Semaste			error = ENXIO;
184254721Semaste		} else {
185254721Semaste			error = bus_setup_intr(dev, sc->irq, INTR_TYPE_MISC,
186254721Semaste			    upd7210intr, &sc->upd7210, &sc->intr_handler);
187254721Semaste		}
188254721Semaste	}
189254721Semaste	if (error) {
190254721Semastedevice_printf(dev, "error = %d\n", error);
191254721Semaste		for (i = 0; i < 8; i++) {
192254721Semaste			if (sc->port[i] == NULL)
193254721Semaste				break;
194254721Semaste			bus_release_resource(dev, SYS_RES_IOPORT,
195254721Semaste			    0, sc->port[i]);
196254721Semaste		}
197254721Semaste		if (sc->intr_handler != NULL)
198254721Semaste			bus_teardown_intr(dev, sc->irq, sc->intr_handler);
199254721Semaste		if (sc->irq != NULL)
200254721Semaste			bus_release_resource(dev, SYS_RES_IRQ, i, sc->irq);
201254721Semaste	}
202254721Semaste	upd7210attach(&sc->upd7210);
203254721Semaste	return (error);
204254721Semaste}
205254721Semaste
206254721SemasteDRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0);
207254721SemasteDRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0);
208254721Semaste
209254721Semaste/* ---> upd7210.c at some point */
210254721Semaste
211254721Semasteenum upd7210_wreg {
212254721Semaste	CDOR	= 0,	/* Command/data out	*/
213254721Semaste	IMR1	= 1,	/* Interrupt mask 1	*/
214254721Semaste	IMR2	= 2,	/* Interrupt mask 2	*/
215254721Semaste	SPMR	= 3,	/* Serial poll mode	*/
216254721Semaste	ADMR	= 4,	/* Address mode		*/
217254721Semaste	AUXMR	= 5,	/* Auxilliary mode	*/
218254721Semaste	ADR	= 6,	/* Address		*/
219254721Semaste	EOSR	= 7,	/* End-of-string	*/
220254721Semaste};
221254721Semaste
222254721Semasteenum upd7210_rreg {
223254721Semaste	DIR	= 0,	/* Data in		*/
224254721Semaste	ISR1	= 1,	/* Interrupt status 1	*/
225254721Semaste	ISR2	= 2,	/* Interrupt status 2	*/
226254721Semaste	SPSR	= 3,	/* Serial poll status	*/
227254721Semaste	ADSR	= 4,	/* Address status	*/
228254721Semaste	CPTR	= 5,	/* Command pass though	*/
229254721Semaste	ADR0	= 6,	/* Address 1		*/
230254721Semaste	ADR1	= 7,	/* Address 2		*/
231254721Semaste};
232254721Semaste
233254721Semaste#define AUXMR_PON        0x00
234254721Semaste#define AUXMR_CRST       0x02
235254721Semaste#define AUXMR_RFD        0x03
236254721Semaste#define AUXMR_SEOI       0x06
237254721Semaste#define AUXMR_GTS        0x10
238254721Semaste#define AUXMR_TCA        0x11
239254721Semaste#define AUXMR_TCS        0x12
240254721Semaste#define AUXMR_TCSE       0x1a
241254721Semaste#define AUXMR_DSC        0x14
242254721Semaste#define AUXMR_CIFC       0x16
243254721Semaste#define AUXMR_SIFC       0x1e
244254721Semaste#define AUXMR_CREN       0x17
245254721Semaste#define AUXMR_SREN       0x1f
246254721Semaste#define AUXMR_ICTR       0x20
247254721Semaste#define AUXMR_PPR        0x60
248254721Semaste#define AUXMR_RA         0x80
249254721Semaste#define AUXMR_RB         0xa0
250254721Semaste#define AUXMR_RE         0xc0
251254721Semaste
252254721Semaste
253254721Semaste/* upd7210 generic stuff */
254254721Semaste
255254721Semastestatic u_int
256254721Semasteread_reg(struct upd7210 *u, enum upd7210_rreg reg)
257254721Semaste{
258254721Semaste	u_int r;
259254721Semaste
260254721Semaste	r = bus_space_read_1(
261254721Semaste	    u->reg_tag[reg],
262254721Semaste	    u->reg_handle[reg],
263254721Semaste	    u->reg_offset[reg]);
264254721Semaste	u->rreg[reg] = r;
265254721Semaste	return (r);
266254721Semaste}
267254721Semaste
268254721Semastestatic void
269254721Semastewrite_reg(struct upd7210 *u, enum upd7210_wreg reg, u_int val)
270254721Semaste{
271254721Semaste	bus_space_write_1(
272254721Semaste	    u->reg_tag[reg],
273254721Semaste	    u->reg_handle[reg],
274254721Semaste	    u->reg_offset[reg], val);
275254721Semaste	u->wreg[reg] = val;
276254721Semaste}
277254721Semaste
278254721Semastestatic void
279254721Semasteupd7210intr(void *arg)
280254721Semaste{
281254721Semaste	int i;
282254721Semaste	u_int isr1, isr2;
283254721Semaste	struct upd7210 *u;
284254721Semaste
285254721Semaste	u = arg;
286254721Semaste	mtx_lock(&u->mutex);
287254721Semaste	isr1 = read_reg(u, ISR1);
288254721Semaste	isr2 = read_reg(u, ISR2);
289254721Semaste	if (isr1 & 1) {
290254721Semaste		i = read_reg(u, DIR);
291254721Semaste		u->buf[u->buf_wp++] = i;
292254721Semaste		u->buf_wp &= (u->bufsize - 1);
293254721Semaste		i = (u->buf_rp + u->bufsize - u->buf_wp) & (u->bufsize - 1);
294254721Semaste		if (i < 8)
295254721Semaste			write_reg(u, IMR1, 0);
296254721Semaste		wakeup(u->buf);
297254721Semaste	} else {
298254721Semaste		printf("upd7210intr [%02x %02x %02x",
299254721Semaste		    read_reg(u, DIR), isr1, isr2);
300254721Semaste		printf(" %02x %02x %02x %02x %02x]\n",
301254721Semaste		    read_reg(u, SPSR),
302254721Semaste		    read_reg(u, ADSR),
303254721Semaste		    read_reg(u, CPTR),
304254721Semaste		    read_reg(u, ADR0),
305254721Semaste		    read_reg(u, ADR1));
306254721Semaste	}
307254721Semaste	mtx_unlock(&u->mutex);
308254721Semaste}
309254721Semaste
310254721Semastestatic int
311254721Semastegpib_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
312254721Semaste{
313254721Semaste	struct upd7210 *u;
314254721Semaste
315254721Semaste	u = dev->si_drv1;
316254721Semaste
317254721Semaste	mtx_lock(&u->mutex);
318254721Semaste	if (u->busy)
319254721Semaste		return (EBUSY);
320254721Semaste	u->busy = 1;
321254721Semaste	mtx_unlock(&u->mutex);
322254721Semaste
323254721Semaste	u->buf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
324254721Semaste	u->bufsize = PAGE_SIZE;
325254721Semaste	u->buf_wp = 0;
326254721Semaste	u->buf_rp = 0;
327254721Semaste
328254721Semaste	write_reg(u, AUXMR, AUXMR_CRST);
329254721Semaste	DELAY(10000);
330254721Semaste	write_reg(u, AUXMR, AUXMR_ICTR | 8);
331254721Semaste	DELAY(1000);
332254721Semaste	write_reg(u, ADR, 0x60);
333254721Semaste	write_reg(u, ADR, 0xe0);
334254721Semaste	write_reg(u, ADMR, 0x70);
335254721Semaste	write_reg(u, AUXMR, AUXMR_PON);
336254721Semaste	write_reg(u, IMR1, 0x01);
337254721Semaste	return (0);
338254721Semaste}
339254721Semaste
340254721Semastestatic int
341254721Semastegpib_close(struct cdev *dev, int oflags, int devtype, struct thread *td)
342254721Semaste{
343254721Semaste	struct upd7210 *u;
344254721Semaste
345254721Semaste	u = dev->si_drv1;
346254721Semaste
347254721Semaste	mtx_lock(&u->mutex);
348254721Semaste	u->busy = 0;
349254721Semaste	write_reg(u, AUXMR, AUXMR_CRST);
350254721Semaste	DELAY(10000);
351254721Semaste	write_reg(u, IMR1, 0x00);
352254721Semaste	write_reg(u, IMR2, 0x00);
353254721Semaste	free(u->buf, M_DEVBUF);
354254721Semaste	u->buf = NULL;
355254721Semaste	mtx_unlock(&u->mutex);
356254721Semaste	return (0);
357254721Semaste}
358254721Semaste
359254721Semastestatic int
360254721Semastegpib_read(struct cdev *dev, struct uio *uio, int ioflag)
361254721Semaste{
362254721Semaste	struct upd7210 *u;
363254721Semaste	int error;
364254721Semaste	size_t z;
365254721Semaste
366254721Semaste	u = dev->si_drv1;
367254721Semaste	error = 0;
368254721Semaste
369254721Semaste	mtx_lock(&u->mutex);
370254721Semaste	while (u->buf_wp == u->buf_rp) {
371254721Semaste		error = msleep(u->buf, &u->mutex, PZERO | PCATCH,
372254721Semaste		    "gpibrd", hz);
373254721Semaste		if (error && error != EWOULDBLOCK) {
374254721Semaste			mtx_unlock(&u->mutex);
375254721Semaste			return (error);
376254721Semaste		}
377254721Semaste	}
378254721Semaste	while (uio->uio_resid > 0 && u->buf_wp != u->buf_rp) {
379254721Semaste		if (u->buf_wp < u->buf_rp)
380254721Semaste			z = u->bufsize - u->buf_rp;
381254721Semaste		else
382254721Semaste			z = u->buf_wp - u->buf_rp;
383254721Semaste		if (z > uio->uio_resid)
384254721Semaste			z = uio->uio_resid;
385254721Semaste		mtx_unlock(&u->mutex);
386254721Semaste		error = uiomove(u->buf + u->buf_rp, z, uio);
387254721Semaste		mtx_lock(&u->mutex);
388254721Semaste		if (error)
389254721Semaste			break;
390254721Semaste		u->buf_rp += z;
391254721Semaste		u->buf_rp &= (u->bufsize - 1);
392254721Semaste	}
393254721Semaste	if (u->wreg[IMR1] == 0)
394254721Semaste		write_reg(u, IMR1, 0x01);
395254721Semaste	mtx_unlock(&u->mutex);
396254721Semaste	return (error);
397254721Semaste}
398254721Semaste
399254721Semaste
400254721Semaste
401254721Semastestruct cdevsw gpib_cdevsw = {
402254721Semaste	.d_version =	D_VERSION,
403254721Semaste	.d_name =	"gpib",
404254721Semaste	.d_open	=	gpib_open,
405254721Semaste	.d_close =	gpib_close,
406254721Semaste	.d_read =	gpib_read,
407254721Semaste};
408254721Semaste
409254721Semastestatic void
410254721Semasteupd7210attach(struct upd7210 *u)
411254721Semaste{
412254721Semaste	int unit = 0;
413254721Semaste
414254721Semaste	mtx_init(&u->mutex, "gpib", NULL, MTX_DEF);
415254721Semaste	u->cdev = make_dev(&gpib_cdevsw, unit,
416254721Semaste	    UID_ROOT, GID_WHEEL, 0444,
417254721Semaste	    "gpib%ul", unit);
418254721Semaste	u->cdev->si_drv1 = u;
419254721Semaste}
420254721Semaste