firewire: Don't use subsystem rwsem, it's going away.
[linux-2.6] / drivers / telephony / ixj_pcmcia.c
1 #include "ixj-ver.h"
2
3 #include <linux/module.h>
4
5 #include <linux/init.h>
6 #include <linux/kernel.h>       /* printk() */
7 #include <linux/fs.h>           /* everything... */
8 #include <linux/errno.h>        /* error codes */
9 #include <linux/slab.h>
10
11 #include <pcmcia/cs_types.h>
12 #include <pcmcia/cs.h>
13 #include <pcmcia/cistpl.h>
14 #include <pcmcia/ds.h>
15
16 #include "ixj.h"
17
18 /*
19  *      PCMCIA service support for Quicknet cards
20  */
21  
22 #ifdef PCMCIA_DEBUG
23 static int pc_debug = PCMCIA_DEBUG;
24 module_param(pc_debug, int, 0644);
25 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
26 #else
27 #define DEBUG(n, args...)
28 #endif
29
30 typedef struct ixj_info_t {
31         int ndev;
32         dev_node_t node;
33         struct ixj *port;
34 } ixj_info_t;
35
36 static void ixj_detach(struct pcmcia_device *p_dev);
37 static int ixj_config(struct pcmcia_device * link);
38 static void ixj_cs_release(struct pcmcia_device * link);
39
40 static int ixj_probe(struct pcmcia_device *p_dev)
41 {
42         DEBUG(0, "ixj_attach()\n");
43         /* Create new ixj device */
44         p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
45         p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
46         p_dev->io.IOAddrLines = 3;
47         p_dev->conf.IntType = INT_MEMORY_AND_IO;
48         p_dev->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
49         if (!p_dev->priv) {
50                 return -ENOMEM;
51         }
52         memset(p_dev->priv, 0, sizeof(struct ixj_info_t));
53
54         return ixj_config(p_dev);
55 }
56
57 static void ixj_detach(struct pcmcia_device *link)
58 {
59         DEBUG(0, "ixj_detach(0x%p)\n", link);
60
61         ixj_cs_release(link);
62
63         kfree(link->priv);
64 }
65
66 #define CS_CHECK(fn, ret) \
67 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
68
69 static void ixj_get_serial(struct pcmcia_device * link, IXJ * j)
70 {
71         char *str;
72         int i, place;
73         DEBUG(0, "ixj_get_serial(0x%p)\n", link);
74
75         str = link->prod_id[0];
76         if (!str)
77                 goto cs_failed;
78         printk("%s", str);
79         str = link->prod_id[1];
80         if (!str)
81                 goto cs_failed;
82         printk(" %s", str);
83         str = link->prod_id[2];
84         if (!str)
85                 goto cs_failed;
86         place = 1;
87         for (i = strlen(str) - 1; i >= 0; i--) {
88                 switch (str[i]) {
89                 case '0':
90                 case '1':
91                 case '2':
92                 case '3':
93                 case '4':
94                 case '5':
95                 case '6':
96                 case '7':
97                 case '8':
98                 case '9':
99                         j->serial += (str[i] - 48) * place;
100                         break;
101                 case 'A':
102                 case 'B':
103                 case 'C':
104                 case 'D':
105                 case 'E':
106                 case 'F':
107                         j->serial += (str[i] - 55) * place;
108                         break;
109                 case 'a':
110                 case 'b':
111                 case 'c':
112                 case 'd':
113                 case 'e':
114                 case 'f':
115                         j->serial += (str[i] - 87) * place;
116                         break;
117                 }
118                 place = place * 0x10;
119         }
120         str = link->prod_id[3];
121         if (!str)
122                 goto cs_failed;
123         printk(" version %s\n", str);
124       cs_failed:
125         return;
126 }
127
128 static int ixj_config(struct pcmcia_device * link)
129 {
130         IXJ *j;
131         ixj_info_t *info;
132         tuple_t tuple;
133         u_short buf[128];
134         cisparse_t parse;
135         cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
136         cistpl_cftable_entry_t dflt =
137         {
138                 0
139         };
140         int last_ret, last_fn;
141         info = link->priv;
142         DEBUG(0, "ixj_config(0x%p)\n", link);
143         tuple.TupleData = (cisdata_t *) buf;
144         tuple.TupleOffset = 0;
145         tuple.TupleDataMax = 255;
146         tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
147         tuple.Attributes = 0;
148         CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
149         while (1) {
150                 if (pcmcia_get_tuple_data(link, &tuple) != 0 ||
151                                 pcmcia_parse_tuple(link, &tuple, &parse) != 0)
152                         goto next_entry;
153                 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
154                         cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
155                         link->conf.ConfigIndex = cfg->index;
156                         link->io.BasePort1 = io->win[0].base;
157                         link->io.NumPorts1 = io->win[0].len;
158                         if (io->nwin == 2) {
159                                 link->io.BasePort2 = io->win[1].base;
160                                 link->io.NumPorts2 = io->win[1].len;
161                         }
162                         if (pcmcia_request_io(link, &link->io) != 0)
163                                 goto next_entry;
164                         /* If we've got this far, we're done */
165                         break;
166                 }
167               next_entry:
168                 if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
169                         dflt = *cfg;
170                 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(link, &tuple));
171         }
172
173         CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
174
175         /*
176          *      Register the card with the core.
177          */     
178         j=ixj_pcmcia_probe(link->io.BasePort1,link->io.BasePort1 + 0x10);
179
180         info->ndev = 1;
181         info->node.major = PHONE_MAJOR;
182         link->dev_node = &info->node;
183         ixj_get_serial(link, j);
184         return 0;
185       cs_failed:
186         cs_error(link, last_fn, last_ret);
187         ixj_cs_release(link);
188         return -ENODEV;
189 }
190
191 static void ixj_cs_release(struct pcmcia_device *link)
192 {
193         ixj_info_t *info = link->priv;
194         DEBUG(0, "ixj_cs_release(0x%p)\n", link);
195         info->ndev = 0;
196         pcmcia_disable_device(link);
197 }
198
199 static struct pcmcia_device_id ixj_ids[] = {
200         PCMCIA_DEVICE_MANF_CARD(0x0257, 0x0600),
201         PCMCIA_DEVICE_NULL
202 };
203 MODULE_DEVICE_TABLE(pcmcia, ixj_ids);
204
205 static struct pcmcia_driver ixj_driver = {
206         .owner          = THIS_MODULE,
207         .drv            = {
208                 .name   = "ixj_cs",
209         },
210         .probe          = ixj_probe,
211         .remove         = ixj_detach,
212         .id_table       = ixj_ids,
213 };
214
215 static int __init ixj_pcmcia_init(void)
216 {
217         return pcmcia_register_driver(&ixj_driver);
218 }
219
220 static void ixj_pcmcia_exit(void)
221 {
222         pcmcia_unregister_driver(&ixj_driver);
223 }
224
225 module_init(ixj_pcmcia_init);
226 module_exit(ixj_pcmcia_exit);
227
228 MODULE_LICENSE("GPL");