1 /*======================================================================
2 
3     A driver for PCMCIA IDE/ATA disk cards
4 
5     The contents of this file are subject to the Mozilla Public
6     License Version 1.1 (the "License"); you may not use this file
7     except in compliance with the License. You may obtain a copy of
8     the License at http://www.mozilla.org/MPL/
9 
10     Software distributed under the License is distributed on an "AS
11     IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
12     implied. See the License for the specific language governing
13     rights and limitations under the License.
14 
15     The initial developer of the original code is David A. Hinds
16     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
17     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
18 
19     Alternatively, the contents of this file may be used under the
20     terms of the GNU General Public License version 2 (the "GPL"), in
21     which case the provisions of the GPL are applicable instead of the
22     above.  If you wish to allow the use of your version of this file
23     only under the terms of the GPL and not to allow others to use
24     your version of this file under the MPL, indicate your decision
25     by deleting the provisions above and replace them with the notice
26     and other provisions required by the GPL.  If you do not delete
27     the provisions above, a recipient may use your version of this
28     file under either the MPL or the GPL.
29 
30 ======================================================================*/
31 
32 #include <linux/module.h>
33 #include <linux/kernel.h>
34 #include <linux/init.h>
35 #include <linux/ptrace.h>
36 #include <linux/slab.h>
37 #include <linux/string.h>
38 #include <linux/timer.h>
39 #include <linux/ioport.h>
40 #include <linux/ide.h>
41 #include <linux/major.h>
42 #include <linux/delay.h>
43 #include <asm/io.h>
44 
45 #include <pcmcia/cistpl.h>
46 #include <pcmcia/ds.h>
47 #include <pcmcia/cisreg.h>
48 #include <pcmcia/ciscode.h>
49 
50 #define DRV_NAME "ide-cs"
51 
52 /*====================================================================*/
53 
54 /* Module parameters */
55 
56 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
57 MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver");
58 MODULE_LICENSE("Dual MPL/GPL");
59 
60 /*====================================================================*/
61 
62 typedef struct ide_info_t {
63 	struct pcmcia_device	*p_dev;
64 	struct ide_host		*host;
65 	int			ndev;
66 } ide_info_t;
67 
68 static void ide_release(struct pcmcia_device *);
69 static int ide_config(struct pcmcia_device *);
70 
71 static void ide_detach(struct pcmcia_device *p_dev);
72 
ide_probe(struct pcmcia_device * link)73 static int ide_probe(struct pcmcia_device *link)
74 {
75     ide_info_t *info;
76 
77     dev_dbg(&link->dev, "ide_attach()\n");
78 
79     /* Create new ide device */
80     info = kzalloc(sizeof(*info), GFP_KERNEL);
81     if (!info)
82 	return -ENOMEM;
83 
84     info->p_dev = link;
85     link->priv = info;
86 
87     link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO |
88 	    CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
89 
90     return ide_config(link);
91 } /* ide_attach */
92 
ide_detach(struct pcmcia_device * link)93 static void ide_detach(struct pcmcia_device *link)
94 {
95     ide_info_t *info = link->priv;
96 
97     dev_dbg(&link->dev, "ide_detach(0x%p)\n", link);
98 
99     ide_release(link);
100 
101     kfree(info);
102 } /* ide_detach */
103 
104 static const struct ide_port_ops idecs_port_ops = {
105 	.quirkproc		= ide_undecoded_slave,
106 };
107 
108 static const struct ide_port_info idecs_port_info = {
109 	.port_ops		= &idecs_port_ops,
110 	.host_flags		= IDE_HFLAG_NO_DMA,
111 	.irq_flags		= IRQF_SHARED,
112 	.chipset		= ide_pci,
113 };
114 
idecs_register(unsigned long io,unsigned long ctl,unsigned long irq,struct pcmcia_device * handle)115 static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
116 				unsigned long irq, struct pcmcia_device *handle)
117 {
118     struct ide_host *host;
119     ide_hwif_t *hwif;
120     int i, rc;
121     struct ide_hw hw, *hws[] = { &hw };
122 
123     if (!request_region(io, 8, DRV_NAME)) {
124 	printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
125 			DRV_NAME, io, io + 7);
126 	return NULL;
127     }
128 
129     if (!request_region(ctl, 1, DRV_NAME)) {
130 	printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
131 			DRV_NAME, ctl);
132 	release_region(io, 8);
133 	return NULL;
134     }
135 
136     memset(&hw, 0, sizeof(hw));
137     ide_std_init_ports(&hw, io, ctl);
138     hw.irq = irq;
139     hw.dev = &handle->dev;
140 
141     rc = ide_host_add(&idecs_port_info, hws, 1, &host);
142     if (rc)
143 	goto out_release;
144 
145     hwif = host->ports[0];
146 
147     if (hwif->present)
148 	return host;
149 
150     /* retry registration in case device is still spinning up */
151     for (i = 0; i < 10; i++) {
152 	msleep(100);
153 	ide_port_scan(hwif);
154 	if (hwif->present)
155 	    return host;
156     }
157 
158     return host;
159 
160 out_release:
161     release_region(ctl, 1);
162     release_region(io, 8);
163     return NULL;
164 }
165 
pcmcia_check_one_config(struct pcmcia_device * pdev,void * priv_data)166 static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
167 {
168 	int *is_kme = priv_data;
169 
170 	if ((pdev->resource[0]->flags & IO_DATA_PATH_WIDTH)
171 	    != IO_DATA_PATH_WIDTH_8) {
172 		pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
173 		pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
174 	}
175 	pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
176 	pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
177 
178 	if (pdev->resource[1]->end) {
179 		pdev->resource[0]->end = 8;
180 		pdev->resource[1]->end = (*is_kme) ? 2 : 1;
181 	} else {
182 		if (pdev->resource[0]->end < 16)
183 			return -ENODEV;
184 	}
185 
186 	return pcmcia_request_io(pdev);
187 }
188 
ide_config(struct pcmcia_device * link)189 static int ide_config(struct pcmcia_device *link)
190 {
191     ide_info_t *info = link->priv;
192     int ret = 0, is_kme = 0;
193     unsigned long io_base, ctl_base;
194     struct ide_host *host;
195 
196     dev_dbg(&link->dev, "ide_config(0x%p)\n", link);
197 
198     is_kme = ((link->manf_id == MANFID_KME) &&
199 	      ((link->card_id == PRODID_KME_KXLC005_A) ||
200 	       (link->card_id == PRODID_KME_KXLC005_B)));
201 
202     if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) {
203 	    link->config_flags &= ~CONF_AUTO_CHECK_VCC;
204 	    if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme))
205 		    goto failed; /* No suitable config found */
206     }
207     io_base = link->resource[0]->start;
208     if (link->resource[1]->end)
209 	    ctl_base = link->resource[1]->start;
210     else
211 	    ctl_base = link->resource[0]->start + 0x0e;
212 
213     if (!link->irq)
214 	    goto failed;
215 
216     ret = pcmcia_enable_device(link);
217     if (ret)
218 	    goto failed;
219 
220     /* disable drive interrupts during IDE probe */
221     outb(0x02, ctl_base);
222 
223     /* special setup for KXLC005 card */
224     if (is_kme)
225 	outb(0x81, ctl_base+1);
226 
227      host = idecs_register(io_base, ctl_base, link->irq, link);
228      if (host == NULL && resource_size(link->resource[0]) == 0x20) {
229 	    outb(0x02, ctl_base + 0x10);
230 	    host = idecs_register(io_base + 0x10, ctl_base + 0x10,
231 				  link->irq, link);
232     }
233 
234     if (host == NULL)
235 	goto failed;
236 
237     info->ndev = 1;
238     info->host = host;
239     dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n",
240 	    'a' + host->ports[0]->index * 2,
241 	    link->vpp / 10, link->vpp % 10);
242 
243     return 0;
244 
245 failed:
246     ide_release(link);
247     return -ENODEV;
248 } /* ide_config */
249 
ide_release(struct pcmcia_device * link)250 static void ide_release(struct pcmcia_device *link)
251 {
252     ide_info_t *info = link->priv;
253     struct ide_host *host = info->host;
254 
255     dev_dbg(&link->dev, "ide_release(0x%p)\n", link);
256 
257     if (info->ndev) {
258 	ide_hwif_t *hwif = host->ports[0];
259 	unsigned long data_addr, ctl_addr;
260 
261 	data_addr = hwif->io_ports.data_addr;
262 	ctl_addr = hwif->io_ports.ctl_addr;
263 
264 	ide_host_remove(host);
265 	info->ndev = 0;
266 
267 	release_region(ctl_addr, 1);
268 	release_region(data_addr, 8);
269     }
270 
271     pcmcia_disable_device(link);
272 } /* ide_release */
273 
274 
275 static const struct pcmcia_device_id ide_ids[] = {
276 	PCMCIA_DEVICE_FUNC_ID(4),
277 	PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),	/* Corsair */
278 	PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000),	/* Hitachi */
279 	PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000),	/* I-O Data CFA */
280 	PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001),	/* Mitsubishi CFA */
281 	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
282 	PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904),
283 	PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),	/* SanDisk CFA */
284 	PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000),	/* Kingston */
285 	PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), 	/* TI emulated */
286 	PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000),	/* Toshiba */
287 	PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
288 	PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000),	/* Samsung */
289 	PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000),	/* Hitachi */
290 	PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
291 	PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100),	/* Viking CFA */
292 	PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200),	/* Lexar, Viking CFA */
293 	PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
294 	PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
295 	PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
296 	PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
297 	PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
298 	PCMCIA_DEVICE_PROD_ID12("CNF   ", "CD-ROM", 0x46d7db81, 0x66536591),
299 	PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
300 	PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
301 	PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
302 	PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf),
303 	PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
304 	PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
305 	PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
306 	PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
307 	PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
308 	PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420),
309 	PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
310 	PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
311 	PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x55d5bffb),
312 	PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10),
313 	PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
314 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
315 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
316 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
317 	PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2      ", 0xe37be2b5, 0x8671043b),
318 	PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee),
319 	PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
320 	PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
321 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
322 	PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
323 	PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
324 	PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883),
325 	PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
326 	PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
327 	PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
328 	PCMCIA_DEVICE_PROD_ID1("TRANSCEND    512M   ", 0xd0909443),
329 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32),
330 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1),
331 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2),
332 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
333 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x7558f133),
334 	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47),
335 	PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
336 	PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918),
337 	PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
338 	PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
339 	PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
340 	PCMCIA_DEVICE_PROD_ID2("Flash Card", 0x5a362506),
341 	PCMCIA_DEVICE_NULL,
342 };
343 MODULE_DEVICE_TABLE(pcmcia, ide_ids);
344 
345 static struct pcmcia_driver ide_cs_driver = {
346 	.owner		= THIS_MODULE,
347 	.name		= "ide-cs",
348 	.probe		= ide_probe,
349 	.remove		= ide_detach,
350 	.id_table       = ide_ids,
351 };
352 
init_ide_cs(void)353 static int __init init_ide_cs(void)
354 {
355 	return pcmcia_register_driver(&ide_cs_driver);
356 }
357 
exit_ide_cs(void)358 static void __exit exit_ide_cs(void)
359 {
360 	pcmcia_unregister_driver(&ide_cs_driver);
361 }
362 
363 late_initcall(init_ide_cs);
364 module_exit(exit_ide_cs);
365