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