update atp870u driver to 0.78 from D-Link source
[linux-2.4.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     /* 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
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
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
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
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);