blob: 5771955cc5326ef16897e4156a80abaef0b995dd [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */
2/*======================================================================
3
4 A teles S0 PCMCIA client driver
5
6 Based on skeleton by David Hinds, dhinds@allegro.stanford.edu
7 Written by Christof Petig, christof.petig@wtal.de
8
9 Also inspired by ELSA PCMCIA driver
10 by Klaus Lichtenwalder <Lichtenwalder@ACM.org>
11
12 Extentions to new hisax_pcmcia by Karsten Keil
13
14 minor changes to be compatible with kernel 2.4.x
15 by Jan.Schubert@GMX.li
16
17======================================================================*/
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/ptrace.h>
23#include <linux/slab.h>
24#include <linux/string.h>
25#include <linux/timer.h>
26#include <linux/ioport.h>
27#include <asm/io.h>
28#include <asm/system.h>
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <pcmcia/cs_types.h>
31#include <pcmcia/cs.h>
32#include <pcmcia/cistpl.h>
33#include <pcmcia/cisreg.h>
34#include <pcmcia/ds.h>
35#include "hisax_cfg.h"
36
37MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
38MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
39MODULE_LICENSE("GPL");
40
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42/*====================================================================*/
43
44/* Parameters that can be set with 'insmod' */
45
46static int protocol = 2; /* EURO-ISDN Default */
47module_param(protocol, int, 0);
48
49/*====================================================================*/
50
51/*
52 The event() function is this driver's Card Services event handler.
53 It will be called by Card Services when an appropriate card status
54 event is received. The config() and release() entry points are
55 used to configure or release a socket, in response to card insertion
56 and ejection events. They are invoked from the teles_cs event
57 handler.
58*/
59
Henne158e33d2010-03-25 12:05:30 +000060static int teles_cs_config(struct pcmcia_device *link) __devinit ;
Dominik Brodowskifba395e2006-03-31 17:21:06 +020061static void teles_cs_release(struct pcmcia_device *link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63/*
64 The attach() and detach() entry points are used to create and destroy
65 "instances" of the driver, where each instance represents everything
66 needed to manage one actual PCMCIA card.
67*/
68
Henne158e33d2010-03-25 12:05:30 +000069static void teles_detach(struct pcmcia_device *p_dev) __devexit ;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Linus Torvalds1da177e2005-04-16 15:20:36 -070071typedef struct local_info_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +010072 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 int busy;
74 int cardnr;
75} local_info_t;
76
77/*======================================================================
78
79 teles_attach() creates an "instance" of the driver, allocatingx
80 local data structures for one device. The device is registered
81 with Card Services.
82
83 The dev_link structure is initialized, but we don't actually
84 configure the card at this point -- we wait until we receive a
85 card insertion event.
86
87======================================================================*/
88
Henne158e33d2010-03-25 12:05:30 +000089static int __devinit teles_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -070090{
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 local_info_t *local;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Dominik Brodowskie773cfe2009-10-24 15:50:13 +020093 dev_dbg(&link->dev, "teles_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95 /* Allocate space for private device-specific data */
Burman Yan41f96932006-12-08 02:39:35 -080096 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +010097 if (!local) return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 local->cardnr = -1;
Dominik Brodowskifd238232006-03-05 10:45:09 +010099
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200100 local->p_dev = link;
Dominik Brodowskifd238232006-03-05 10:45:09 +0100101 link->priv = local;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 /*
104 General socket configuration defaults can go here. In this
105 client, we assume very little, and rely on the CIS for almost
106 everything. In most clients, many details (i.e., number, sizes,
107 and attributes of IO windows) are fixed by the nature of the
108 device, and can be hard-wired here.
109 */
110 link->io.NumPorts1 = 96;
111 link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
112 link->io.IOAddrLines = 5;
113
114 link->conf.Attributes = CONF_ENABLE_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 link->conf.IntType = INT_MEMORY_AND_IO;
116
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200117 return teles_cs_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118} /* teles_attach */
119
120/*======================================================================
121
122 This deletes a driver "instance". The device is de-registered
123 with Card Services. If it has been released, all local data
124 structures are freed. Otherwise, the structures will be freed
125 when the device is released.
126
127======================================================================*/
128
Henne158e33d2010-03-25 12:05:30 +0000129static void __devexit teles_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100131 local_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200133 dev_dbg(&link->dev, "teles_detach(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100135 info->busy = 1;
136 teles_cs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
Dominik Brodowskie2d40962006-03-02 00:09:29 +0100138 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139} /* teles_detach */
140
141/*======================================================================
142
143 teles_cs_config() is scheduled to run after a CARD_INSERTION event
144 is received, to configure the PCMCIA socket, and to make the
145 device available to the system.
146
147======================================================================*/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200149static int teles_cs_configcheck(struct pcmcia_device *p_dev,
150 cistpl_cftable_entry_t *cf,
Dominik Brodowski8e2fc392008-08-02 15:30:31 +0200151 cistpl_cftable_entry_t *dflt,
Dominik Brodowskiad913c12008-08-02 16:12:00 +0200152 unsigned int vcc,
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200153 void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200155 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200157 if ((cf->io.nwin > 0) && cf->io.win[0].base) {
158 printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200159 p_dev->io.BasePort1 = cf->io.win[0].base;
160 if (!pcmcia_request_io(p_dev, &p_dev->io))
161 return 0;
162 } else {
163 printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200164 for (j = 0x2f0; j > 0x100; j -= 0x10) {
165 p_dev->io.BasePort1 = j;
166 if (!pcmcia_request_io(p_dev, &p_dev->io))
167 return 0;
168 }
169 }
170 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171}
172
Henne158e33d2010-03-25 12:05:30 +0000173static int __devinit teles_cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 local_info_t *dev;
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200176 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 IsdnCard_t icard;
178
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200179 dev_dbg(&link->dev, "teles_config(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 dev = link->priv;
181
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200182 i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200183 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
Dominik Brodowskieb141202010-03-07 12:21:16 +0100186 if (!link->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200189 i = pcmcia_request_configuration(link, &link->conf);
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200190 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 /* Finally, report what we've done */
Dominik Brodowskided6a1a2010-03-20 19:35:12 +0100194 dev_info(&link->dev, "index 0x%02x:",
195 link->conf.ConfigIndex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 if (link->conf.Attributes & CONF_ENABLE_IRQ)
Dominik Brodowskieb141202010-03-07 12:21:16 +0100197 printk(", irq %d", link->irq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 if (link->io.NumPorts1)
199 printk(", io 0x%04x-0x%04x", link->io.BasePort1,
200 link->io.BasePort1+link->io.NumPorts1-1);
201 if (link->io.NumPorts2)
202 printk(" & 0x%04x-0x%04x", link->io.BasePort2,
203 link->io.BasePort2+link->io.NumPorts2-1);
204 printk("\n");
205
Dominik Brodowskieb141202010-03-07 12:21:16 +0100206 icard.para[0] = link->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 icard.para[1] = link->io.BasePort1;
208 icard.protocol = protocol;
209 icard.typ = ISDN_CTYPE_TELESPCMCIA;
210
211 i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
212 if (i < 0) {
213 printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
214 i, link->io.BasePort1);
215 teles_cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200216 return -ENODEV;
217 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200219 ((local_info_t*)link->priv)->cardnr = i;
220 return 0;
221
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222cs_failed:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 teles_cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200224 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225} /* teles_cs_config */
226
227/*======================================================================
228
229 After a card is removed, teles_cs_release() will unregister the net
230 device, and release the PCMCIA configuration. If the device is
231 still open, this will be postponed until it is closed.
232
233======================================================================*/
234
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200235static void teles_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
237 local_info_t *local = link->priv;
238
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200239 dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
241 if (local) {
242 if (local->cardnr >= 0) {
243 /* no unregister function with hisax */
244 HiSax_closecard(local->cardnr);
245 }
246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200248 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249} /* teles_cs_release */
250
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200251static int teles_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100252{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100253 local_info_t *dev = link->priv;
254
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100255 dev->busy = 1;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100256
257 return 0;
258}
259
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200260static int teles_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100261{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100262 local_info_t *dev = link->priv;
263
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100264 dev->busy = 0;
265
266 return 0;
267}
268
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
Dominik Brodowski0a10d732005-06-27 16:28:24 -0700270static struct pcmcia_device_id teles_ids[] = {
271 PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
272 PCMCIA_DEVICE_NULL,
273};
274MODULE_DEVICE_TABLE(pcmcia, teles_ids);
275
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276static struct pcmcia_driver teles_cs_driver = {
277 .owner = THIS_MODULE,
278 .drv = {
279 .name = "teles_cs",
280 },
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200281 .probe = teles_probe,
Henne158e33d2010-03-25 12:05:30 +0000282 .remove = __devexit_p(teles_detach),
Dominik Brodowski0a10d732005-06-27 16:28:24 -0700283 .id_table = teles_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100284 .suspend = teles_suspend,
285 .resume = teles_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286};
287
288static int __init init_teles_cs(void)
289{
290 return pcmcia_register_driver(&teles_cs_driver);
291}
292
293static void __exit exit_teles_cs(void)
294{
295 pcmcia_unregister_driver(&teles_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297
298module_init(init_teles_cs);
299module_exit(exit_teles_cs);