import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / ide / legacy / ide-cs.c
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
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
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
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
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
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     outb(0x02, ctl_base); // Set nIEN = disable device interrupts
343
344     /* retry registration in case device is still spinning up */
345     for (i = 0; i < 10; i++) {
346         if (ctl_base)
347             outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
348         hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
349         if (hd >= 0) break;
350         if (link->io.NumPorts1 == 0x20) {
351             if (ctl_base)
352                 outb(0x02, ctl_base+0x10);
353             hd = idecs_register(io_base+0x10, ctl_base+0x10,
354                               link->irq.AssignedIRQ);
355             if (hd >= 0) {
356                 io_base += 0x10; ctl_base += 0x10;
357                 break;
358             }
359         }
360         __set_current_state(TASK_UNINTERRUPTIBLE);
361         schedule_timeout(HZ/10);
362     }
363     
364     if (hd < 0) {
365         printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
366                ", irq %u failed\n", io_base, ctl_base,
367                link->irq.AssignedIRQ);
368         goto failed;
369     }
370
371     MOD_INC_USE_COUNT;
372     info->ndev = 1;
373     sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
374     info->node.major = ide_major[hd];
375     info->node.minor = 0;
376     info->hd = hd;
377     link->dev = &info->node;
378     printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
379            info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
380            link->conf.Vpp1/10, link->conf.Vpp1%10);
381
382     link->state &= ~DEV_CONFIG_PENDING;
383     return;
384     
385 cs_failed:
386     cs_error(link->handle, last_fn, last_ret);
387 failed:
388     ide_release(link);
389
390 } /* ide_config */
391
392 /*======================================================================
393
394     After a card is removed, ide_release() will unregister the net
395     device, and release the PCMCIA configuration.  If the device is
396     still open, this will be postponed until it is closed.
397     
398 ======================================================================*/
399
400 static void ide_release(void *arg)
401 {
402     dev_link_t *link = arg;
403     ide_info_t *info = link->priv;
404     
405     if (!(link->state & DEV_CONFIG))
406         return;
407
408     DEBUG(0, "ide_do_release(0x%p)\n", link);
409
410     if (info->ndev) {
411         /* FIXME: if this fails we need to queue the cleanup somehow
412            -- need to investigate the required PCMCIA magic */
413         ide_unregister(info->hd);
414         MOD_DEC_USE_COUNT;
415     }
416
417     request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
418     if (link->io.NumPorts2)
419         request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
420     
421     info->ndev = 0;
422     link->dev = NULL;
423     
424     CardServices(ReleaseConfiguration, link->handle);
425     CardServices(ReleaseIO, link->handle, &link->io);
426     CardServices(ReleaseIRQ, link->handle, &link->irq);
427     
428     link->state &= ~DEV_CONFIG;
429
430 } /* ide_release */
431
432 /*======================================================================
433
434     The card status event handler.  Mostly, this schedules other
435     stuff to run after an event is received.  A CARD_REMOVAL event
436     also sets some flags to discourage the ide drivers from
437     talking to the ports.
438     
439 ======================================================================*/
440
441 int ide_event(event_t event, int priority,
442               event_callback_args_t *args)
443 {
444     dev_link_t *link = args->client_data;
445     ide_info_t *info = link->priv;
446
447     DEBUG(1, "ide_event(0x%06x)\n", event);
448     
449     switch (event) {
450     case CS_EVENT_CARD_REMOVAL:
451         link->state &= ~DEV_PRESENT;
452         if (link->state & DEV_CONFIG)
453             schedule_task(&info->rel_task);
454         break;
455     case CS_EVENT_CARD_INSERTION:
456         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
457         ide_config(link);
458         break;
459     case CS_EVENT_PM_SUSPEND:
460         link->state |= DEV_SUSPEND;
461         /* Fall through... */
462     case CS_EVENT_RESET_PHYSICAL:
463         if (link->state & DEV_CONFIG)
464             CardServices(ReleaseConfiguration, link->handle);
465         break;
466     case CS_EVENT_PM_RESUME:
467         link->state &= ~DEV_SUSPEND;
468         /* Fall through... */
469     case CS_EVENT_CARD_RESET:
470         if (DEV_OK(link))
471             CardServices(RequestConfiguration, link->handle, &link->conf);
472         break;
473     }
474     return 0;
475 } /* ide_event */
476
477 /*====================================================================*/
478
479 static int __init init_ide_cs(void)
480 {
481     servinfo_t serv;
482     DEBUG(0, "%s\n", version);
483     CardServices(GetCardServicesInfo, &serv);
484     if (serv.Revision != CS_RELEASE_CODE) {
485         printk(KERN_NOTICE "ide_cs: Card Services release "
486                "does not match!\n");
487         return -1;
488     }
489     register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
490     return 0;
491 }
492
493 static void __exit exit_ide_cs(void)
494 {
495     DEBUG(0, "ide_cs: unloading\n");
496     unregister_pccard_driver(&dev_info);
497     while (dev_list != NULL)
498         ide_detach(dev_list);
499 }
500
501 module_init(init_ide_cs);
502 module_exit(exit_ide_cs);