ata-card.c revision 120871
1/*-
2 * Copyright (c) 1998 - 2003 S�ren Schmidt <sos@FreeBSD.org>
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 *    without modification, immediately at the beginning of the file.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/dev/ata/ata-card.c 120871 2003-10-07 04:26:14Z imp $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/ata.h>
35#include <sys/kernel.h>
36#include <sys/module.h>
37#include <sys/bus.h>
38#include <sys/malloc.h>
39#include <sys/taskqueue.h>
40#include <machine/stdarg.h>
41#include <machine/resource.h>
42#include <machine/bus.h>
43#include <sys/rman.h>
44#include <dev/ata/ata-all.h>
45#include <dev/pccard/pccard_cis.h>
46#include <dev/pccard/pccarddevs.h>
47#include <dev/pccard/pccardreg.h>
48#include <dev/pccard/pccardvar.h>
49
50static const struct pccard_product ata_pccard_products[] = {
51	PCMCIA_CARD(FREECOM, PCCARDIDE, 0),
52	PCMCIA_CARD(EXP, EXPMULTIMEDIA, 0),
53	PCMCIA_CARD(IODATA, CBIDE2, 0),
54	PCMCIA_CARD(OEM2, CDROM1, 0),
55	PCMCIA_CARD(OEM2, IDE, 0),
56	PCMCIA_CARD(PANASONIC, KXLC005, 0),
57	PCMCIA_CARD(TEAC, IDECARDII, 0),
58	{NULL}
59};
60
61static int
62ata_pccard_match(device_t dev)
63{
64    const struct pccard_product *pp;
65    u_int32_t fcn = PCCARD_FUNCTION_UNSPEC;
66    int error = 0;
67
68    error = pccard_get_function(dev, &fcn);
69    if (error != 0)
70	return (error);
71
72    /* if it says its a disk we should register it */
73    if (fcn == PCCARD_FUNCTION_DISK)
74	return (0);
75
76    /* match other devices here, primarily cdrom/dvd rom */
77    if ((pp = pccard_product_lookup(dev, ata_pccard_products,
78				    sizeof(ata_pccard_products[0]), NULL))) {
79	if (pp->pp_name)
80	    device_set_desc(dev, pp->pp_name);
81	return (0);
82    }
83    return(ENXIO);
84}
85
86static void
87ata_pccard_locknoop(struct ata_channel *ch, int type)
88{
89}
90
91static void
92ata_pccard_setmode(struct ata_device *atadev, int mode)
93{
94    atadev->mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX);
95}
96
97static int
98ata_pccard_probe(device_t dev)
99{
100    struct ata_channel *ch = device_get_softc(dev);
101    struct resource *io, *altio;
102    int i, rid, len, start, end;
103    u_long tmp;
104
105    /* allocate the io range to get start and length */
106    rid = ATA_IOADDR_RID;
107    len = bus_get_resource_count(dev, SYS_RES_IOPORT, rid);
108    io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
109			    ATA_IOSIZE, RF_ACTIVE);
110    if (!io)
111	return ENXIO;
112
113    /* reallocate the io address to only cover the io ports */
114    start = rman_get_start(io);
115    end = start + ATA_IOSIZE - 1;
116    bus_release_resource(dev, SYS_RES_IOPORT, rid, io);
117    io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
118			    start, end, ATA_IOSIZE, RF_ACTIVE);
119
120    /*
121     * if we got more than the default ATA_IOSIZE ports, this is likely
122     * a pccard system where the altio ports are located at offset 14
123     * otherwise its the normal altio offset
124     */
125    if (bus_get_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, &tmp, &tmp)) {
126	if (len > ATA_IOSIZE) {
127	    bus_set_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,
128			     start + ATA_PCCARD_ALTOFFSET, ATA_ALTIOSIZE);
129	}
130	else {
131	    bus_set_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID,
132			     start + ATA_ALTOFFSET, ATA_ALTIOSIZE);
133	}
134    }
135
136    /* allocate the altport range */
137    rid = ATA_ALTADDR_RID;
138    altio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
139			       ATA_ALTIOSIZE, RF_ACTIVE);
140    if (!altio) {
141	bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io);
142	return ENXIO;
143    }
144
145    /* setup the resource vectors */
146    for (i = ATA_DATA; i <= ATA_STATUS; i++) {
147	ch->r_io[i].res = io;
148	ch->r_io[i].offset = i;
149    }
150    ch->r_io[ATA_ALTSTAT].res = altio;
151    ch->r_io[ATA_ALTSTAT].offset = 0;
152
153    /* initialize softc for this channel */
154    ch->unit = 0;
155    ch->flags |= (ATA_USE_16BIT | ATA_NO_SLAVE);
156    ch->locking = ata_pccard_locknoop;
157    ch->device[MASTER].setmode = ata_pccard_setmode;
158    ch->device[SLAVE].setmode = ata_pccard_setmode;
159    return ata_probe(dev);
160}
161
162static int
163ata_pccard_detach(device_t dev)
164{
165    struct ata_channel *ch = device_get_softc(dev);
166    int i;
167
168    ata_detach(dev);
169    bus_release_resource(dev, SYS_RES_IOPORT,
170			 ATA_ALTADDR_RID, ch->r_io[ATA_ALTSTAT].res);
171    bus_release_resource(dev, SYS_RES_IOPORT,
172			 ATA_IOADDR_RID, ch->r_io[ATA_DATA].res);
173    for (i = ATA_DATA; i < ATA_MAX_RES; i++)
174	ch->r_io[i].res = NULL;
175    return 0;
176}
177
178static device_method_t ata_pccard_methods[] = {
179    /* device interface */
180    DEVMETHOD(device_probe,	pccard_compat_probe),
181    DEVMETHOD(device_attach,	pccard_compat_attach),
182    DEVMETHOD(device_detach,	ata_pccard_detach),
183
184    /* Card interface */
185    DEVMETHOD(card_compat_match,	ata_pccard_match),
186    DEVMETHOD(card_compat_probe,	ata_pccard_probe),
187    DEVMETHOD(card_compat_attach,	ata_attach),
188    { 0, 0 }
189};
190
191static driver_t ata_pccard_driver = {
192    "ata",
193    ata_pccard_methods,
194    sizeof(struct ata_channel),
195};
196
197DRIVER_MODULE(ata, pccard, ata_pccard_driver, ata_devclass, 0, 0);
198