ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / ide / legacy / ide-cs.c
1 /*======================================================================
2
3     A driver for PCMCIA IDE/ATA disk cards
4
5     ide-cs.c 1.3 2002/10/26 05:45:31
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
23     which 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/ide.h>
44 #include <linux/hdreg.h>
45 #include <linux/major.h>
46 #include <asm/io.h>
47 #include <asm/system.h>
48
49 #include <pcmcia/version.h>
50 #include <pcmcia/cs_types.h>
51 #include <pcmcia/cs.h>
52 #include <pcmcia/cistpl.h>
53 #include <pcmcia/ds.h>
54 #include <pcmcia/cisreg.h>
55 #include <pcmcia/ciscode.h>
56
57 /*====================================================================*/
58
59 /* Module parameters */
60
61 MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
62 MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver");
63 MODULE_LICENSE("Dual MPL/GPL");
64
65 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
66
67 /* Bit map of interrupts to choose from */
68 INT_MODULE_PARM(irq_mask, 0xdeb8);
69 static int irq_list[4] = { -1 };
70 MODULE_PARM(irq_list, "1-4i");
71
72 #ifdef PCMCIA_DEBUG
73 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
74 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
75 static char *version =
76 "ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)";
77 #else
78 #define DEBUG(n, args...)
79 #endif
80
81 /*====================================================================*/
82
83 static const char ide_major[] = {
84     IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
85     IDE4_MAJOR, IDE5_MAJOR
86 };
87
88 typedef struct ide_info_t {
89     dev_link_t  link;
90     int         ndev;
91     dev_node_t  node;
92     int         hd;
93 } ide_info_t;
94
95 static void ide_release(dev_link_t *);
96 static int ide_event(event_t event, int priority,
97                      event_callback_args_t *args);
98
99 static dev_info_t dev_info = "ide-cs";
100
101 static dev_link_t *ide_attach(void);
102 static void ide_detach(dev_link_t *);
103
104 static dev_link_t *dev_list = NULL;
105
106 /*======================================================================
107
108     ide_attach() creates an "instance" of the driver, allocating
109     local data structures for one device.  The device is registered
110     with Card Services.
111
112 ======================================================================*/
113
114 static dev_link_t *ide_attach(void)
115 {
116     ide_info_t *info;
117     dev_link_t *link;
118     client_reg_t client_reg;
119     int i, ret;
120     
121     DEBUG(0, "ide_attach()\n");
122
123     /* Create new ide device */
124     info = kmalloc(sizeof(*info), GFP_KERNEL);
125     if (!info) return NULL;
126     memset(info, 0, sizeof(*info));
127     link = &info->link; link->priv = info;
128
129     link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
130     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
131     link->io.IOAddrLines = 3;
132     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
133     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
134     if (irq_list[0] == -1)
135         link->irq.IRQInfo2 = irq_mask;
136     else
137         for (i = 0; i < 4; i++)
138             link->irq.IRQInfo2 |= 1 << irq_list[i];
139     link->conf.Attributes = CONF_ENABLE_IRQ;
140     link->conf.Vcc = 50;
141     link->conf.IntType = INT_MEMORY_AND_IO;
142     
143     /* Register with Card Services */
144     link->next = dev_list;
145     dev_list = link;
146     client_reg.dev_info = &dev_info;
147     client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
148     client_reg.EventMask =
149         CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
150         CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
151         CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
152     client_reg.event_handler = &ide_event;
153     client_reg.Version = 0x0210;
154     client_reg.event_callback_args.client_data = link;
155     ret = pcmcia_register_client(&link->handle, &client_reg);
156     if (ret != CS_SUCCESS) {
157         cs_error(link->handle, RegisterClient, ret);
158         ide_detach(link);
159         return NULL;
160     }
161     
162     return link;
163 } /* ide_attach */
164
165 /*======================================================================
166
167     This deletes a driver "instance".  The device is de-registered
168     with Card Services.  If it has been released, all local data
169     structures are freed.  Otherwise, the structures will be freed
170     when the device is released.
171
172 ======================================================================*/
173
174 static void ide_detach(dev_link_t *link)
175 {
176     dev_link_t **linkp;
177     int ret;
178
179     DEBUG(0, "ide_detach(0x%p)\n", link);
180     
181     /* Locate device structure */
182     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
183         if (*linkp == link) break;
184     if (*linkp == NULL)
185         return;
186
187     if (link->state & DEV_CONFIG)
188         ide_release(link);
189     
190     if (link->handle) {
191         ret = pcmcia_deregister_client(link->handle);
192         if (ret != CS_SUCCESS)
193             cs_error(link->handle, DeregisterClient, ret);
194     }
195     
196     /* Unlink, free device structure */
197     *linkp = link->next;
198     kfree(link->priv);
199     
200 } /* ide_detach */
201
202 /*======================================================================
203
204     ide_config() is scheduled to run after a CARD_INSERTION event
205     is received, to configure the PCMCIA socket, and to make the
206     ide device available to the system.
207
208 ======================================================================*/
209
210 #define CS_CHECK(fn, ret) \
211 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
212
213 static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq)
214 {
215     hw_regs_t hw;
216     memset(&hw, 0, sizeof(hw));
217     ide_init_hwif_ports(&hw, io, ctl, NULL);
218     hw.irq = irq;
219     hw.chipset = ide_pci;
220     return ide_register_hw(&hw, NULL);
221 }
222
223 void ide_config(dev_link_t *link)
224 {
225     client_handle_t handle = link->handle;
226     ide_info_t *info = link->priv;
227     tuple_t tuple;
228     u_short buf[128];
229     cisparse_t parse;
230     config_info_t conf;
231     cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
232     cistpl_cftable_entry_t dflt = { 0 };
233     int i, pass, last_ret, last_fn, hd, is_kme = 0;
234     unsigned long io_base, ctl_base;
235
236     DEBUG(0, "ide_config(0x%p)\n", link);
237     
238     tuple.TupleData = (cisdata_t *)buf;
239     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
240     tuple.Attributes = 0;
241     tuple.DesiredTuple = CISTPL_CONFIG;
242     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
243     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
244     CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
245     link->conf.ConfigBase = parse.config.base;
246     link->conf.Present = parse.config.rmask[0];
247
248     tuple.DesiredTuple = CISTPL_MANFID;
249     if (!pcmcia_get_first_tuple(handle, &tuple) &&
250         !pcmcia_get_tuple_data(handle, &tuple) &&
251         !pcmcia_parse_tuple(handle, &tuple, &parse))
252         is_kme = ((parse.manfid.manf == MANFID_KME) &&
253                   ((parse.manfid.card == PRODID_KME_KXLC005_A) ||
254                    (parse.manfid.card == PRODID_KME_KXLC005_B)));
255
256     /* Configure card */
257     link->state |= DEV_CONFIG;
258
259     /* Not sure if this is right... look up the current Vcc */
260     CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
261     link->conf.Vcc = conf.Vcc;
262     
263     pass = io_base = ctl_base = 0;
264     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
265     tuple.Attributes = 0;
266     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
267     while (1) {
268         if (pcmcia_get_tuple_data(handle, &tuple) != 0) goto next_entry;
269         if (pcmcia_parse_tuple(handle, &tuple, &parse) != 0) goto next_entry;
270
271         /* Check for matching Vcc, unless we're desperate */
272         if (!pass) {
273             if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
274                 if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
275                     goto next_entry;
276             } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
277                 if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
278                     goto next_entry;
279             }
280         }
281         
282         if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
283             link->conf.Vpp1 = link->conf.Vpp2 =
284                 cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
285         else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
286             link->conf.Vpp1 = link->conf.Vpp2 =
287                 dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
288         
289         if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
290             cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
291             link->conf.ConfigIndex = cfg->index;
292             link->io.BasePort1 = io->win[0].base;
293             link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
294             if (!(io->flags & CISTPL_IO_16BIT))
295                 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
296             if (io->nwin == 2) {
297                 link->io.NumPorts1 = 8;
298                 link->io.BasePort2 = io->win[1].base;
299                 link->io.NumPorts2 = (is_kme) ? 2 : 1;
300                 if (pcmcia_request_io(link->handle, &link->io) != 0)
301                         goto next_entry;
302                 io_base = link->io.BasePort1;
303                 ctl_base = link->io.BasePort2;
304             } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
305                 link->io.NumPorts1 = io->win[0].len;
306                 link->io.NumPorts2 = 0;
307                 if (pcmcia_request_io(link->handle, &link->io) != 0)
308                         goto next_entry;
309                 io_base = link->io.BasePort1;
310                 ctl_base = link->io.BasePort1+0x0e;
311             } else goto next_entry;
312             /* If we've got this far, we're done */
313             break;
314         }
315         
316     next_entry:
317         if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
318         if (pass) {
319             CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
320         } else if (pcmcia_get_next_tuple(handle, &tuple) != 0) {
321             CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
322             memset(&dflt, 0, sizeof(dflt));
323             pass++;
324         }
325     }
326     
327     CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
328     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
329
330     /* deal with brain dead IDE resource management */
331     release_region(link->io.BasePort1, link->io.NumPorts1);
332     if (link->io.NumPorts2)
333         release_region(link->io.BasePort2, link->io.NumPorts2);
334
335     /* disable drive interrupts during IDE probe */
336     outb(0x02, ctl_base);
337
338     /* special setup for KXLC005 card */
339     if (is_kme) outb(0x81, ctl_base+1);
340
341     /* retry registration in case device is still spinning up */
342     for (hd = -1, i = 0; i < 10; i++) {
343         hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
344         if (hd >= 0) break;
345         if (link->io.NumPorts1 == 0x20) {
346             outb(0x02, ctl_base+0x10);
347             hd = idecs_register(io_base+0x10, ctl_base+0x10,
348                                 link->irq.AssignedIRQ);
349             if (hd >= 0) {
350                 io_base += 0x10; ctl_base += 0x10;
351                 break;
352             }
353         }
354         __set_current_state(TASK_UNINTERRUPTIBLE);
355         schedule_timeout(HZ/10);
356     }
357     
358     if (hd < 0) {
359         printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3lx & 0x%3lx"
360                ", irq %u failed\n", io_base, ctl_base,
361                link->irq.AssignedIRQ);
362         goto failed;
363     }
364
365     info->ndev = 1;
366     sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
367     info->node.major = ide_major[hd];
368     info->node.minor = 0;
369     info->hd = hd;
370     link->dev = &info->node;
371     printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
372            info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
373            link->conf.Vpp1/10, link->conf.Vpp1%10);
374
375     link->state &= ~DEV_CONFIG_PENDING;
376     return;
377     
378 cs_failed:
379     cs_error(link->handle, last_fn, last_ret);
380 failed:
381     ide_release(link);
382     link->state &= ~DEV_CONFIG_PENDING;
383
384 } /* ide_config */
385
386 /*======================================================================
387
388     After a card is removed, ide_release() will unregister the net
389     device, and release the PCMCIA configuration.  If the device is
390     still open, this will be postponed until it is closed.
391     
392 ======================================================================*/
393
394 void ide_release(dev_link_t *link)
395 {
396     ide_info_t *info = link->priv;
397     
398     DEBUG(0, "ide_release(0x%p)\n", link);
399
400     if (info->ndev) {
401         /* FIXME: if this fails we need to queue the cleanup somehow
402            -- need to investigate the required PCMCIA magic */
403         ide_unregister(info->hd);
404         /* deal with brain dead IDE resource management */
405         request_region(link->io.BasePort1, link->io.NumPorts1,
406                        info->node.dev_name);
407         if (link->io.NumPorts2)
408             request_region(link->io.BasePort2, link->io.NumPorts2,
409                            info->node.dev_name);
410     }
411     info->ndev = 0;
412     link->dev = NULL;
413     
414     pcmcia_release_configuration(link->handle);
415     pcmcia_release_io(link->handle, &link->io);
416     pcmcia_release_irq(link->handle, &link->irq);
417     
418     link->state &= ~DEV_CONFIG;
419
420 } /* ide_release */
421
422 /*======================================================================
423
424     The card status event handler.  Mostly, this schedules other
425     stuff to run after an event is received.  A CARD_REMOVAL event
426     also sets some flags to discourage the ide drivers from
427     talking to the ports.
428     
429 ======================================================================*/
430
431 int ide_event(event_t event, int priority,
432               event_callback_args_t *args)
433 {
434     dev_link_t *link = args->client_data;
435
436     DEBUG(1, "ide_event(0x%06x)\n", event);
437     
438     switch (event) {
439     case CS_EVENT_CARD_REMOVAL:
440         link->state &= ~DEV_PRESENT;
441         if (link->state & DEV_CONFIG)
442                 ide_release(link);
443         break;
444     case CS_EVENT_CARD_INSERTION:
445         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
446         ide_config(link);
447         break;
448     case CS_EVENT_PM_SUSPEND:
449         link->state |= DEV_SUSPEND;
450         /* Fall through... */
451     case CS_EVENT_RESET_PHYSICAL:
452         if (link->state & DEV_CONFIG)
453             pcmcia_release_configuration(link->handle);
454         break;
455     case CS_EVENT_PM_RESUME:
456         link->state &= ~DEV_SUSPEND;
457         /* Fall through... */
458     case CS_EVENT_CARD_RESET:
459         if (DEV_OK(link))
460             pcmcia_request_configuration(link->handle, &link->conf);
461         break;
462     }
463     return 0;
464 } /* ide_event */
465
466 static struct pcmcia_driver ide_cs_driver = {
467         .owner          = THIS_MODULE,
468         .drv            = {
469                 .name   = "ide-cs",
470         },
471         .attach         = ide_attach,
472         .detach         = ide_detach,
473 };
474
475 static int __init init_ide_cs(void)
476 {
477         return pcmcia_register_driver(&ide_cs_driver);
478 }
479
480 static void __exit exit_ide_cs(void)
481 {
482         pcmcia_unregister_driver(&ide_cs_driver);
483         while (dev_list != NULL)
484                 ide_detach(dev_list);
485 }
486
487 module_init(init_ide_cs);
488 module_exit(exit_ide_cs);