blob: 161a1938552ee6ba836c6a7a4ba6dcd9b459cd15 [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
Lucas De Marchi25985ed2011-03-30 22:57:33 -030012 Extensions to new hisax_pcmcia by Karsten Keil
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
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/cistpl.h>
31#include <pcmcia/cisreg.h>
32#include <pcmcia/ds.h>
33#include "hisax_cfg.h"
34
35MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards");
36MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de");
37MODULE_LICENSE("GPL");
38
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40/*====================================================================*/
41
42/* Parameters that can be set with 'insmod' */
43
44static int protocol = 2; /* EURO-ISDN Default */
45module_param(protocol, int, 0);
46
Henne158e33d2010-03-25 12:05:30 +000047static int teles_cs_config(struct pcmcia_device *link) __devinit ;
Dominik Brodowskifba395e2006-03-31 17:21:06 +020048static void teles_cs_release(struct pcmcia_device *link);
Henne158e33d2010-03-25 12:05:30 +000049static void teles_detach(struct pcmcia_device *p_dev) __devexit ;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
Linus Torvalds1da177e2005-04-16 15:20:36 -070051typedef struct local_info_t {
Dominik Brodowskifd238232006-03-05 10:45:09 +010052 struct pcmcia_device *p_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 int busy;
54 int cardnr;
55} local_info_t;
56
Henne158e33d2010-03-25 12:05:30 +000057static int __devinit teles_probe(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -070058{
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 local_info_t *local;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Dominik Brodowskie773cfe2009-10-24 15:50:13 +020061 dev_dbg(&link->dev, "teles_attach()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63 /* Allocate space for private device-specific data */
Burman Yan41f96932006-12-08 02:39:35 -080064 local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
Dominik Brodowskif8cfa612005-11-14 21:25:51 +010065 if (!local) return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 local->cardnr = -1;
Dominik Brodowskifd238232006-03-05 10:45:09 +010067
Dominik Brodowskifba395e2006-03-31 17:21:06 +020068 local->p_dev = link;
Dominik Brodowskifd238232006-03-05 10:45:09 +010069 link->priv = local;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Dominik Brodowski00990e72010-07-30 13:13:46 +020071 link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072
Dominik Brodowski15b99ac2006-03-31 17:26:06 +020073 return teles_cs_config(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074} /* teles_attach */
75
Henne158e33d2010-03-25 12:05:30 +000076static void __devexit teles_detach(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -070077{
Dominik Brodowskie2d40962006-03-02 00:09:29 +010078 local_info_t *info = link->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Dominik Brodowskie773cfe2009-10-24 15:50:13 +020080 dev_dbg(&link->dev, "teles_detach(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Dominik Brodowskie2d40962006-03-02 00:09:29 +010082 info->busy = 1;
83 teles_cs_release(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Dominik Brodowskie2d40962006-03-02 00:09:29 +010085 kfree(info);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086} /* teles_detach */
87
Dominik Brodowski00990e72010-07-30 13:13:46 +020088static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +020090 int j;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Dominik Brodowski90abdc32010-07-24 17:23:51 +020092 p_dev->io_lines = 5;
Dominik Brodowski00990e72010-07-30 13:13:46 +020093 p_dev->resource[0]->end = 96;
94 p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
95 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
Dominik Brodowski90abdc32010-07-24 17:23:51 +020096
Dominik Brodowski00990e72010-07-30 13:13:46 +020097 if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +020098 printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
Dominik Brodowski90abdc32010-07-24 17:23:51 +020099 if (!pcmcia_request_io(p_dev))
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200100 return 0;
101 } else {
102 printk(KERN_INFO "(teles_cs: looks like the 97 model)\n");
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200103 for (j = 0x2f0; j > 0x100; j -= 0x10) {
Dominik Brodowski90abdc32010-07-24 17:23:51 +0200104 p_dev->resource[0]->start = j;
105 if (!pcmcia_request_io(p_dev))
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200106 return 0;
107 }
108 }
109 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110}
111
Henne158e33d2010-03-25 12:05:30 +0000112static int __devinit teles_cs_config(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113{
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200114 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 IsdnCard_t icard;
116
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200117 dev_dbg(&link->dev, "teles_config(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200119 i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200120 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
Dominik Brodowskieb141202010-03-07 12:21:16 +0100123 if (!link->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200126 i = pcmcia_enable_device(link);
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200127 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Dominik Brodowskieb141202010-03-07 12:21:16 +0100130 icard.para[0] = link->irq;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200131 icard.para[1] = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 icard.protocol = protocol;
133 icard.typ = ISDN_CTYPE_TELESPCMCIA;
134
135 i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
136 if (i < 0) {
137 printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200138 i, (unsigned int) link->resource[0]->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 teles_cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200140 return -ENODEV;
141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200143 ((local_info_t*)link->priv)->cardnr = i;
144 return 0;
145
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146cs_failed:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 teles_cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200148 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149} /* teles_cs_config */
150
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200151static void teles_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
153 local_info_t *local = link->priv;
154
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200155 dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 if (local) {
158 if (local->cardnr >= 0) {
159 /* no unregister function with hisax */
160 HiSax_closecard(local->cardnr);
161 }
162 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200164 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165} /* teles_cs_release */
166
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200167static int teles_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100168{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100169 local_info_t *dev = link->priv;
170
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100171 dev->busy = 1;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100172
173 return 0;
174}
175
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200176static int teles_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100177{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100178 local_info_t *dev = link->priv;
179
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100180 dev->busy = 0;
181
182 return 0;
183}
184
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
Joe Perches25f8f542011-05-03 19:29:01 -0700186static const struct pcmcia_device_id teles_ids[] = {
Dominik Brodowski0a10d732005-06-27 16:28:24 -0700187 PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
188 PCMCIA_DEVICE_NULL,
189};
190MODULE_DEVICE_TABLE(pcmcia, teles_ids);
191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192static struct pcmcia_driver teles_cs_driver = {
193 .owner = THIS_MODULE,
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200194 .name = "teles_cs",
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200195 .probe = teles_probe,
Henne158e33d2010-03-25 12:05:30 +0000196 .remove = __devexit_p(teles_detach),
Dominik Brodowski0a10d732005-06-27 16:28:24 -0700197 .id_table = teles_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100198 .suspend = teles_suspend,
199 .resume = teles_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200};
201
202static int __init init_teles_cs(void)
203{
204 return pcmcia_register_driver(&teles_cs_driver);
205}
206
207static void __exit exit_teles_cs(void)
208{
209 pcmcia_unregister_driver(&teles_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210}
211
212module_init(init_teles_cs);
213module_exit(exit_teles_cs);