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