ncr53c500_pccard.c revision 73280
1/*	$FreeBSD: head/sys/dev/ncv/ncr53c500_pccard.c 73280 2001-03-01 17:09:09Z markm $	*/
2/*	$NecBSD: ncr53c500_pisa.c,v 1.28 1998/11/26 01:59:11 honda Exp $	*/
3/*	$NetBSD$	*/
4
5/*
6 * [Ported for FreeBSD]
7 *  Copyright (c) 2000
8 *      Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe.
9 *      All rights reserved.
10 * [NetBSD for NEC PC-98 series]
11 *  Copyright (c) 1995, 1996, 1997, 1998
12 *	NetBSD/pc98 porting staff. All rights reserved.
13 *  Copyright (c) 1995, 1996, 1997, 1998
14 *	Naofumi HONDA. All rights reserved.
15 *
16 *  Redistribution and use in source and binary forms, with or without
17 *  modification, are permitted provided that the following conditions
18 *  are met:
19 *  1. Redistributions of source code must retain the above copyright
20 *     notice, this list of conditions and the following disclaimer.
21 *  2. Redistributions in binary form must reproduce the above copyright
22 *     notice, this list of conditions and the following disclaimer in the
23 *     documentation and/or other materials provided with the distribution.
24 *  3. The name of the author may not be used to endorse or promote products
25 *     derived from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
31 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/disklabel.h>
43#if defined(__FreeBSD__) && __FreeBSD_version >= 500001
44#include <sys/bio.h>
45#endif
46#include <sys/buf.h>
47#include <sys/queue.h>
48#include <sys/malloc.h>
49#include <sys/errno.h>
50
51#include <vm/vm.h>
52
53#include <machine/bus.h>
54#include <machine/bus_pio.h>
55#include <i386/isa/isa_device.h>
56
57#include <machine/dvcfg.h>
58
59#if defined(__FreeBSD__) && __FreeBSD_version < 400001
60static struct ncv_softc *ncv_get_softc(int);
61extern struct ncv_softc *ncvdata[];
62#define DEVPORT_ALLOCSOFTCFUNC	ncv_get_softc
63#define DEVPORT_SOFTCARRAY	ncvdata
64#endif
65#include <sys/device_port.h>
66
67#include <cam/scsi/scsi_low.h>
68#include <cam/scsi/scsi_low_pisa.h>
69
70#include <dev/ncv/ncr53c500reg.h>
71#include <dev/ncv/ncr53c500hw.h>
72#include <dev/ncv/ncr53c500var.h>
73#if defined(__NetBSD__) || (defined(__FreeBSD__) && __FreeBSD_version < 400001)
74#include "ncv.h"
75#endif
76
77#define KME_KXLC004_01 0x100
78#define OFFSET_KME_KXLC004_01 0x10
79
80/* pccard support */
81#include	"card.h"
82#if NCARD > 0
83#include	<sys/kernel.h>
84#include	<sys/module.h>
85#if !defined(__FreeBSD__) || __FreeBSD_version < 500014
86#include	<sys/select.h>
87#endif
88#include	<pccard/cardinfo.h>
89#include	<pccard/slot.h>
90
91static int ncvprobe(DEVPORT_PDEVICE devi);
92static int ncvattach(DEVPORT_PDEVICE devi);
93
94static void	ncv_card_unload __P((DEVPORT_PDEVICE));
95#if defined(__FreeBSD__) && __FreeBSD_version < 400001
96static int	ncv_card_init __P((DEVPORT_PDEVICE));
97static int	ncv_card_intr __P((DEVPORT_PDEVICE));
98#endif
99
100#if defined(__FreeBSD__) && __FreeBSD_version >= 400001
101/*
102 * Additional code for FreeBSD new-bus PCCard frontend
103 */
104
105static void
106ncv_pccard_intr(void * arg)
107{
108	ncvintr(arg);
109}
110
111static void
112ncv_release_resource(DEVPORT_PDEVICE dev)
113{
114	struct ncv_softc	*sc = device_get_softc(dev);
115
116	if (sc->ncv_intrhand) {
117		bus_teardown_intr(dev, sc->irq_res, sc->ncv_intrhand);
118	}
119
120	if (sc->port_res) {
121		bus_release_resource(dev, SYS_RES_IOPORT,
122				     sc->port_rid, sc->port_res);
123	}
124
125	if (sc->port_res_dmy) {
126		bus_release_resource(dev, SYS_RES_IOPORT,
127				     sc->port_rid_dmy, sc->port_res_dmy);
128	}
129
130	if (sc->irq_res) {
131		bus_release_resource(dev, SYS_RES_IRQ,
132				     sc->irq_rid, sc->irq_res);
133	}
134
135	if (sc->mem_res) {
136		bus_release_resource(dev, SYS_RES_MEMORY,
137				     sc->mem_rid, sc->mem_res);
138	}
139}
140
141static int
142ncv_alloc_resource(DEVPORT_PDEVICE dev)
143{
144	struct ncv_softc	*sc = device_get_softc(dev);
145	u_int32_t		flags = DEVPORT_PDEVFLAGS(dev);
146	u_long			ioaddr, iosize, maddr, msize;
147	int			error;
148	bus_addr_t		offset = 0;
149
150	if(flags & KME_KXLC004_01)
151		offset = OFFSET_KME_KXLC004_01;
152
153	error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize);
154	if (error || (iosize < (offset + NCVIOSZ))) {
155		return(ENOMEM);
156	}
157
158	sc->port_rid = 0;
159	sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid,
160					  ioaddr+offset, ioaddr+iosize-offset,
161					  iosize-offset, RF_ACTIVE);
162	if (sc->port_res == NULL) {
163		ncv_release_resource(dev);
164		return(ENOMEM);
165	}
166
167	if (offset != 0) {
168		sc->port_rid_dmy = 0;
169		sc->port_res_dmy = bus_alloc_resource(dev, SYS_RES_IOPORT,
170						&sc->port_rid_dmy,
171						ioaddr, ioaddr+offset, offset,
172						RF_ACTIVE);
173		if (sc->port_res_dmy == NULL) {
174			printf("Warning: cannot allocate IOPORT partially.\n");
175		}
176	} else {
177		sc->port_rid_dmy = 0;
178		sc->port_res_dmy = NULL;
179	}
180
181	sc->irq_rid = 0;
182	sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irq_rid,
183					 0, ~0, 1, RF_ACTIVE);
184	if (sc->irq_res == NULL) {
185		ncv_release_resource(dev);
186		return(ENOMEM);
187	}
188
189	error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize);
190	if (error) {
191		return(0);	/* XXX */
192	}
193
194	/* no need to allocate memory if not configured */
195	if (maddr == 0 || msize == 0) {
196		return(0);
197	}
198
199	sc->mem_rid = 0;
200	sc->mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid,
201					 0, ~0, msize, RF_ACTIVE);
202	if (sc->mem_res == NULL) {
203		ncv_release_resource(dev);
204		return(ENOMEM);
205	}
206
207	return(0);
208}
209
210static int
211ncv_pccard_probe(DEVPORT_PDEVICE dev)
212{
213	struct ncv_softc	*sc = device_get_softc(dev);
214	int			error;
215
216	bzero(sc, sizeof(struct ncv_softc));
217
218	error = ncv_alloc_resource(dev);
219	if (error) {
220		return(error);
221	}
222
223	if (ncvprobe(dev) == 0) {
224		ncv_release_resource(dev);
225		return(ENXIO);
226	}
227
228	ncv_release_resource(dev);
229
230	return(0);
231}
232
233static int
234ncv_pccard_attach(DEVPORT_PDEVICE dev)
235{
236	struct ncv_softc	*sc = device_get_softc(dev);
237	int			error;
238
239	error = ncv_alloc_resource(dev);
240	if (error) {
241		return(error);
242	}
243
244	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY,
245			       ncv_pccard_intr, (void *)sc, &sc->ncv_intrhand);
246	if (error) {
247		ncv_release_resource(dev);
248		return(error);
249	}
250
251	if (ncvattach(dev) == 0) {
252		ncv_release_resource(dev);
253		return(ENXIO);
254	}
255
256	return(0);
257}
258
259static	void
260ncv_pccard_detach(DEVPORT_PDEVICE dev)
261{
262	ncv_card_unload(dev);
263	ncv_release_resource(dev);
264}
265
266static device_method_t ncv_pccard_methods[] = {
267	/* Device interface */
268	DEVMETHOD(device_probe,		ncv_pccard_probe),
269	DEVMETHOD(device_attach,	ncv_pccard_attach),
270	DEVMETHOD(device_detach,	ncv_pccard_detach),
271
272	{ 0, 0 }
273};
274
275static driver_t ncv_pccard_driver = {
276	"ncv",
277	ncv_pccard_methods,
278	sizeof(struct ncv_softc),
279};
280
281static devclass_t ncv_devclass;
282
283DRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0);
284
285#else
286
287PCCARD_MODULE(ncv, ncv_card_init, ncv_card_unload, ncv_card_intr, 0, cam_imask);
288
289#endif
290
291#if defined(__FreeBSD__) && __FreeBSD_version < 400001
292static struct ncv_softc *
293ncv_get_softc(int unit)
294{
295	struct ncv_softc *sc;
296
297	if (unit >= NNCV) {
298		return(NULL);
299	}
300
301	if (ncvdata[unit] == NULL) {
302		sc = malloc(sizeof(struct ncv_softc), M_TEMP,M_NOWAIT);
303		if (sc == NULL) {
304			printf("ncv_get_softc: cannot malloc!\n");
305			return(NULL);
306		}
307		ncvdata[unit] = sc;
308	} else {
309		sc = ncvdata[unit];
310	}
311
312	return(sc);
313}
314
315static int
316ncv_card_init(DEVPORT_PDEVICE devi)
317{
318	int unit = DEVPORT_PDEVUNIT(devi);
319
320	if (NNCV <= unit)
321		return (ENODEV);
322
323	if (ncvprobe(devi) == 0)
324		return (ENXIO);
325
326	if (ncvattach(devi) == 0)
327		return (ENXIO);
328	return (0);
329}
330
331static int
332ncv_card_intr(DEVPORT_PDEVICE devi)
333{
334
335	ncvintr(DEVPORT_PDEVGET_SOFTC(devi));
336	return 1;
337}
338#endif
339
340static void
341ncv_card_unload(DEVPORT_PDEVICE devi)
342{
343	struct ncv_softc *sc = DEVPORT_PDEVGET_SOFTC(devi);
344
345	printf("%s: unload\n", sc->sc_sclow.sl_xname);
346	scsi_low_deactivate((struct scsi_low_softc *)sc);
347        scsi_low_dettach(&sc->sc_sclow);
348}
349
350static int
351ncvprobe(DEVPORT_PDEVICE devi)
352{
353	int rv;
354	struct ncv_softc *sc = device_get_softc(devi);
355	u_int32_t flags = DEVPORT_PDEVFLAGS(devi);
356
357#if defined(__FreeBSD__) && __FreeBSD_version >= 400001
358	rv = ncvprobesubr(rman_get_bustag(sc->port_res),
359			  rman_get_bushandle(sc->port_res),
360			  flags, NCV_HOSTID);
361#else
362	bus_addr_t offset = 0;
363	u_int iobase = DEVPORT_PDEVIOBASE(devi);
364
365	if(flags & KME_KXLC004_01)
366		offset = OFFSET_KME_KXLC004_01;
367
368	rv = ncvprobesubr(I386_BUS_SPACE_IO,
369			  iobase + offset,
370			  flags, NCV_HOSTID);
371#endif
372
373	return rv;
374}
375
376static int
377ncvattach(DEVPORT_PDEVICE devi)
378{
379	struct ncv_softc *sc;
380	struct scsi_low_softc *slp;
381	u_int32_t flags = DEVPORT_PDEVFLAGS(devi);
382#if defined(__FreeBSD__) && __FreeBSD_version < 400001
383	int unit = DEVPORT_PDEVUNIT(devi);
384	bus_addr_t offset = 0;
385	u_int iobase = DEVPORT_PDEVIOBASE(devi);
386#endif
387	char dvname[16]; /* SCSI_LOW_DVNAME_LEN */
388
389	strcpy(dvname, "ncv");
390
391#if defined(__FreeBSD__) && __FreeBSD_version < 400001
392	if (unit >= NNCV)
393	{
394		printf("%s: unit number too high\n", dvname);
395		return (0);
396	}
397
398	if (iobase == 0)
399	{
400		printf("%s: no ioaddr is given\n", dvname);
401		return (0);
402	}
403
404	if(flags & KME_KXLC004_01)
405		offset = OFFSET_KME_KXLC004_01;
406#endif
407
408	sc = DEVPORT_PDEVALLOC_SOFTC(devi);
409	if (sc == NULL) {
410		return(0);
411	}
412
413	slp = &sc->sc_sclow;
414#if defined(__FreeBSD__) && __FreeBSD_version >= 400001
415	slp->sl_dev = devi;
416	sc->sc_iot = rman_get_bustag(sc->port_res);
417	sc->sc_ioh = rman_get_bushandle(sc->port_res);
418#else
419	bzero(sc, sizeof(struct ncv_softc));
420	strcpy(slp->sl_dev.dv_xname, dvname);
421	slp->sl_dev.dv_unit = unit;
422	sc->sc_iot = I386_BUS_SPACE_IO;
423	sc->sc_ioh = iobase + offset;
424#endif
425
426	slp->sl_hostid = NCV_HOSTID;
427	slp->sl_cfgflags = flags;
428
429	ncvattachsubr(sc);
430
431	sc->sc_ih = ncvintr;
432
433	return(NCVIOSZ);
434}
435#endif /* NCARD */
436