1/*====================================================================== 2 3 A driver for PCMCIA IDE/ATA disk cards 4 5 ide_cs.c 1.26 1999/11/16 02:10:49 6 7 The contents of this file are subject to the Mozilla Public 8 License Version 1.1 (the "License"); you may not use this file 9 except in compliance with the License. You may obtain a copy of 10 the License at http://www.mozilla.org/MPL/ 11 12 Software distributed under the License is distributed on an "AS 13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or 14 implied. See the License for the specific language governing 15 rights and limitations under the License. 16 17 The initial developer of the original code is David A. Hinds 18 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 20 21 Alternatively, the contents of this file may be used under the 22 terms of the GNU General Public License version 2 (the "GPL"), in which 23 case the provisions of the GPL are applicable instead of the 24 above. If you wish to allow the use of your version of this file 25 only under the terms of the GPL and not to allow others to use 26 your version of this file under the MPL, indicate your decision 27 by deleting the provisions above and replace them with the notice 28 and other provisions required by the GPL. If you do not delete 29 the provisions above, a recipient may use your version of this 30 file under either the MPL or the GPL. 31 32======================================================================*/ 33 34#include <linux/module.h> 35#include <linux/kernel.h> 36#include <linux/init.h> 37#include <linux/sched.h> 38#include <linux/ptrace.h> 39#include <linux/slab.h> 40#include <linux/string.h> 41#include <linux/timer.h> 42#include <linux/ioport.h> 43#include <linux/hdreg.h> 44#include <linux/major.h> 45#include <linux/ide.h> 46 47#include <asm/io.h> 48#include <asm/system.h> 49 50#include <pcmcia/version.h> 51#include <pcmcia/cs_types.h> 52#include <pcmcia/cs.h> 53#include <pcmcia/cistpl.h> 54#include <pcmcia/ds.h> 55#include <pcmcia/cisreg.h> 56 57#ifdef PCMCIA_DEBUG 58static int pc_debug = PCMCIA_DEBUG; 59MODULE_PARM(pc_debug, "i"); 60#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) 61static char *version = 62"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)"; 63#else 64#define DEBUG(n, args...) 65#endif 66 67/*====================================================================*/ 68 69/* Parameters that can be set with 'insmod' */ 70 71/* Bit map of interrupts to choose from */ 72static u_int irq_mask = 0xdeb8; 73static int irq_list[4] = { -1 }; 74 75MODULE_PARM(irq_mask, "i"); 76MODULE_PARM(irq_list, "1-4i"); 77 78MODULE_LICENSE("GPL"); 79 80 81/*====================================================================*/ 82 83static const char ide_major[] = { 84 IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR, 85#ifdef IDE4_MAJOR 86 IDE4_MAJOR, IDE5_MAJOR 87#endif 88}; 89 90typedef struct ide_info_t { 91 dev_link_t link; 92 int ndev; 93 dev_node_t node; 94 int hd; 95} ide_info_t; 96 97static void ide_config(dev_link_t *link); 98static void ide_release(u_long arg); 99static int ide_event(event_t event, int priority, 100 event_callback_args_t *args); 101 102static dev_info_t dev_info = "ide-cs"; 103 104static dev_link_t *ide_attach(void); 105static void ide_detach(dev_link_t *); 106 107static dev_link_t *dev_list = NULL; 108 109/*====================================================================*/ 110 111static void cs_error(client_handle_t handle, int func, int ret) 112{ 113 error_info_t err = { func, ret }; 114 CardServices(ReportError, handle, &err); 115} 116 117/*====================================================================== 118 119 ide_attach() creates an "instance" of the driver, allocating 120 local data structures for one device. The device is registered 121 with Card Services. 122 123======================================================================*/ 124 125static dev_link_t *ide_attach(void) 126{ 127 ide_info_t *info; 128 dev_link_t *link; 129 client_reg_t client_reg; 130 int i, ret; 131 132 DEBUG(0, "ide_attach()\n"); 133 134 /* Create new ide device */ 135 info = kmalloc(sizeof(*info), GFP_KERNEL); 136 if (!info) return NULL; 137 memset(info, 0, sizeof(*info)); 138 link = &info->link; link->priv = info; 139 140 link->release.function = &ide_release; 141 link->release.data = (u_long)link; 142 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; 143 link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; 144 link->io.IOAddrLines = 3; 145 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; 146 link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; 147 if (irq_list[0] == -1) 148 link->irq.IRQInfo2 = irq_mask; 149 else 150 for (i = 0; i < 4; i++) 151 link->irq.IRQInfo2 |= 1 << irq_list[i]; 152 link->conf.Attributes = CONF_ENABLE_IRQ; 153 link->conf.Vcc = 50; 154 link->conf.IntType = INT_MEMORY_AND_IO; 155 156 /* Register with Card Services */ 157 link->next = dev_list; 158 dev_list = link; 159 client_reg.dev_info = &dev_info; 160 client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; 161 client_reg.EventMask = 162 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | 163 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | 164 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; 165 client_reg.event_handler = &ide_event; 166 client_reg.Version = 0x0210; 167 client_reg.event_callback_args.client_data = link; 168 ret = CardServices(RegisterClient, &link->handle, &client_reg); 169 if (ret != CS_SUCCESS) { 170 cs_error(link->handle, RegisterClient, ret); 171 ide_detach(link); 172 return NULL; 173 } 174 175 return link; 176} /* ide_attach */ 177 178/*====================================================================== 179 180 This deletes a driver "instance". The device is de-registered 181 with Card Services. If it has been released, all local data 182 structures are freed. Otherwise, the structures will be freed 183 when the device is released. 184 185======================================================================*/ 186 187static void ide_detach(dev_link_t *link) 188{ 189 dev_link_t **linkp; 190 int ret; 191 192 DEBUG(0, "ide_detach(0x%p)\n", link); 193 194 /* Locate device structure */ 195 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) 196 if (*linkp == link) break; 197 if (*linkp == NULL) 198 return; 199 200 del_timer(&link->release); 201 if (link->state & DEV_CONFIG) 202 ide_release((u_long)link); 203 204 if (link->handle) { 205 ret = CardServices(DeregisterClient, link->handle); 206 if (ret != CS_SUCCESS) 207 cs_error(link->handle, DeregisterClient, ret); 208 } 209 210 /* Unlink, free device structure */ 211 *linkp = link->next; 212 kfree(link->priv); 213 214} /* ide_detach */ 215 216/*====================================================================== 217 218 ide_config() is scheduled to run after a CARD_INSERTION event 219 is received, to configure the PCMCIA socket, and to make the 220 ide device available to the system. 221 222======================================================================*/ 223 224#define CS_CHECK(fn, args...) \ 225while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed 226 227#define CFG_CHECK(fn, args...) \ 228if (CardServices(fn, args) != 0) goto next_entry 229 230int idecs_register (int arg1, int arg2, int irq) 231{ 232 hw_regs_t hw; 233 ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL); 234 hw.irq = irq; 235 hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */ 236 return ide_register_hw(&hw, NULL); 237} 238 239void ide_config(dev_link_t *link) 240{ 241 client_handle_t handle = link->handle; 242 ide_info_t *info = link->priv; 243 tuple_t tuple; 244 u_short buf[128]; 245 cisparse_t parse; 246 config_info_t conf; 247 cistpl_cftable_entry_t *cfg = &parse.cftable_entry; 248 cistpl_cftable_entry_t dflt = { 0 }; 249 int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base; 250 251 DEBUG(0, "ide_config(0x%p)\n", link); 252 253 tuple.TupleData = (cisdata_t *)buf; 254 tuple.TupleOffset = 0; tuple.TupleDataMax = 255; 255 tuple.Attributes = 0; 256 tuple.DesiredTuple = CISTPL_CONFIG; 257 CS_CHECK(GetFirstTuple, handle, &tuple); 258 CS_CHECK(GetTupleData, handle, &tuple); 259 CS_CHECK(ParseTuple, handle, &tuple, &parse); 260 link->conf.ConfigBase = parse.config.base; 261 link->conf.Present = parse.config.rmask[0]; 262 263 /* Configure card */ 264 link->state |= DEV_CONFIG; 265 266 /* Not sure if this is right... look up the current Vcc */ 267 CS_CHECK(GetConfigurationInfo, handle, &conf); 268 link->conf.Vcc = conf.Vcc; 269 270 pass = io_base = ctl_base = 0; 271 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; 272 tuple.Attributes = 0; 273 CS_CHECK(GetFirstTuple, handle, &tuple); 274 while (1) { 275 CFG_CHECK(GetTupleData, handle, &tuple); 276 CFG_CHECK(ParseTuple, handle, &tuple, &parse); 277 278 /* Check for matching Vcc, unless we're desperate */ 279 if (!pass) { 280 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { 281 if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) 282 goto next_entry; 283 } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) { 284 if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) 285 goto next_entry; 286 } 287 } 288 289 if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) 290 link->conf.Vpp1 = link->conf.Vpp2 = 291 cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; 292 else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) 293 link->conf.Vpp1 = link->conf.Vpp2 = 294 dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; 295 296 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { 297 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; 298 link->conf.ConfigIndex = cfg->index; 299 link->io.BasePort1 = io->win[0].base; 300 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; 301 if (!(io->flags & CISTPL_IO_16BIT)) 302 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 303 if (io->nwin == 2) { 304 link->io.NumPorts1 = 8; 305 link->io.BasePort2 = io->win[1].base; 306 link->io.NumPorts2 = 1; 307 CFG_CHECK(RequestIO, link->handle, &link->io); 308 io_base = link->io.BasePort1; 309 ctl_base = link->io.BasePort2; 310 } else if ((io->nwin == 1) && (io->win[0].len >= 16)) { 311 link->io.NumPorts1 = io->win[0].len; 312 link->io.NumPorts2 = 0; 313 CFG_CHECK(RequestIO, link->handle, &link->io); 314 io_base = link->io.BasePort1; 315 ctl_base = link->io.BasePort1+0x0e; 316 } else goto next_entry; 317 /* If we've got this far, we're done */ 318 break; 319 } 320 321 next_entry: 322 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; 323 if (pass) { 324 CS_CHECK(GetNextTuple, handle, &tuple); 325 } else if (CardServices(GetNextTuple, handle, &tuple) != 0) { 326 CS_CHECK(GetFirstTuple, handle, &tuple); 327 memset(&dflt, 0, sizeof(dflt)); 328 pass++; 329 } 330 } 331 332 CS_CHECK(RequestIRQ, handle, &link->irq); 333 CS_CHECK(RequestConfiguration, handle, &link->conf); 334 335 /* deal with brain dead IDE resource management */ 336 release_region(link->io.BasePort1, link->io.NumPorts1); 337 if (link->io.NumPorts2) 338 release_region(link->io.BasePort2, link->io.NumPorts2); 339 340 /* retry registration in case device is still spinning up */ 341 for (i = 0; i < 10; i++) { 342 if (ctl_base) 343 outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */ 344 hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ); 345 if (hd >= 0) break; 346 if (link->io.NumPorts1 == 0x20) { 347 if (ctl_base) 348 outb(0x02, ctl_base+0x10); 349 hd = idecs_register(io_base+0x10, ctl_base+0x10, 350 link->irq.AssignedIRQ); 351 if (hd >= 0) { 352 io_base += 0x10; ctl_base += 0x10; 353 break; 354 } 355 } 356 __set_current_state(TASK_UNINTERRUPTIBLE); 357 schedule_timeout(HZ/10); 358 } 359 360 if (hd < 0) { 361 printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x" 362 ", irq %u failed\n", io_base, ctl_base, 363 link->irq.AssignedIRQ); 364 goto failed; 365 } 366 367 MOD_INC_USE_COUNT; 368 info->ndev = 1; 369 sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2)); 370 info->node.major = ide_major[hd]; 371 info->node.minor = 0; 372 info->hd = hd; 373 link->dev = &info->node; 374 printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n", 375 info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10, 376 link->conf.Vpp1/10, link->conf.Vpp1%10); 377 378 link->state &= ~DEV_CONFIG_PENDING; 379 return; 380 381cs_failed: 382 cs_error(link->handle, last_fn, last_ret); 383failed: 384 ide_release((u_long)link); 385 386} /* ide_config */ 387 388/*====================================================================== 389 390 After a card is removed, ide_release() will unregister the net 391 device, and release the PCMCIA configuration. If the device is 392 still open, this will be postponed until it is closed. 393 394======================================================================*/ 395 396void ide_release(u_long arg) 397{ 398 dev_link_t *link = (dev_link_t *)arg; 399 ide_info_t *info = link->priv; 400 401 DEBUG(0, "ide_release(0x%p)\n", link); 402 403 if (info->ndev) { 404 ide_unregister(info->hd); 405 MOD_DEC_USE_COUNT; 406 } 407 408 request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs"); 409 if (link->io.NumPorts2) 410 request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs"); 411 412 info->ndev = 0; 413 link->dev = NULL; 414 415 CardServices(ReleaseConfiguration, link->handle); 416 CardServices(ReleaseIO, link->handle, &link->io); 417 CardServices(ReleaseIRQ, link->handle, &link->irq); 418 419 link->state &= ~DEV_CONFIG; 420 421} /* ide_release */ 422 423/*====================================================================== 424 425 The card status event handler. Mostly, this schedules other 426 stuff to run after an event is received. A CARD_REMOVAL event 427 also sets some flags to discourage the ide drivers from 428 talking to the ports. 429 430======================================================================*/ 431 432int ide_event(event_t event, int priority, 433 event_callback_args_t *args) 434{ 435 dev_link_t *link = args->client_data; 436 437 DEBUG(1, "ide_event(0x%06x)\n", event); 438 439 switch (event) { 440 case CS_EVENT_CARD_REMOVAL: 441 link->state &= ~DEV_PRESENT; 442 if (link->state & DEV_CONFIG) 443 mod_timer(&link->release, jiffies + HZ/20); 444 break; 445 case CS_EVENT_CARD_INSERTION: 446 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; 447 ide_config(link); 448 break; 449 case CS_EVENT_PM_SUSPEND: 450 link->state |= DEV_SUSPEND; 451 /* Fall through... */ 452 case CS_EVENT_RESET_PHYSICAL: 453 if (link->state & DEV_CONFIG) 454 CardServices(ReleaseConfiguration, link->handle); 455 break; 456 case CS_EVENT_PM_RESUME: 457 link->state &= ~DEV_SUSPEND; 458 /* Fall through... */ 459 case CS_EVENT_CARD_RESET: 460 if (DEV_OK(link)) 461 CardServices(RequestConfiguration, link->handle, &link->conf); 462 break; 463 } 464 return 0; 465} /* ide_event */ 466 467/*====================================================================*/ 468 469static int __init init_ide_cs(void) 470{ 471 servinfo_t serv; 472 DEBUG(0, "%s\n", version); 473 CardServices(GetCardServicesInfo, &serv); 474 if (serv.Revision != CS_RELEASE_CODE) { 475 printk(KERN_NOTICE "ide_cs: Card Services release " 476 "does not match!\n"); 477 return -1; 478 } 479 register_pccard_driver(&dev_info, &ide_attach, &ide_detach); 480 return 0; 481} 482 483static void __exit exit_ide_cs(void) 484{ 485 DEBUG(0, "ide_cs: unloading\n"); 486 unregister_pccard_driver(&dev_info); 487 while (dev_list != NULL) 488 ide_detach(dev_list); 489} 490 491module_init(init_ide_cs); 492module_exit(exit_ide_cs); 493