View | Details | Raw Unified | Return to bug 20338
Collapse All | Expand All

(-)sio_pci.c (+277 lines)
Added Link Here
1
/*
2
 * Serial driver for non-intelligent PCI multiport adapters.
3
 * Implements the probe, attach and interrupt dispatcher,
4
 * and uses sio.c for the most part of work.
5
 * The PCI ports get unit numbers _after_ the ISA sio ports.
6
 * Option COM_MULTIPORT is not necessary.
7
 *
8
 * Copyright (C) 2000 Cronyx Engineering Ltd.
9
 * Author: Serge Vakulenko <vak@cronyx.ru>
10
 *
11
 * Supports:
12
 *	Cronyx Omega-PCI adapter, by Serge Vakulenko <vak@cronyx.ru>
13
 *
14
 * This software is distributed with NO WARRANTIES, not even the implied
15
 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
 *
17
 * Authors grant any other persons or organisations permission to use
18
 * or modify this software as long as this message is kept with the software,
19
 * all derivative works or modified versions.
20
 */
21
#include <sys/param.h>
22
#include <sys/systm.h>
23
#include <sys/kernel.h>
24
#include <sys/timepps.h>
25
#include <sys/tty.h>
26
#include <vm/vm.h>
27
#include <vm/pmap.h>
28
#include <machine/bus.h>
29
#ifndef SMP
30
#include <machine/lock.h>
31
#endif
32
#include <machine/resource.h>
33
#include <sys/bus.h>
34
#include <sys/rman.h>
35
#include <pci/pcivar.h>
36
#if __FreeBSD_version >= 400000
37
#include <isa/siovar.h>
38
#include <isa/sioreg.h>
39
#else
40
#include <sys/malloc.h>
41
#include <sys/interrupt.h>
42
#include <i386/isa/siovar.h>
43
#include <i386/isa/sioreg.h>
44
#endif
45
#include <isa/ic/ns16550.h>
46
47
#include "sio.h"
48
49
#define MAXCHAN		8
50
51
#ifndef __i386__
52
#define disable_intr()
53
#define enable_intr()
54
#endif
55
56
#ifdef SMP
57
#define disable_intr()	COM_DISABLE_INTR()
58
#define enable_intr()	COM_ENABLE_INTR()
59
#endif /* SMP */
60
61
typedef struct _sio_pci_t {
62
	int		nchan;
63
	int		fifo_size;
64
	int		base_reg;
65
	int		hw_rts_cts;
66
	Port_t		iobase;
67
	Port_t		iostep;
68
	struct resource	*res;
69
	struct resource	*irq;
70
	void		*intrhand;
71
	struct com_s	com [MAXCHAN];
72
} sio_pci_t;
73
74
static void sio_pci_intr	__P((void *arg));
75
76
static int sio_pci_numunits = NSIO;
77
78
#if __FreeBSD_version >= 400000
79
/*
80
 * FreeBSD version 4.x
81
 */
82
static int sio_pci_probe	__P((device_t));
83
static int sio_pci_attach	__P((device_t));
84
85
static devclass_t siopci_devclass;
86
87
static device_method_t sio_pci_methods[] = {
88
	/* Device interface */
89
	DEVMETHOD(device_probe,		sio_pci_probe),
90
	DEVMETHOD(device_attach,	sio_pci_attach),
91
	{ 0, 0 }
92
};
93
94
static driver_t sio_pci_driver = {
95
	"siopci",
96
	sio_pci_methods,
97
	sizeof(sio_pci_t)
98
};
99
DRIVER_MODULE(sio_pci, pci, sio_pci_driver, siopci_devclass, 0, 0);
100
101
#else
102
/*
103
 * FreeBSD version 3.x
104
 */
105
static const char *sio_pci_probe	__P((pcici_t, pcidi_t));
106
static void sio_pci_attach		__P((pcici_t, int));
107
108
static u_long sio_pci_count;
109
110
static struct pci_device sio_pci_device = {
111
        "siopci",
112
        sio_pci_probe,
113
        sio_pci_attach,
114
        &sio_pci_count,
115
        NULL
116
};
117
DATA_SET(pcidevice_set, sio_pci_device);
118
119
#endif /* __FreeBSD_version >= 400000 */
120
121
#if __FreeBSD_version >= 400000
122
static int
123
sio_pci_probe(dev)
124
	device_t	dev;
125
{
126
	u_long device_id = pci_get_vendor(dev) | pci_get_device(dev) << 16;
127
#else
128
static const char *
129
sio_pci_probe(config_id, device_id)
130
	pcici_t config_id;
131
	pcidi_t device_id;
132
{
133
#endif
134
	const char *desc = 0;
135
136
	if (device_id == 0xc00110b5)
137
		desc = "Cronyx-Omega-PCI Serial Adapter";
138
#ifdef notyet
139
	/* Add your device here. */
140
	else if (device_id == 0xXXXXXXXX)
141
		desc = "XXX";
142
#endif
143
144
#if __FreeBSD_version >= 400000
145
	if (! desc)
146
		return ENXIO;
147
	device_set_desc(dev, desc);
148
	return 0;
149
#else
150
	return desc;
151
#endif
152
}
153
154
#if __FreeBSD_version >= 400000
155
static int
156
sio_pci_attach(dev)
157
	device_t	dev;
158
{
159
	u_long		device_id = pci_get_vendor(dev) |
160
				    pci_get_device(dev) << 16;
161
	sio_pci_t	*d = device_get_softc(dev);
162
	int		rid;
163
#define PCI_READ_CONFIG(reg) pci_read_config(dev, reg, 4)
164
#else
165
static void
166
sio_pci_attach(config_id, unit)
167
	pcici_t config_id;
168
	int unit;
169
{
170
	u_long device_id = config_id->vendor | config_id->device << 16;
171
	sio_pci_t	*d = malloc(sizeof *d, M_DEVBUF, M_WAITOK);
172
#define PCI_READ_CONFIG(reg) pci_conf_read(config_id, reg)
173
#endif
174
	struct com_s	*com;
175
	int		s, err = 0;
176
177
	bzero((char*)d, sizeof(*d));
178
	s = splimp();
179
180
	/* Default values. */
181
	d->nchan = 8;			/* channels per adapter */
182
	d->iostep = 8;			/* addresses per channel */
183
	d->base_reg = 0x18;		/* pci register: base addr2 */
184
185
	/* Device dependent values. */
186
	if (device_id == 0xc00110b5) {
187
		d->fifo_size = 64;	/* fifo size in bytes */
188
		d->hw_rts_cts = 1;	/* hardware rts/cts support */
189
	}
190
#ifdef notyet
191
	else if (device_id == 0xXXXXXXXX) {
192
		/* Add your device here. */
193
	}
194
#endif
195
196
#if __FreeBSD_version >= 400000
197
	/* Allocate i/o region. */
198
	rid = d->base_reg;
199
	d->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1,
200
		RF_ACTIVE);
201
	if (! d->res) {
202
		printf("sio%d: couldn't map ports/memory\n", sio_pci_numunits);
203
		err = ENXIO;
204
		goto fail;
205
	}
206
207
	/* Allocate interrupt. */
208
	rid = 0;
209
	d->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
210
		RF_SHAREABLE | RF_ACTIVE);
211
	if (! d->irq) {
212
		printf("sio%d: couldn't map interrupt\n", sio_pci_numunits);
213
		err = ENXIO;
214
		goto fail;
215
	}
216
217
	/* Register the interrupt handler. */
218
	err = bus_setup_intr(dev, d->irq, INTR_TYPE_TTY | INTR_TYPE_FAST,
219
		sio_pci_intr, d, &d->intrhand);
220
#else
221
	err = ! pci_map_int_right(config_id, sio_pci_intr, d, &tty_imask,
222
		INTR_FAST);
223
#endif
224
	if (err) {
225
		printf("sio%d: couldn't set up irq\n", sio_pci_numunits);
226
#if __FreeBSD_version >= 400000
227
fail:		if (d->res)
228
			bus_release_resource(dev, SYS_RES_IOPORT,
229
				d->base_reg, d->res);
230
		if (d->irq)
231
			bus_release_resource(dev, SYS_RES_IRQ, 0, d->irq);
232
#endif
233
		goto done;
234
	}
235
236
	/* Attach sio ports. */
237
	d->iobase = PCI_READ_CONFIG (d->base_reg) & ~3;
238
	for (com=d->com; com<d->com+d->nchan; ++com) {
239
		com->iobase = d->iobase + (com - d->com) * d->iostep;
240
241
		/* Interrupt enable, do it _before_ sio_attach_unit. */
242
		outb(com->iobase + com_mcr, MCR_IENABLE);
243
244
		if (sio_attach_unit(com, sio_pci_numunits++, com->iobase,
245
		    d->fifo_size << 24, 0) != 0)
246
			printf("sio%d: cannot attach\n", sio_pci_numunits);
247
248
		/* Must do this _after_ sio_attach_unit. */
249
		com->st16650a = d->hw_rts_cts;
250
	}
251
done:
252
	splx (s);
253
#if __FreeBSD_version >= 400000
254
	return err;
255
#endif
256
}
257
258
static void
259
sio_pci_intr(arg)
260
	void		*arg;
261
{
262
	sio_pci_t	*d = arg;
263
	struct com_s	*com;
264
	bool_t		possibly_more_intrs;
265
266
	disable_intr();
267
	do {
268
		possibly_more_intrs = FALSE;
269
		for (com=d->com; com<d->com+d->nchan; ++com) {
270
			if ((inb(com->int_id_port) & IIR_IMASK) != IIR_NOPEND) {
271
				siointr1(com);
272
				possibly_more_intrs = TRUE;
273
			}
274
		}
275
	} while (possibly_more_intrs);
276
	enable_intr();
277
}

Return to bug 20338