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