[PATCH] ARM SMP: TLB implementations only affect local CPU
[linux-2.6] / 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_param(n, int, 0)
66
67 #ifdef PCMCIA_DEBUG
68 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
69 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
70 static char *version =
71 "ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)";
72 #else
73 #define DEBUG(n, args...)
74 #endif
75
76 /*====================================================================*/
77
78 static const char ide_major[] = {
79     IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
80     IDE4_MAJOR, IDE5_MAJOR
81 };
82
83 typedef struct ide_info_t {
84     dev_link_t  link;
85     int         ndev;
86     dev_node_t  node;
87     int         hd;
88 } ide_info_t;
89
90 static void ide_release(dev_link_t *);
91 static int ide_event(event_t event, int priority,
92                      event_callback_args_t *args);
93
94 static dev_info_t dev_info = "ide-cs";
95
96 static dev_link_t *ide_attach(void);
97 static void ide_detach(dev_link_t *);
98
99 static dev_link_t *dev_list = NULL;
100
101 /*======================================================================
102
103     ide_attach() creates an "instance" of the driver, allocating
104     local data structures for one device.  The device is registered
105     with Card Services.
106
107 ======================================================================*/
108
109 static dev_link_t *ide_attach(void)
110 {
111     ide_info_t *info;
112     dev_link_t *link;
113     client_reg_t client_reg;
114     int ret;
115     
116     DEBUG(0, "ide_attach()\n");
117
118     /* Create new ide device */
119     info = kmalloc(sizeof(*info), GFP_KERNEL);
120     if (!info) return NULL;
121     memset(info, 0, sizeof(*info));
122     link = &info->link; link->priv = info;
123
124     link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
125     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
126     link->io.IOAddrLines = 3;
127     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
128     link->irq.IRQInfo1 = IRQ_LEVEL_ID;
129     link->conf.Attributes = CONF_ENABLE_IRQ;
130     link->conf.Vcc = 50;
131     link->conf.IntType = INT_MEMORY_AND_IO;
132     
133     /* Register with Card Services */
134     link->next = dev_list;
135     dev_list = link;
136     client_reg.dev_info = &dev_info;
137     client_reg.EventMask =
138         CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
139         CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
140         CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
141     client_reg.event_handler = &ide_event;
142     client_reg.Version = 0x0210;
143     client_reg.event_callback_args.client_data = link;
144     ret = pcmcia_register_client(&link->handle, &client_reg);
145     if (ret != CS_SUCCESS) {
146         cs_error(link->handle, RegisterClient, ret);
147         ide_detach(link);
148         return NULL;
149     }
150     
151     return link;
152 } /* ide_attach */
153
154 /*======================================================================
155
156     This deletes a driver "instance".  The device is de-registered
157     with Card Services.  If it has been released, all local data
158     structures are freed.  Otherwise, the structures will be freed
159     when the device is released.
160
161 ======================================================================*/
162
163 static void ide_detach(dev_link_t *link)
164 {
165     dev_link_t **linkp;
166     int ret;
167
168     DEBUG(0, "ide_detach(0x%p)\n", link);
169     
170     /* Locate device structure */
171     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
172         if (*linkp == link) break;
173     if (*linkp == NULL)
174         return;
175
176     if (link->state & DEV_CONFIG)
177         ide_release(link);
178     
179     if (link->handle) {
180         ret = pcmcia_deregister_client(link->handle);
181         if (ret != CS_SUCCESS)
182             cs_error(link->handle, DeregisterClient, ret);
183     }
184     
185     /* Unlink, free device structure */
186     *linkp = link->next;
187     kfree(link->priv);
188     
189 } /* ide_detach */
190
191 static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq)
192 {
193     hw_regs_t hw;
194     memset(&hw, 0, sizeof(hw));
195     ide_init_hwif_ports(&hw, io, ctl, NULL);
196     hw.irq = irq;
197     hw.chipset = ide_pci;
198     return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave);
199 }
200
201 /*======================================================================
202
203     ide_config() is scheduled to run after a CARD_INSERTION event
204     is received, to configure the PCMCIA socket, and to make the
205     ide device available to the system.
206
207 ======================================================================*/
208
209 #define CS_CHECK(fn, ret) \
210 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
211
212 static void ide_config(dev_link_t *link)
213 {
214     client_handle_t handle = link->handle;
215     ide_info_t *info = link->priv;
216     tuple_t tuple;
217     struct {
218         u_short         buf[128];
219         cisparse_t      parse;
220         config_info_t   conf;
221         cistpl_cftable_entry_t dflt;
222     } *stk = NULL;
223     cistpl_cftable_entry_t *cfg;
224     int i, pass, last_ret = 0, last_fn = 0, hd, is_kme = 0;
225     unsigned long io_base, ctl_base;
226
227     DEBUG(0, "ide_config(0x%p)\n", link);
228
229     stk = kmalloc(sizeof(*stk), GFP_KERNEL);
230     if (!stk) goto err_mem;
231     memset(stk, 0, sizeof(*stk));
232     cfg = &stk->parse.cftable_entry;
233
234     tuple.TupleData = (cisdata_t *)&stk->buf;
235     tuple.TupleOffset = 0;
236     tuple.TupleDataMax = 255;
237     tuple.Attributes = 0;
238     tuple.DesiredTuple = CISTPL_CONFIG;
239     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
240     CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
241     CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &stk->parse));
242     link->conf.ConfigBase = stk->parse.config.base;
243     link->conf.Present = stk->parse.config.rmask[0];
244
245     tuple.DesiredTuple = CISTPL_MANFID;
246     if (!pcmcia_get_first_tuple(handle, &tuple) &&
247         !pcmcia_get_tuple_data(handle, &tuple) &&
248         !pcmcia_parse_tuple(handle, &tuple, &stk->parse))
249         is_kme = ((stk->parse.manfid.manf == MANFID_KME) &&
250                   ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) ||
251                    (stk->parse.manfid.card == PRODID_KME_KXLC005_B)));
252
253     /* Configure card */
254     link->state |= DEV_CONFIG;
255
256     /* Not sure if this is right... look up the current Vcc */
257     CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &stk->conf));
258     link->conf.Vcc = stk->conf.Vcc;
259
260     pass = io_base = ctl_base = 0;
261     tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
262     tuple.Attributes = 0;
263     CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
264     while (1) {
265         if (pcmcia_get_tuple_data(handle, &tuple) != 0) goto next_entry;
266         if (pcmcia_parse_tuple(handle, &tuple, &stk->parse) != 0) goto next_entry;
267
268         /* Check for matching Vcc, unless we're desperate */
269         if (!pass) {
270             if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
271                 if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
272                     goto next_entry;
273             } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
274                 if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
275                     goto next_entry;
276             }
277         }
278
279         if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
280             link->conf.Vpp1 = link->conf.Vpp2 =
281                 cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
282         else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
283             link->conf.Vpp1 = link->conf.Vpp2 =
284                 stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
285
286         if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
287             cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
288             link->conf.ConfigIndex = cfg->index;
289             link->io.BasePort1 = io->win[0].base;
290             link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
291             if (!(io->flags & CISTPL_IO_16BIT))
292                 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
293             if (io->nwin == 2) {
294                 link->io.NumPorts1 = 8;
295                 link->io.BasePort2 = io->win[1].base;
296                 link->io.NumPorts2 = (is_kme) ? 2 : 1;
297                 if (pcmcia_request_io(link->handle, &link->io) != 0)
298                         goto next_entry;
299                 io_base = link->io.BasePort1;
300                 ctl_base = link->io.BasePort2;
301             } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
302                 link->io.NumPorts1 = io->win[0].len;
303                 link->io.NumPorts2 = 0;
304                 if (pcmcia_request_io(link->handle, &link->io) != 0)
305                         goto next_entry;
306                 io_base = link->io.BasePort1;
307                 ctl_base = link->io.BasePort1 + 0x0e;
308             } else goto next_entry;
309             /* If we've got this far, we're done */
310             break;
311         }
312
313     next_entry:
314         if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
315             memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
316         if (pass) {
317             CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
318         } else if (pcmcia_get_next_tuple(handle, &tuple) != 0) {
319             CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
320             memset(&stk->dflt, 0, sizeof(stk->dflt));
321             pass++;
322         }
323     }
324
325     CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
326     CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
327
328     /* disable drive interrupts during IDE probe */
329     outb(0x02, ctl_base);
330
331     /* special setup for KXLC005 card */
332     if (is_kme)
333         outb(0x81, ctl_base+1);
334
335     /* retry registration in case device is still spinning up */
336     for (hd = -1, i = 0; i < 10; i++) {
337         hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
338         if (hd >= 0) break;
339         if (link->io.NumPorts1 == 0x20) {
340             outb(0x02, ctl_base + 0x10);
341             hd = idecs_register(io_base + 0x10, ctl_base + 0x10,
342                                 link->irq.AssignedIRQ);
343             if (hd >= 0) {
344                 io_base += 0x10;
345                 ctl_base += 0x10;
346                 break;
347             }
348         }
349         __set_current_state(TASK_UNINTERRUPTIBLE);
350         schedule_timeout(HZ/10);
351     }
352
353     if (hd < 0) {
354         printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3lx & 0x%3lx"
355                ", irq %u failed\n", io_base, ctl_base,
356                link->irq.AssignedIRQ);
357         goto failed;
358     }
359
360     info->ndev = 1;
361     sprintf(info->node.dev_name, "hd%c", 'a' + (hd * 2));
362     info->node.major = ide_major[hd];
363     info->node.minor = 0;
364     info->hd = hd;
365     link->dev = &info->node;
366     printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
367            info->node.dev_name, link->conf.Vcc / 10, link->conf.Vcc % 10,
368            link->conf.Vpp1 / 10, link->conf.Vpp1 % 10);
369
370     link->state &= ~DEV_CONFIG_PENDING;
371     kfree(stk);
372     return;
373
374 err_mem:
375     printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n");
376     goto failed;
377
378 cs_failed:
379     cs_error(link->handle, last_fn, last_ret);
380 failed:
381     kfree(stk);
382     ide_release(link);
383     link->state &= ~DEV_CONFIG_PENDING;
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     }
405     info->ndev = 0;
406     link->dev = NULL;
407     
408     pcmcia_release_configuration(link->handle);
409     pcmcia_release_io(link->handle, &link->io);
410     pcmcia_release_irq(link->handle, &link->irq);
411     
412     link->state &= ~DEV_CONFIG;
413
414 } /* ide_release */
415
416 /*======================================================================
417
418     The card status event handler.  Mostly, this schedules other
419     stuff to run after an event is received.  A CARD_REMOVAL event
420     also sets some flags to discourage the ide drivers from
421     talking to the ports.
422     
423 ======================================================================*/
424
425 int ide_event(event_t event, int priority,
426               event_callback_args_t *args)
427 {
428     dev_link_t *link = args->client_data;
429
430     DEBUG(1, "ide_event(0x%06x)\n", event);
431     
432     switch (event) {
433     case CS_EVENT_CARD_REMOVAL:
434         link->state &= ~DEV_PRESENT;
435         if (link->state & DEV_CONFIG)
436                 ide_release(link);
437         break;
438     case CS_EVENT_CARD_INSERTION:
439         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
440         ide_config(link);
441         break;
442     case CS_EVENT_PM_SUSPEND:
443         link->state |= DEV_SUSPEND;
444         /* Fall through... */
445     case CS_EVENT_RESET_PHYSICAL:
446         if (link->state & DEV_CONFIG)
447             pcmcia_release_configuration(link->handle);
448         break;
449     case CS_EVENT_PM_RESUME:
450         link->state &= ~DEV_SUSPEND;
451         /* Fall through... */
452     case CS_EVENT_CARD_RESET:
453         if (DEV_OK(link))
454             pcmcia_request_configuration(link->handle, &link->conf);
455         break;
456     }
457     return 0;
458 } /* ide_event */
459
460 static struct pcmcia_device_id ide_ids[] = {
461         PCMCIA_DEVICE_FUNC_ID(4),
462         PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
463         PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
464         PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
465         PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),
466         PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
467         PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
468         PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
469         PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
470         PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
471         PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
472         PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
473         PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
474         PCMCIA_DEVICE_PROD_ID12("EXP", "CD", 0x6f58c983, 0xaae5994f),
475         PCMCIA_DEVICE_PROD_ID12("EXP   ", "CD-ROM", 0x0a5c52fd, 0x66536591),
476         PCMCIA_DEVICE_PROD_ID12("EXP   ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
477         PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
478         PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
479         PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
480         PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
481         PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
482         PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2      ", 0xe37be2b5, 0x8671043b),
483         PCMCIA_DEVICE_PROD_ID12(" ", "NinjaATA-", 0x3b6e20c8, 0xebe0bd79),
484         PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
485         PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
486         PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
487         PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
488         PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
489         PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
490         PCMCIA_DEVICE_NULL,
491 };
492 MODULE_DEVICE_TABLE(pcmcia, ide_ids);
493
494 static struct pcmcia_driver ide_cs_driver = {
495         .owner          = THIS_MODULE,
496         .drv            = {
497                 .name   = "ide-cs",
498         },
499         .attach         = ide_attach,
500         .detach         = ide_detach,
501         .id_table       = ide_ids,
502 };
503
504 static int __init init_ide_cs(void)
505 {
506         return pcmcia_register_driver(&ide_cs_driver);
507 }
508
509 static void __exit exit_ide_cs(void)
510 {
511         pcmcia_unregister_driver(&ide_cs_driver);
512         BUG_ON(dev_list != NULL);
513 }
514
515 module_init(init_ide_cs);
516 module_exit(exit_ide_cs);