blob: 282a4467ef19571c803f296aee3b82b2e5883c20 [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/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{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 local_info_t *dev;
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200115 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 IsdnCard_t icard;
117
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200118 dev_dbg(&link->dev, "teles_config(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 dev = link->priv;
120
Dominik Brodowski5fcd4da2008-07-29 08:38:55 +0200121 i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200122 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Dominik Brodowskieb141202010-03-07 12:21:16 +0100125 if (!link->irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
Dominik Brodowski1ac71e52010-07-29 19:27:09 +0200128 i = pcmcia_enable_device(link);
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200129 if (i != 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 goto cs_failed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
Dominik Brodowskieb141202010-03-07 12:21:16 +0100132 icard.para[0] = link->irq;
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200133 icard.para[1] = link->resource[0]->start;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 icard.protocol = protocol;
135 icard.typ = ISDN_CTYPE_TELESPCMCIA;
136
137 i = hisax_init_pcmcia(link, &(((local_info_t*)link->priv)->busy), &icard);
138 if (i < 0) {
139 printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n",
Dominik Brodowski9a017a92010-07-24 15:58:54 +0200140 i, (unsigned int) link->resource[0]->start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 teles_cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200142 return -ENODEV;
143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200145 ((local_info_t*)link->priv)->cardnr = i;
146 return 0;
147
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148cs_failed:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 teles_cs_release(link);
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200150 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151} /* teles_cs_config */
152
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200153static void teles_cs_release(struct pcmcia_device *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
155 local_info_t *local = link->priv;
156
Dominik Brodowskie773cfe2009-10-24 15:50:13 +0200157 dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159 if (local) {
160 if (local->cardnr >= 0) {
161 /* no unregister function with hisax */
162 HiSax_closecard(local->cardnr);
163 }
164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200166 pcmcia_disable_device(link);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167} /* teles_cs_release */
168
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200169static int teles_suspend(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100170{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100171 local_info_t *dev = link->priv;
172
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100173 dev->busy = 1;
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100174
175 return 0;
176}
177
Dominik Brodowskifba395e2006-03-31 17:21:06 +0200178static int teles_resume(struct pcmcia_device *link)
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100179{
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100180 local_info_t *dev = link->priv;
181
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100182 dev->busy = 0;
183
184 return 0;
185}
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Dominik Brodowski0a10d732005-06-27 16:28:24 -0700188static struct pcmcia_device_id teles_ids[] = {
189 PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
190 PCMCIA_DEVICE_NULL,
191};
192MODULE_DEVICE_TABLE(pcmcia, teles_ids);
193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194static struct pcmcia_driver teles_cs_driver = {
195 .owner = THIS_MODULE,
Dominik Brodowski2e9b9812010-08-08 11:36:26 +0200196 .name = "teles_cs",
Dominik Brodowski15b99ac2006-03-31 17:26:06 +0200197 .probe = teles_probe,
Henne158e33d2010-03-25 12:05:30 +0000198 .remove = __devexit_p(teles_detach),
Dominik Brodowski0a10d732005-06-27 16:28:24 -0700199 .id_table = teles_ids,
Dominik Brodowski98e4c282005-11-14 21:21:18 +0100200 .suspend = teles_suspend,
201 .resume = teles_resume,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202};
203
204static int __init init_teles_cs(void)
205{
206 return pcmcia_register_driver(&teles_cs_driver);
207}
208
209static void __exit exit_teles_cs(void)
210{
211 pcmcia_unregister_driver(&teles_cs_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212}
213
214module_init(init_teles_cs);
215module_exit(exit_teles_cs);