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 56MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); 57MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver"); 58MODULE_LICENSE("Dual MPL/GPL"); 59 60/*====================================================================*/ 61 62typedef struct ide_info_t { 63 struct pcmcia_device *p_dev; 64 struct ide_host *host; 65 int ndev; 66} ide_info_t; 67 68static void ide_release(struct pcmcia_device *); 69static int ide_config(struct pcmcia_device *); 70 71static void ide_detach(struct pcmcia_device *p_dev); 72 73static 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 93static 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 104static const struct ide_port_ops idecs_port_ops = { 105 .quirkproc = ide_undecoded_slave, 106}; 107 108static 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 115static 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 160out_release: 161 release_region(ctl, 1); 162 release_region(io, 8); 163 return NULL; 164} 165 166static 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_8)) { 171 pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; 172 pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; 173 } 174 pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH; 175 pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8; 176 177 if (pdev->resource[1]->end) { 178 pdev->resource[0]->end = 8; 179 pdev->resource[1]->end = (*is_kme) ? 2 : 1; 180 } else { 181 if (pdev->resource[0]->end < 16) 182 return -ENODEV; 183 } 184 185 return pcmcia_request_io(pdev); 186} 187 188static int ide_config(struct pcmcia_device *link) 189{ 190 ide_info_t *info = link->priv; 191 int ret = 0, is_kme = 0; 192 unsigned long io_base, ctl_base; 193 struct ide_host *host; 194 195 dev_dbg(&link->dev, "ide_config(0x%p)\n", link); 196 197 is_kme = ((link->manf_id == MANFID_KME) && 198 ((link->card_id == PRODID_KME_KXLC005_A) || 199 (link->card_id == PRODID_KME_KXLC005_B))); 200 201 if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) { 202 link->config_flags &= ~CONF_AUTO_CHECK_VCC; 203 if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) 204 goto failed; /* No suitable config found */ 205 } 206 io_base = link->resource[0]->start; 207 if (link->resource[1]->end) 208 ctl_base = link->resource[1]->start; 209 else 210 ctl_base = link->resource[0]->start + 0x0e; 211 212 if (!link->irq) 213 goto failed; 214 215 ret = pcmcia_enable_device(link); 216 if (ret) 217 goto failed; 218 219 /* disable drive interrupts during IDE probe */ 220 outb(0x02, ctl_base); 221 222 /* special setup for KXLC005 card */ 223 if (is_kme) 224 outb(0x81, ctl_base+1); 225 226 host = idecs_register(io_base, ctl_base, link->irq, link); 227 if (host == NULL && resource_size(link->resource[0]) == 0x20) { 228 outb(0x02, ctl_base + 0x10); 229 host = idecs_register(io_base + 0x10, ctl_base + 0x10, 230 link->irq, link); 231 } 232 233 if (host == NULL) 234 goto failed; 235 236 info->ndev = 1; 237 info->host = host; 238 dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n", 239 'a' + host->ports[0]->index * 2, 240 link->vpp / 10, link->vpp % 10); 241 242 return 0; 243 244failed: 245 ide_release(link); 246 return -ENODEV; 247} /* ide_config */ 248 249static void ide_release(struct pcmcia_device *link) 250{ 251 ide_info_t *info = link->priv; 252 struct ide_host *host = info->host; 253 254 dev_dbg(&link->dev, "ide_release(0x%p)\n", link); 255 256 if (info->ndev) { 257 ide_hwif_t *hwif = host->ports[0]; 258 unsigned long data_addr, ctl_addr; 259 260 data_addr = hwif->io_ports.data_addr; 261 ctl_addr = hwif->io_ports.ctl_addr; 262 263 ide_host_remove(host); 264 info->ndev = 0; 265 266 release_region(ctl_addr, 1); 267 release_region(data_addr, 8); 268 } 269 270 pcmcia_disable_device(link); 271} /* ide_release */ 272 273 274static const struct pcmcia_device_id ide_ids[] = { 275 PCMCIA_DEVICE_FUNC_ID(4), 276 PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */ 277 PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */ 278 PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */ 279 PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */ 280 PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), 281 PCMCIA_DEVICE_MANF_CARD(0x0032, 0x2904), 282 PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), /* SanDisk CFA */ 283 PCMCIA_DEVICE_MANF_CARD(0x004f, 0x0000), /* Kingston */ 284 PCMCIA_DEVICE_MANF_CARD(0x0097, 0x1620), /* TI emulated */ 285 PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ 286 PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), 287 PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ 288 PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */ 289 PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001), 290 PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0100), /* Viking CFA */ 291 PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar, Viking CFA */ 292 PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0), 293 PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74), 294 PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9), 295 PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591), 296 PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728), 297 PCMCIA_DEVICE_PROD_ID12("CNF ", "CD-ROM", 0x46d7db81, 0x66536591), 298 PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591), 299 PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4), 300 PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde), 301 PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf), 302 PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591), 303 PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728), 304 PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), 305 PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), 306 PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), 307 PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420), 308 PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), 309 PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), 310 PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 1GB", 0x2e6d1829, 0x55d5bffb), 311 PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF CARD 4GB", 0x2e6d1829, 0x531e7d10), 312 PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e), 313 PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), 314 PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), 315 PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674), 316 PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b), 317 PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF300", 0x7ed2ad87, 0x7e9e78ee), 318 PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c), 319 PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79), 320 PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591), 321 PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728), 322 PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1), 323 PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883), 324 PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d), 325 PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6), 326 PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003), 327 PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443), 328 PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF45", 0x709b1bf1, 0xf68b6f32), 329 PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS1GCF80", 0x709b1bf1, 0x2a54d4b1), 330 PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS2GCF120", 0x709b1bf1, 0x969aa4f2), 331 PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8), 332 PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF133", 0x709b1bf1, 0x7558f133), 333 PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS8GCF133", 0x709b1bf1, 0xb2f89b47), 334 PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852), 335 PCMCIA_DEVICE_PROD_ID12("WEIDA", "TWTTI", 0xcc7cf69c, 0x212bb918), 336 PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209), 337 PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e), 338 PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6), 339 PCMCIA_DEVICE_PROD_ID2("Flash Card", 0x5a362506), 340 PCMCIA_DEVICE_NULL, 341}; 342MODULE_DEVICE_TABLE(pcmcia, ide_ids); 343 344static struct pcmcia_driver ide_cs_driver = { 345 .owner = THIS_MODULE, 346 .name = "ide-cs", 347 .probe = ide_probe, 348 .remove = ide_detach, 349 .id_table = ide_ids, 350}; 351 352static int __init init_ide_cs(void) 353{ 354 return pcmcia_register_driver(&ide_cs_driver); 355} 356 357static void __exit exit_ide_cs(void) 358{ 359 pcmcia_unregister_driver(&ide_cs_driver); 360} 361 362late_initcall(init_ide_cs); 363module_exit(exit_ide_cs); 364