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 
cs_error(client_handle_t handle,int func,int ret)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 
ide_attach(void)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 
ide_detach(dev_link_t * link)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 
idecs_register(int arg1,int arg2,int irq)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 
ide_config(dev_link_t * link)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 
ide_release(void * arg)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 
ide_event(event_t event,int priority,event_callback_args_t * args)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 
init_ide_cs(void)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 
exit_ide_cs(void)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);
501