~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/ide/ide-cs.c

Version: ~ [ 2.2.5 ] ~ [ 2.4.1 ] ~ [ 2.4.9 ] ~ [ 2.6.17.10 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 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/malloc.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     info->ndev = 0;
391     link->dev = NULL;
392     
393     CardServices(ReleaseConfiguration, link->handle);
394     CardServices(ReleaseIO, link->handle, &link->io);
395     CardServices(ReleaseIRQ, link->handle, &link->irq);
396     
397     link->state &= ~DEV_CONFIG;
398 
399 } /* ide_release */
400 
401 /*======================================================================
402 
403     The card status event handler.  Mostly, this schedules other
404     stuff to run after an event is received.  A CARD_REMOVAL event
405     also sets some flags to discourage the ide drivers from
406     talking to the ports.
407     
408 ======================================================================*/
409 
410 int ide_event(event_t event, int priority,
411               event_callback_args_t *args)
412 {
413     dev_link_t *link = args->client_data;
414 
415     DEBUG(1, "ide_event(0x%06x)\n", event);
416     
417     switch (event) {
418     case CS_EVENT_CARD_REMOVAL:
419         link->state &= ~DEV_PRESENT;
420         if (link->state & DEV_CONFIG)
421             mod_timer(&link->release, jiffies + HZ/20);
422         break;
423     case CS_EVENT_CARD_INSERTION:
424         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
425         ide_config(link);
426         break;
427     case CS_EVENT_PM_SUSPEND:
428         link->state |= DEV_SUSPEND;
429         /* Fall through... */
430     case CS_EVENT_RESET_PHYSICAL:
431         if (link->state & DEV_CONFIG)
432             CardServices(ReleaseConfiguration, link->handle);
433         break;
434     case CS_EVENT_PM_RESUME:
435         link->state &= ~DEV_SUSPEND;
436         /* Fall through... */
437     case CS_EVENT_CARD_RESET:
438         if (DEV_OK(link))
439             CardServices(RequestConfiguration, link->handle, &link->conf);
440         break;
441     }
442     return 0;
443 } /* ide_event */
444 
445 /*====================================================================*/
446 
447 static int __init init_ide_cs(void)
448 {
449     servinfo_t serv;
450     DEBUG(0, "%s\n", version);
451     CardServices(GetCardServicesInfo, &serv);
452     if (serv.Revision != CS_RELEASE_CODE) {
453         printk(KERN_NOTICE "ide_cs: Card Services release "
454                "does not match!\n");
455         return -1;
456     }
457     register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
458     return 0;
459 }
460 
461 static void __exit exit_ide_cs(void)
462 {
463     DEBUG(0, "ide_cs: unloading\n");
464     unregister_pccard_driver(&dev_info);
465     while (dev_list != NULL)
466         ide_detach(dev_list);
467 }
468 
469 module_init(init_ide_cs);
470 module_exit(exit_ide_cs);
471 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.