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 #include <asm/system.h>
45
46 #include <pcmcia/cistpl.h>
47 #include <pcmcia/ds.h>
48 #include <pcmcia/cisreg.h>
49 #include <pcmcia/ciscode.h>
50
51 #define DRV_NAME "ide-cs"
52
53 /*====================================================================*/
54
55 /* Module parameters */
56
57 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
58 MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver");
59 MODULE_LICENSE("Dual MPL/GPL");
60
61 /*====================================================================*/
62
63 typedef struct ide_info_t {
64 struct pcmcia_device *p_dev;
65 struct ide_host *host;
66 int ndev;
67 } ide_info_t;
68
69 static void ide_release(struct pcmcia_device *);
70 static int ide_config(struct pcmcia_device *);
71
72 static void ide_detach(struct pcmcia_device *p_dev);
73
ide_probe(struct pcmcia_device * link)74 static int ide_probe(struct pcmcia_device *link)
75 {
76 ide_info_t *info;
77
78 dev_dbg(&link->dev, "ide_attach()\n");
79
80 /* Create new ide device */
81 info = kzalloc(sizeof(*info), GFP_KERNEL);
82 if (!info)
83 return -ENOMEM;
84
85 info->p_dev = link;
86 link->priv = info;
87
88 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO |
89 CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
90
91 return ide_config(link);
92 } /* ide_attach */
93
ide_detach(struct pcmcia_device * link)94 static void ide_detach(struct pcmcia_device *link)
95 {
96 ide_info_t *info = link->priv;
97
98 dev_dbg(&link->dev, "ide_detach(0x%p)\n", link);
99
100 ide_release(link);
101
102 kfree(info);
103 } /* ide_detach */
104
105 static const struct ide_port_ops idecs_port_ops = {
106 .quirkproc = ide_undecoded_slave,
107 };
108
109 static const struct ide_port_info idecs_port_info = {
110 .port_ops = &idecs_port_ops,
111 .host_flags = IDE_HFLAG_NO_DMA,
112 .irq_flags = IRQF_SHARED,
113 .chipset = ide_pci,
114 };
115
idecs_register(unsigned long io,unsigned long ctl,unsigned long irq,struct pcmcia_device * handle)116 static struct ide_host *idecs_register(unsigned long io, unsigned long ctl,
117 unsigned long irq, struct pcmcia_device *handle)
118 {
119 struct ide_host *host;
120 ide_hwif_t *hwif;
121 int i, rc;
122 struct ide_hw hw, *hws[] = { &hw };
123
124 if (!request_region(io, 8, DRV_NAME)) {
125 printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX not free.\n",
126 DRV_NAME, io, io + 7);
127 return NULL;
128 }
129
130 if (!request_region(ctl, 1, DRV_NAME)) {
131 printk(KERN_ERR "%s: I/O resource 0x%lX not free.\n",
132 DRV_NAME, ctl);
133 release_region(io, 8);
134 return NULL;
135 }
136
137 memset(&hw, 0, sizeof(hw));
138 ide_std_init_ports(&hw, io, ctl);
139 hw.irq = irq;
140 hw.dev = &handle->dev;
141
142 rc = ide_host_add(&idecs_port_info, hws, 1, &host);
143 if (rc)
144 goto out_release;
145
146 hwif = host->ports[0];
147
148 if (hwif->present)
149 return host;
150
151 /* retry registration in case device is still spinning up */
152 for (i = 0; i < 10; i++) {
153 msleep(100);
154 ide_port_scan(hwif);
155 if (hwif->present)
156 return host;
157 }
158
159 return host;
160
161 out_release:
162 release_region(ctl, 1);
163 release_region(io, 8);
164 return NULL;
165 }
166
pcmcia_check_one_config(struct pcmcia_device * pdev,void * priv_data)167 static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
168 {
169 int *is_kme = priv_data;
170
171 if (!(pdev->resource[0]->flags & 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 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