pcii.c revision 141123
1141121Sphk/*-
2141121Sphk * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
3141121Sphk * All rights reserved.
4141121Sphk *
5141121Sphk * Redistribution and use in source and binary forms, with or without
6141121Sphk * modification, are permitted provided that the following conditions
7141121Sphk * are met:
8141121Sphk * 1. Redistributions of source code must retain the above copyright
9141121Sphk *    notice, this list of conditions and the following disclaimer as
10141121Sphk *    the first lines of this file unmodified.
11141121Sphk * 2. Redistributions in binary form must reproduce the above copyright
12141121Sphk *    notice, this list of conditions and the following disclaimer in the
13141121Sphk *    documentation and/or other materials provided with the distribution.
14141121Sphk *
15141121Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16141121Sphk * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17141121Sphk * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18141121Sphk * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19141121Sphk * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20141121Sphk * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21141121Sphk * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22141121Sphk * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23141121Sphk * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24141121Sphk * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25141121Sphk *
26141121Sphk * Supported hardware:
27141123Sphk *    PCIIA compatible cards.
28141123Sphk *
29141123Sphk *    Tested and known working:
30141121Sphk *	"B&C Microsystems PC488A-0"
31141121Sphk *
32141121Sphk * A whole lot of wonderful things could be written for GPIB, but for now
33141121Sphk * I have just written it such that it is possible to capture data in the
34141121Sphk * mode known as "unaddressed listen only mode".  This is what many plotters
35141121Sphk * and printers do on GPIB.  This is enough to capture some output from
36141121Sphk * various test instruments.
37141121Sphk *
38141121Sphk * If you are interested in working on this, send me email.
39141121Sphk */
40141121Sphk
41141121Sphk#include <sys/cdefs.h>
42141121Sphk__FBSDID("$FreeBSD: head/sys/dev/ieee488/pcii.c 141123 2005-02-01 20:34:47Z phk $");
43141121Sphk
44141121Sphk#include <sys/param.h>
45141121Sphk#include <sys/systm.h>
46141121Sphk#include <sys/conf.h>
47141121Sphk#include <sys/malloc.h>
48141121Sphk#include <sys/kernel.h>
49141121Sphk#include <sys/module.h>
50141121Sphk#include <sys/bus.h>
51141121Sphk#include <sys/mutex.h>
52141121Sphk#include <sys/uio.h>
53141121Sphk#include <machine/bus.h>
54141121Sphk#include <machine/resource.h>
55141121Sphk#include <sys/rman.h>
56141121Sphk
57141121Sphk/* ---> upd7210.h at some point. */
58141121Sphk
59141121Sphkstruct upd7210 {
60141121Sphk	bus_space_handle_t	reg_handle[8];
61141121Sphk	bus_space_tag_t		reg_tag[8];
62141121Sphk	u_int			reg_offset[8];
63141121Sphk
64141121Sphk	/* private stuff */
65141121Sphk	struct mtx		mutex;
66141121Sphk	uint8_t			rreg[8];
67141121Sphk	uint8_t			wreg[8];
68141121Sphk
69141121Sphk	int			busy;
70141121Sphk	u_char			*buf;
71141121Sphk	size_t			bufsize;
72141121Sphk	u_int			buf_wp;
73141121Sphk	u_int			buf_rp;
74141121Sphk	struct cdev		*cdev;
75141121Sphk};
76141121Sphk
77141121Sphkstatic void upd7210intr(void *);
78141121Sphkstatic void upd7210attach(struct upd7210 *);
79141121Sphk
80141121Sphk
81141121Sphk/* ----> pcii.c */
82141121Sphk
83141121Sphkstruct pcii_softc {
84141121Sphk	int foo;
85141121Sphk	struct resource	*port[8];
86141121Sphk	struct resource	*irq;
87141121Sphk	void *intr_handler;
88141121Sphk	struct upd7210	upd7210;
89141121Sphk};
90141121Sphk
91141121Sphk#define HERE() printf("pcii HERE %s:%d\n", __FILE__, __LINE__)
92141121Sphk
93141121Sphkstatic devclass_t pcii_devclass;
94141121Sphk
95141121Sphkstatic int	pcii_probe(device_t dev);
96141121Sphkstatic int	pcii_attach(device_t dev);
97141121Sphk
98141121Sphkstatic device_method_t pcii_methods[] = {
99141121Sphk	DEVMETHOD(device_probe,		pcii_probe),
100141121Sphk	DEVMETHOD(device_attach,	pcii_attach),
101141121Sphk	DEVMETHOD(device_suspend,	bus_generic_suspend),
102141121Sphk	DEVMETHOD(device_resume,	bus_generic_resume),
103141121Sphk
104141121Sphk	{ 0, 0 }
105141121Sphk};
106141121Sphk
107141121Sphkstatic driver_t pcii_driver = {
108141121Sphk	"pcii",
109141121Sphk	pcii_methods,
110141121Sphk	sizeof(struct pcii_softc *),
111141121Sphk};
112141121Sphk
113141121Sphkstatic int
114141121Sphkpcii_probe(device_t dev)
115141121Sphk{
116141121Sphk	struct resource	*port;
117141121Sphk	int rid;
118141121Sphk	u_long start, count;
119141121Sphk	int i, j, error = 0;
120141121Sphk
121141121Sphk	device_set_desc(dev, "PCII IEEE-4888 controller");
122141121Sphk
123141121Sphk	rid = 0;
124141121Sphk	if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0)
125141121Sphk		return ENXIO;
126141121Sphk	if ((start & 0x3ff) != 0x2e1)
127141121Sphk		return (ENXIO);
128141121Sphk	count = 1;
129141121Sphk	if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0)
130141121Sphk		return ENXIO;
131141121Sphk	for (i = 0; i < 8; i++) {
132141121Sphk		j = bus_set_resource(dev, SYS_RES_IOPORT, i,
133141121Sphk		    start + 0x400 * i, 1);
134141121Sphk		if (j) {
135141121Sphk			error = ENXIO;
136141121Sphk			break;
137141121Sphk		}
138141121Sphk		rid = i;
139141121Sphk		port = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
140141121Sphk		    &rid, RF_ACTIVE);
141141121Sphk		if (port == NULL)
142141121Sphk			return (ENXIO);
143141121Sphk		else
144141121Sphk			bus_release_resource(dev, SYS_RES_IOPORT, i, port);
145141121Sphk	}
146141121Sphk
147141121Sphk	rid = 0;
148141121Sphk	port = bus_alloc_resource_any(dev,
149141121Sphk	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
150141121Sphk	if (port == NULL)
151141121Sphk		return (ENXIO);
152141121Sphk	bus_release_resource(dev, SYS_RES_IRQ, rid, port);
153141121Sphk
154141121Sphk	return (error);
155141121Sphk}
156141121Sphk
157141121Sphkstatic int
158141121Sphkpcii_attach(device_t dev)
159141121Sphk{
160141121Sphk	struct pcii_softc *sc;
161141121Sphk	int		unit;
162141121Sphk	int		rid;
163141121Sphk	int i, error = 0;
164141121Sphk
165141121Sphk	unit = device_get_unit(dev);
166141121Sphk	sc = device_get_softc(dev);
167141121Sphk	memset(sc, 0, sizeof *sc);
168141121Sphk
169141121Sphk	device_set_desc(dev, "PCII IEEE-4888 controller");
170141121Sphk
171141121Sphk	for (rid = 0; rid < 8; rid++) {
172141121Sphk		sc->port[rid] = bus_alloc_resource_any(dev,
173141121Sphk		    SYS_RES_IOPORT, &rid, RF_ACTIVE);
174141121Sphk		if (sc->port[rid] == NULL) {
175141121Sphk			error = ENXIO;
176141121Sphk			break;
177141121Sphk		}
178141121Sphk		sc->upd7210.reg_tag[rid] = rman_get_bustag(sc->port[rid]);
179141121Sphk		sc->upd7210.reg_handle[rid] = rman_get_bushandle(sc->port[rid]);
180141121Sphk	}
181141121Sphk	if (!error) {
182141121Sphk		rid = 0;
183141121Sphk		sc->irq = bus_alloc_resource_any(dev,
184141121Sphk		    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
185141121Sphk		if (sc->irq == NULL) {
186141121Sphk			error = ENXIO;
187141121Sphk		} else {
188141123Sphk			error = bus_setup_intr(dev, sc->irq,
189141123Sphk			    INTR_TYPE_MISC | INTR_MPSAFE,
190141121Sphk			    upd7210intr, &sc->upd7210, &sc->intr_handler);
191141121Sphk		}
192141121Sphk	}
193141121Sphk	if (error) {
194141121Sphkdevice_printf(dev, "error = %d\n", error);
195141121Sphk		for (i = 0; i < 8; i++) {
196141121Sphk			if (sc->port[i] == NULL)
197141121Sphk				break;
198141121Sphk			bus_release_resource(dev, SYS_RES_IOPORT,
199141121Sphk			    0, sc->port[i]);
200141121Sphk		}
201141121Sphk		if (sc->intr_handler != NULL)
202141121Sphk			bus_teardown_intr(dev, sc->irq, sc->intr_handler);
203141121Sphk		if (sc->irq != NULL)
204141121Sphk			bus_release_resource(dev, SYS_RES_IRQ, i, sc->irq);
205141121Sphk	}
206141121Sphk	upd7210attach(&sc->upd7210);
207141121Sphk	return (error);
208141121Sphk}
209141121Sphk
210141121SphkDRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0);
211141121SphkDRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0);
212141121Sphk
213141121Sphk/* ---> upd7210.c at some point */
214141121Sphk
215141121Sphkenum upd7210_wreg {
216141121Sphk	CDOR	= 0,	/* Command/data out	*/
217141121Sphk	IMR1	= 1,	/* Interrupt mask 1	*/
218141121Sphk	IMR2	= 2,	/* Interrupt mask 2	*/
219141121Sphk	SPMR	= 3,	/* Serial poll mode	*/
220141121Sphk	ADMR	= 4,	/* Address mode		*/
221141121Sphk	AUXMR	= 5,	/* Auxilliary mode	*/
222141121Sphk	ADR	= 6,	/* Address		*/
223141121Sphk	EOSR	= 7,	/* End-of-string	*/
224141121Sphk};
225141121Sphk
226141121Sphkenum upd7210_rreg {
227141121Sphk	DIR	= 0,	/* Data in		*/
228141121Sphk	ISR1	= 1,	/* Interrupt status 1	*/
229141121Sphk	ISR2	= 2,	/* Interrupt status 2	*/
230141121Sphk	SPSR	= 3,	/* Serial poll status	*/
231141121Sphk	ADSR	= 4,	/* Address status	*/
232141121Sphk	CPTR	= 5,	/* Command pass though	*/
233141121Sphk	ADR0	= 6,	/* Address 1		*/
234141121Sphk	ADR1	= 7,	/* Address 2		*/
235141121Sphk};
236141121Sphk
237141121Sphk#define AUXMR_PON        0x00
238141121Sphk#define AUXMR_CRST       0x02
239141121Sphk#define AUXMR_RFD        0x03
240141121Sphk#define AUXMR_SEOI       0x06
241141121Sphk#define AUXMR_GTS        0x10
242141121Sphk#define AUXMR_TCA        0x11
243141121Sphk#define AUXMR_TCS        0x12
244141121Sphk#define AUXMR_TCSE       0x1a
245141121Sphk#define AUXMR_DSC        0x14
246141121Sphk#define AUXMR_CIFC       0x16
247141121Sphk#define AUXMR_SIFC       0x1e
248141121Sphk#define AUXMR_CREN       0x17
249141121Sphk#define AUXMR_SREN       0x1f
250141121Sphk#define AUXMR_ICTR       0x20
251141121Sphk#define AUXMR_PPR        0x60
252141121Sphk#define AUXMR_RA         0x80
253141121Sphk#define AUXMR_RB         0xa0
254141121Sphk#define AUXMR_RE         0xc0
255141121Sphk
256141121Sphk
257141121Sphk/* upd7210 generic stuff */
258141121Sphk
259141121Sphkstatic u_int
260141121Sphkread_reg(struct upd7210 *u, enum upd7210_rreg reg)
261141121Sphk{
262141121Sphk	u_int r;
263141121Sphk
264141121Sphk	r = bus_space_read_1(
265141121Sphk	    u->reg_tag[reg],
266141121Sphk	    u->reg_handle[reg],
267141121Sphk	    u->reg_offset[reg]);
268141121Sphk	u->rreg[reg] = r;
269141121Sphk	return (r);
270141121Sphk}
271141121Sphk
272141121Sphkstatic void
273141121Sphkwrite_reg(struct upd7210 *u, enum upd7210_wreg reg, u_int val)
274141121Sphk{
275141121Sphk	bus_space_write_1(
276141121Sphk	    u->reg_tag[reg],
277141121Sphk	    u->reg_handle[reg],
278141121Sphk	    u->reg_offset[reg], val);
279141121Sphk	u->wreg[reg] = val;
280141121Sphk}
281141121Sphk
282141121Sphkstatic void
283141121Sphkupd7210intr(void *arg)
284141121Sphk{
285141121Sphk	int i;
286141121Sphk	u_int isr1, isr2;
287141121Sphk	struct upd7210 *u;
288141121Sphk
289141121Sphk	u = arg;
290141121Sphk	mtx_lock(&u->mutex);
291141121Sphk	isr1 = read_reg(u, ISR1);
292141121Sphk	isr2 = read_reg(u, ISR2);
293141121Sphk	if (isr1 & 1) {
294141121Sphk		i = read_reg(u, DIR);
295141121Sphk		u->buf[u->buf_wp++] = i;
296141121Sphk		u->buf_wp &= (u->bufsize - 1);
297141121Sphk		i = (u->buf_rp + u->bufsize - u->buf_wp) & (u->bufsize - 1);
298141121Sphk		if (i < 8)
299141121Sphk			write_reg(u, IMR1, 0);
300141121Sphk		wakeup(u->buf);
301141121Sphk	} else {
302141121Sphk		printf("upd7210intr [%02x %02x %02x",
303141121Sphk		    read_reg(u, DIR), isr1, isr2);
304141121Sphk		printf(" %02x %02x %02x %02x %02x]\n",
305141121Sphk		    read_reg(u, SPSR),
306141121Sphk		    read_reg(u, ADSR),
307141121Sphk		    read_reg(u, CPTR),
308141121Sphk		    read_reg(u, ADR0),
309141121Sphk		    read_reg(u, ADR1));
310141121Sphk	}
311141121Sphk	mtx_unlock(&u->mutex);
312141121Sphk}
313141121Sphk
314141121Sphkstatic int
315141121Sphkgpib_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
316141121Sphk{
317141121Sphk	struct upd7210 *u;
318141121Sphk
319141121Sphk	u = dev->si_drv1;
320141121Sphk
321141121Sphk	mtx_lock(&u->mutex);
322141121Sphk	if (u->busy)
323141121Sphk		return (EBUSY);
324141121Sphk	u->busy = 1;
325141121Sphk	mtx_unlock(&u->mutex);
326141121Sphk
327141121Sphk	u->buf = malloc(PAGE_SIZE, M_DEVBUF, M_WAITOK);
328141121Sphk	u->bufsize = PAGE_SIZE;
329141121Sphk	u->buf_wp = 0;
330141121Sphk	u->buf_rp = 0;
331141121Sphk
332141121Sphk	write_reg(u, AUXMR, AUXMR_CRST);
333141121Sphk	DELAY(10000);
334141121Sphk	write_reg(u, AUXMR, AUXMR_ICTR | 8);
335141121Sphk	DELAY(1000);
336141121Sphk	write_reg(u, ADR, 0x60);
337141121Sphk	write_reg(u, ADR, 0xe0);
338141121Sphk	write_reg(u, ADMR, 0x70);
339141121Sphk	write_reg(u, AUXMR, AUXMR_PON);
340141121Sphk	write_reg(u, IMR1, 0x01);
341141121Sphk	return (0);
342141121Sphk}
343141121Sphk
344141121Sphkstatic int
345141121Sphkgpib_close(struct cdev *dev, int oflags, int devtype, struct thread *td)
346141121Sphk{
347141121Sphk	struct upd7210 *u;
348141121Sphk
349141121Sphk	u = dev->si_drv1;
350141121Sphk
351141121Sphk	mtx_lock(&u->mutex);
352141121Sphk	u->busy = 0;
353141121Sphk	write_reg(u, AUXMR, AUXMR_CRST);
354141121Sphk	DELAY(10000);
355141121Sphk	write_reg(u, IMR1, 0x00);
356141121Sphk	write_reg(u, IMR2, 0x00);
357141121Sphk	free(u->buf, M_DEVBUF);
358141121Sphk	u->buf = NULL;
359141121Sphk	mtx_unlock(&u->mutex);
360141121Sphk	return (0);
361141121Sphk}
362141121Sphk
363141121Sphkstatic int
364141121Sphkgpib_read(struct cdev *dev, struct uio *uio, int ioflag)
365141121Sphk{
366141121Sphk	struct upd7210 *u;
367141121Sphk	int error;
368141121Sphk	size_t z;
369141121Sphk
370141121Sphk	u = dev->si_drv1;
371141121Sphk	error = 0;
372141121Sphk
373141121Sphk	mtx_lock(&u->mutex);
374141121Sphk	while (u->buf_wp == u->buf_rp) {
375141121Sphk		error = msleep(u->buf, &u->mutex, PZERO | PCATCH,
376141121Sphk		    "gpibrd", hz);
377141121Sphk		if (error && error != EWOULDBLOCK) {
378141121Sphk			mtx_unlock(&u->mutex);
379141121Sphk			return (error);
380141121Sphk		}
381141121Sphk	}
382141121Sphk	while (uio->uio_resid > 0 && u->buf_wp != u->buf_rp) {
383141121Sphk		if (u->buf_wp < u->buf_rp)
384141121Sphk			z = u->bufsize - u->buf_rp;
385141121Sphk		else
386141121Sphk			z = u->buf_wp - u->buf_rp;
387141121Sphk		if (z > uio->uio_resid)
388141121Sphk			z = uio->uio_resid;
389141121Sphk		mtx_unlock(&u->mutex);
390141121Sphk		error = uiomove(u->buf + u->buf_rp, z, uio);
391141121Sphk		mtx_lock(&u->mutex);
392141121Sphk		if (error)
393141121Sphk			break;
394141121Sphk		u->buf_rp += z;
395141121Sphk		u->buf_rp &= (u->bufsize - 1);
396141121Sphk	}
397141121Sphk	if (u->wreg[IMR1] == 0)
398141121Sphk		write_reg(u, IMR1, 0x01);
399141121Sphk	mtx_unlock(&u->mutex);
400141121Sphk	return (error);
401141121Sphk}
402141121Sphk
403141121Sphk
404141121Sphk
405141121Sphkstruct cdevsw gpib_cdevsw = {
406141121Sphk	.d_version =	D_VERSION,
407141121Sphk	.d_name =	"gpib",
408141121Sphk	.d_open	=	gpib_open,
409141121Sphk	.d_close =	gpib_close,
410141121Sphk	.d_read =	gpib_read,
411141121Sphk};
412141121Sphk
413141121Sphkstatic void
414141121Sphkupd7210attach(struct upd7210 *u)
415141121Sphk{
416141121Sphk	int unit = 0;
417141121Sphk
418141121Sphk	mtx_init(&u->mutex, "gpib", NULL, MTX_DEF);
419141121Sphk	u->cdev = make_dev(&gpib_cdevsw, unit,
420141121Sphk	    UID_ROOT, GID_WHEEL, 0444,
421141121Sphk	    "gpib%ul", unit);
422141121Sphk	u->cdev->si_drv1 = u;
423141121Sphk}
424