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
58 static int pc_debug = PCMCIA_DEBUG;
59 MODULE_PARM(pc_debug, "i");
60 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
61 static 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 */
72 static u_int irq_mask = 0xdeb8;
73 static int irq_list[4] = { -1 };
74
75 MODULE_PARM(irq_mask, "i");
76 MODULE_PARM(irq_list, "1-4i");
77
78 MODULE_LICENSE("GPL");
79
80
81 /*====================================================================*/
82
83 static 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
90 typedef struct ide_info_t {
91 dev_link_t link;
92 int ndev;
93 dev_node_t node;
94 int hd;
95 struct tq_struct rel_task;
96 } ide_info_t;
97
98 static void ide_config(dev_link_t *link);
99 static void ide_release(void *arg);
100 static int ide_event(event_t event, int priority,
101 event_callback_args_t *args);
102
103 static dev_info_t dev_info = "ide-cs";
104
105 static dev_link_t *ide_attach(void);
106 static void ide_detach(dev_link_t *);
107
108 static dev_link_t *dev_list = NULL;
109
110 /*====================================================================*/
111
cs_error(client_handle_t handle,int func,int ret)112 static void cs_error(client_handle_t handle, int func, int ret)
113 {
114 error_info_t err = { func, ret };
115 CardServices(ReportError, handle, &err);
116 }
117
118 /*======================================================================
119
120 ide_attach() creates an "instance" of the driver, allocating
121 local data structures for one device. The device is registered
122 with Card Services.
123
124 ======================================================================*/
125
ide_attach(void)126 static dev_link_t *ide_attach(void)
127 {
128 ide_info_t *info;
129 dev_link_t *link;
130 client_reg_t client_reg;
131 int i, ret;
132
133 DEBUG(0, "ide_attach()\n");
134
135 /* Create new ide device */
136 info = kmalloc(sizeof(*info), GFP_KERNEL);
137 if (!info) return NULL;
138 memset(info, 0, sizeof(*info));
139 link = &info->link; link->priv = info;
140 INIT_TQUEUE(&info->rel_task, ide_release, link);
141
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
ide_detach(dev_link_t * link)187 static void ide_detach(dev_link_t *link)
188 {
189 dev_link_t **linkp;
190 ide_info_t *info = link->priv;
191 int ret;
192
193 DEBUG(0, "ide_detach(0x%p)\n", link);
194
195 /* Locate device structure */
196 for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
197 if (*linkp == link) break;
198 if (*linkp == NULL)
199 return;
200
201 if (link->state & DEV_CONFIG) {
202 schedule_task(&info->rel_task);
203 flush_scheduled_tasks();
204 }
205
206 if (link->handle) {
207 ret = CardServices(DeregisterClient, link->handle);
208 if (ret != CS_SUCCESS)
209 cs_error(link->handle, DeregisterClient, ret);
210 }
211
212 /* Unlink, free device structure */
213 *linkp = link->next;
214 kfree(info);
215
216 } /* ide_detach */
217
218 /*======================================================================
219
220 ide_config() is scheduled to run after a CARD_INSERTION event
221 is received, to configure the PCMCIA socket, and to make the
222 ide device available to the system.
223
224 ======================================================================*/
225
226 #define CS_CHECK(fn, args...) \
227 while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
228
229 #define CFG_CHECK(fn, args...) \
230 if (CardServices(fn, args) != 0) goto next_entry
231
idecs_register(int arg1,int arg2,int irq)232 int idecs_register (int arg1, int arg2, int irq)
233 {
234 hw_regs_t hw;
235 ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
236 hw.irq = irq;
237 hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
238 return ide_register_hw(&hw, NULL);
239 }
240
ide_config(dev_link_t * link)241 void ide_config(dev_link_t *link)
242 {
243 client_handle_t handle = link->handle;
244 ide_info_t *info = link->priv;
245 tuple_t tuple;
246 u_short buf[128];
247 cisparse_t parse;
248 config_info_t conf;
249 cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
250 cistpl_cftable_entry_t dflt = { 0 };
251 int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
252
253 DEBUG(0, "ide_config(0x%p)\n", link);
254
255 tuple.TupleData = (cisdata_t *)buf;
256 tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
257 tuple.Attributes = 0;
258 tuple.DesiredTuple = CISTPL_CONFIG;
259 CS_CHECK(GetFirstTuple, handle, &tuple);
260 CS_CHECK(GetTupleData, handle, &tuple);
261 CS_CHECK(ParseTuple, handle, &tuple, &parse);
262 link->conf.ConfigBase = parse.config.base;
263 link->conf.Present = parse.config.rmask[0];
264
265 /* Configure card */
266 link->state |= DEV_CONFIG;
267
268 /* Not sure if this is right... look up the current Vcc */
269 CS_CHECK(GetConfigurationInfo, handle, &conf);
270 link->conf.Vcc = conf.Vcc;
271
272 pass = io_base = ctl_base = 0;
273 tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
274 tuple.Attributes = 0;
275 CS_CHECK(GetFirstTuple, handle, &tuple);
276 while (1) {
277 CFG_CHECK(GetTupleData, handle, &tuple);
278 CFG_CHECK(ParseTuple, handle, &tuple, &parse);
279
280 /* Check for matching Vcc, unless we're desperate */
281 if (!pass) {
282 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
283 if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
284 goto next_entry;
285 } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
286 if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
287 goto next_entry;
288 }
289 }
290
291 if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
292 link->conf.Vpp1 = link->conf.Vpp2 =
293 cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
294 else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
295 link->conf.Vpp1 = link->conf.Vpp2 =
296 dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
297
298 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
299 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
300 link->conf.ConfigIndex = cfg->index;
301 link->io.BasePort1 = io->win[0].base;
302 link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
303 if (!(io->flags & CISTPL_IO_16BIT))
304 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
305 if (io->nwin == 2) {
306 link->io.NumPorts1 = 8;
307 link->io.BasePort2 = io->win[1].base;
308 link->io.NumPorts2 = 1;
309 CFG_CHECK(RequestIO, link->handle, &link->io);
310 io_base = link->io.BasePort1;
311 ctl_base = link->io.BasePort2;
312 } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
313 link->io.NumPorts1 = io->win[0].len;
314 link->io.NumPorts2 = 0;
315 CFG_CHECK(RequestIO, link->handle, &link->io);
316 io_base = link->io.BasePort1;
317 ctl_base = link->io.BasePort1+0x0e;
318 } else goto next_entry;
319 /* If we've got this far, we're done */
320 break;
321 }
322
323 next_entry:
324 if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
325 if (pass) {
326 CS_CHECK(GetNextTuple, handle, &tuple);
327 } else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
328 CS_CHECK(GetFirstTuple, handle, &tuple);
329 memset(&dflt, 0, sizeof(dflt));
330 pass++;
331 }
332 }
333
334 CS_CHECK(RequestIRQ, handle, &link->irq);
335 CS_CHECK(RequestConfiguration, handle, &link->conf);
336
337 /* deal with brain dead IDE resource management */
338 release_region(link->io.BasePort1, link->io.NumPorts1);
339 if (link->io.NumPorts2)
340 release_region(link->io.BasePort2, link->io.NumPorts2);
341
342 /* retry registration in case device is still spinning up */
343 for (i = 0; i < 10; i++) {
344 if (ctl_base)
345 outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
346 hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
347 if (hd >= 0) break;
348 if (link->io.NumPorts1 == 0x20) {
349 if (ctl_base)
350 outb(0x02, ctl_base+0x10);
351 hd = idecs_register(io_base+0x10, ctl_base+0x10,
352 link->irq.AssignedIRQ);
353 if (hd >= 0) {
354 io_base += 0x10; ctl_base += 0x10;
355 break;
356 }
357 }
358 __set_current_state(TASK_UNINTERRUPTIBLE);
359 schedule_timeout(HZ/10);
360 }
361
362 if (hd < 0) {
363 printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
364 ", irq %u failed\n", io_base, ctl_base,
365 link->irq.AssignedIRQ);
366 goto failed;
367 }
368
369 MOD_INC_USE_COUNT;
370 info->ndev = 1;
371 sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
372 info->node.major = ide_major[hd];
373 info->node.minor = 0;
374 info->hd = hd;
375 link->dev = &info->node;
376 printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
377 info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
378 link->conf.Vpp1/10, link->conf.Vpp1%10);
379
380 link->state &= ~DEV_CONFIG_PENDING;
381 return;
382
383 cs_failed:
384 cs_error(link->handle, last_fn, last_ret);
385 failed:
386 ide_release(link);
387
388 } /* ide_config */
389
390 /*======================================================================
391
392 After a card is removed, ide_release() will unregister the net
393 device, and release the PCMCIA configuration. If the device is
394 still open, this will be postponed until it is closed.
395
396 ======================================================================*/
397
ide_release(void * arg)398 static void ide_release(void *arg)
399 {
400 dev_link_t *link = arg;
401 ide_info_t *info = link->priv;
402
403 if (!(link->state & DEV_CONFIG))
404 return;
405
406 DEBUG(0, "ide_do_release(0x%p)\n", link);
407
408 if (info->ndev) {
409 /* FIXME: if this fails we need to queue the cleanup somehow
410 -- need to investigate the required PCMCIA magic */
411 ide_unregister(info->hd);
412 MOD_DEC_USE_COUNT;
413 }
414
415 request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
416 if (link->io.NumPorts2)
417 request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
418
419 info->ndev = 0;
420 link->dev = NULL;
421
422 CardServices(ReleaseConfiguration, link->handle);
423 CardServices(ReleaseIO, link->handle, &link->io);
424 CardServices(ReleaseIRQ, link->handle, &link->irq);
425
426 link->state &= ~DEV_CONFIG;
427
428 } /* ide_release */
429
430 /*======================================================================
431
432 The card status event handler. Mostly, this schedules other
433 stuff to run after an event is received. A CARD_REMOVAL event
434 also sets some flags to discourage the ide drivers from
435 talking to the ports.
436
437 ======================================================================*/
438
ide_event(event_t event,int priority,event_callback_args_t * args)439 int ide_event(event_t event, int priority,
440 event_callback_args_t *args)
441 {
442 dev_link_t *link = args->client_data;
443 ide_info_t *info = link->priv;
444
445 DEBUG(1, "ide_event(0x%06x)\n", event);
446
447 switch (event) {
448 case CS_EVENT_CARD_REMOVAL:
449 link->state &= ~DEV_PRESENT;
450 if (link->state & DEV_CONFIG)
451 schedule_task(&info->rel_task);
452 break;
453 case CS_EVENT_CARD_INSERTION:
454 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
455 ide_config(link);
456 break;
457 case CS_EVENT_PM_SUSPEND:
458 link->state |= DEV_SUSPEND;
459 /* Fall through... */
460 case CS_EVENT_RESET_PHYSICAL:
461 if (link->state & DEV_CONFIG)
462 CardServices(ReleaseConfiguration, link->handle);
463 break;
464 case CS_EVENT_PM_RESUME:
465 link->state &= ~DEV_SUSPEND;
466 /* Fall through... */
467 case CS_EVENT_CARD_RESET:
468 if (DEV_OK(link))
469 CardServices(RequestConfiguration, link->handle, &link->conf);
470 break;
471 }
472 return 0;
473 } /* ide_event */
474
475 /*====================================================================*/
476
init_ide_cs(void)477 static int __init init_ide_cs(void)
478 {
479 servinfo_t serv;
480 DEBUG(0, "%s\n", version);
481 CardServices(GetCardServicesInfo, &serv);
482 if (serv.Revision != CS_RELEASE_CODE) {
483 printk(KERN_NOTICE "ide_cs: Card Services release "
484 "does not match!\n");
485 return -1;
486 }
487 register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
488 return 0;
489 }
490
exit_ide_cs(void)491 static void __exit exit_ide_cs(void)
492 {
493 DEBUG(0, "ide_cs: unloading\n");
494 unregister_pccard_driver(&dev_info);
495 while (dev_list != NULL)
496 ide_detach(dev_list);
497 }
498
499 module_init(init_ide_cs);
500 module_exit(exit_ide_cs);
501