Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-nvram
[linux-2.6] / drivers / staging / wlan-ng / prism2_cs.c
1 #define WLAN_HOSTIF WLAN_PCMCIA
2 #include "hfa384x.c"
3 #include "prism2mgmt.c"
4 #include "prism2mib.c"
5 #include "prism2sta.c"
6
7 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,21) )
8 #if (WLAN_CPU_FAMILY == WLAN_Ix86)
9 #ifndef CONFIG_ISA
10 #warning "You may need to enable ISA support in your kernel."
11 #endif
12 #endif
13 #endif
14
15 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) )
16 static u_int    irq_mask = 0xdeb8;              /* Interrupt mask */
17 static int      irq_list[4] = { -1 };           /* Interrupt list */
18 #endif
19 static u_int    prism2_ignorevcc=1;             /* Boolean, if set, we
20                                                  * ignore what the Vcc
21                                                  * is set to and what the CIS
22                                                  * says.
23                                                  */
24 module_param( prism2_ignorevcc, int, 0644);
25
26 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) )
27 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,9))
28 static int numlist = 4;
29 module_param_array(irq_list, int, numlist, 0444);
30 #else
31 module_param_array(irq_list, int, NULL, 0444);
32 #endif
33 module_param( irq_mask, int, 0644);
34 #endif
35
36 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
37 static int prism2_cs_suspend(struct pcmcia_device *pdev);
38 static int prism2_cs_resume(struct pcmcia_device *pdev);
39 static void prism2_cs_remove(struct pcmcia_device *pdev);
40 static int prism2_cs_probe(struct pcmcia_device *pdev);
41 #else
42 dev_link_t      *prism2sta_attach(void);
43 static void     prism2sta_detach(dev_link_t *link);
44 static void     prism2sta_config(dev_link_t *link);
45 static void     prism2sta_release(u_long arg);
46 static int      prism2sta_event (event_t event, int priority, event_callback_args_t *args);
47
48 static dev_link_t       *dev_list = NULL;       /* head of instance list */
49 #endif
50
51 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68))
52 /*----------------------------------------------------------------
53 * cs_error
54 *
55 * Utility function to print card services error messages.
56 *
57 * Arguments:
58 *       handle  client handle identifying this CS client
59 *       func    CS function number that generated the error
60 *       ret     CS function return code
61 *
62 * Returns:
63 *       nothing
64 * Side effects:
65 *
66 * Call context:
67 *       process thread
68 *       interrupt
69 ----------------------------------------------------------------*/
70 static void cs_error(client_handle_t handle, int func, int ret)
71 {
72 #if (defined(CS_RELEASE_CODE) && (CS_RELEASE_CODE < 0x2911))
73         CardServices(ReportError, dev_info, (void *)func, (void *)ret);
74 #else
75         error_info_t err = { func, ret };
76         pcmcia_report_error(handle, &err);
77 #endif
78 }
79 #else // kernel_version
80
81 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)
82 static struct pcmcia_device_id prism2_cs_ids[] = {
83         PCMCIA_DEVICE_PROD_ID12("INTERSIL",  "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18), // Intersil PRISM2 Reference Design 11Mb/s 802.11b WLAN Card
84         PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), // Compaq WL100/200 11Mb/s 802.11b WLAN Card
85         PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), // Compaq iPaq HNW-100 11Mb/s 802.11b WLAN Card
86         PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), // Samsung SWL2000-N 11Mb/s 802.11b WLAN Card
87         PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), // Z-Com XI300 11Mb/s 802.11b WLAN Card
88         PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High",  "Rate wireless Networking", 0x273fe3db, 0x32a1eaee), // ZoomAir 4100 11Mb/s 802.11b WLAN Card
89         PCMCIA_DEVICE_PROD_ID123("Instant Wireless ",  " Network PC CARD",  "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0), // Linksys WPC11 11Mbps 802.11b WLAN Card
90         PCMCIA_DEVICE_PROD_ID123("Addtron",  "AWP-100 Wireless PCMCIA",  "Version 01.02", 0xe6ec52ce, 0x8649af2, 0x4b74baa0), // Addtron AWP-100 11Mbps 802.11b WLAN Card
91         PCMCIA_DEVICE_PROD_ID123("D",  "Link DWL-650 11Mbps WLAN Card",  "Version 01.02", 0x71b18589, 0xb6f1b0ab, 0x4b74baa0), // D-Link DWL-650 11Mbps 802.11b WLAN Card
92         PCMCIA_DEVICE_PROD_ID123("SMC",  "SMC2632W",  "Version 01.02", 0xc4f8b18b, 0x474a1f2a, 0x4b74baa0), // SMC 2632W 11Mbps 802.11b WLAN Card
93         PCMCIA_DEVICE_PROD_ID1234("Intersil",  "PRISM 2_5 PCMCIA ADAPTER",  "ISL37300P",  "Eval-RevA", 0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e), // BroMax Freeport 11Mbps 802.11b WLAN Card (Prism 2.5)
94         PCMCIA_DEVICE_PROD_ID123("U.S. Robotics",  "IEEE 802.11b PC-CARD",  "Version 01.02", 0xc7b8df9d, 0x1700d087, 0x4b74baa0), // U.S. Robotics IEEE 802.11b PC-CARD
95         PCMCIA_DEVICE_PROD_ID12("Digital Data Communications",  "WPC-0100", 0xfdd73470, 0xe0b6f146), // Level-One WPC-0100
96         PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), // Bromax OEM 11Mbps 802.11b WLAN Card (Prism 2.5)
97         PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), // Bromax OEM 11Mbps 802.11b WLAN Card (Prism 3)
98         PCMCIA_DEVICE_PROD_ID12("corega K.K.",  "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), // corega K.K. Wireless LAN PCC-11
99         PCMCIA_DEVICE_PROD_ID12("corega K.K.",  "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), // corega K.K. Wireless LAN PCCA-11
100         PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), // CONTEC FLEXSCAN/FX-DDS110-PCC
101         PCMCIA_DEVICE_PROD_ID12("PLANEX",  "GeoWave/GW-NS110", 0x209f40ab, 0x46263178), // PLANEX GeoWave/GW-NS110
102         PCMCIA_DEVICE_PROD_ID123("OEM",  "PRISM2 IEEE 802.11 PC-Card",  "Version 01.02", 0xfea54c90, 0x48f2bdd6, 0x4b74baa0), // Ambicom WL1100 11Mbps 802.11b WLAN Card
103         PCMCIA_DEVICE_PROD_ID123("LeArtery",  "SYNCBYAIR 11Mbps Wireless LAN PC Card",  "Version 01.02", 0x7e3b326a, 0x49893e92, 0x4b74baa0), // LeArtery SYNCBYAIR 11Mbps 802.11b WLAN Card
104 PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), // Intermec MobileLAN 11Mbps 802.11b WLAN Card
105         PCMCIA_DEVICE_PROD_ID123("NETGEAR MA401 Wireless PC",  "Card",  "Version 01.00", 0xa37434e9, 0x9762e8f1, 0xa57adb8c), // NETGEAR MA401 11Mbps 802.11 WLAN Card
106         PCMCIA_DEVICE_PROD_ID1234("Intersil",  "PRISM Freedom PCMCIA Adapter",  "ISL37100P",  "Eval-RevA", 0x4b801a17, 0xf222ec2d, 0x630d52b2, 0xc23adc0e), // Intersil PRISM Freedom 11mbps 802.11 WLAN Card
107         PCMCIA_DEVICE_PROD_ID123("OTC",  "Wireless AirEZY 2411-PCC WLAN Card",  "Version 01.02", 0x4ac44287, 0x235a6bed, 0x4b74baa0), // OTC Wireless AirEZY 2411-PCC 11Mbps 802.11 WLAN Card
108         PCMCIA_DEVICE_PROD_ID1234("802.11",  "11Mbps Wireless LAN Card",  "v08C1",  ""   , 0xb67a610e, 0x655aa7b7, 0x264b451a, 0x0), // Dynalink L11HDT 11Mbps 802.11 WLAN Card
109         PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), // Dynalink L11HDT 11Mbps 802.11 WLAN Card
110         PCMCIA_DEVICE_PROD_ID12("PROXIM",  "RangeLAN-DS/LAN PC CARD", 0xc6536a5e, 0x3f35797d), // PROXIM RangeLAN-DS/LAN PC CARD
111         PCMCIA_DEVICE_PROD_ID1234("ACTIONTEC",  "PRISM Wireless LAN PC Card",  "0381",  "RevA", 0x393089da, 0xa71e69d5, 0x90471fa9, 0x57a66194), // ACTIONTEC PRISM Wireless LAN PC Card
112         PCMCIA_DEVICE_MANF_CARD(0x1668, 0x0101), // ACTIONTEC PRISM Wireless LAN PC Card
113         PCMCIA_DEVICE_PROD_ID12("3Com",  "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3), // 3Com AirConnect 3CRWE737A
114         PCMCIA_DEVICE_PROD_ID12("3Com",  "3CRWE777A AirConnect Wireless LAN PCI Card"  , 0x41240e5b, 0xafc7c33e), // 3Com AirConnect 3CRWE777A
115         PCMCIA_DEVICE_PROD_ID12("ASUS",  "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842), // ASUS WL-100 802.11b WLAN  PC Card
116         PCMCIA_DEVICE_PROD_ID12("ASUS",  "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e), // ASUS WL-110 802.11b WLAN CF Card
117         PCMCIA_DEVICE_PROD_ID12("BUFFALO",  "WLI-CF-S11G", 0x2decece3, 0x82067c18), // BUFFALO WLI-CF-S11G 802.11b WLAN Card
118         PCMCIA_DEVICE_PROD_ID1234("The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P", "RevA", 0xa5f472c2, 0x9c05598d, 0xc9049a39, 0x57a66194), // Linksys WCF11 11Mbps 802.11b WLAN Card (Prism 2.5)
119         PCMCIA_DEVICE_PROD_ID1234("Linksys",  "Wireless CompactFlash Card",  "",  "", 0x733cc81, 0xc52f395, 0x0, 0x0), // Linksys WCF12 11Mbps 802.11b WLAN Card (Prism 3)
120         PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), // Linksys WCF12 11Mbps 802.11b WLAN Card (Prism 3)
121         PCMCIA_DEVICE_PROD_ID1234("NETGEAR MA401RA Wireless PC",  "Card",  "ISL37300P",  "Eval-RevA", 0x306467f, 0x9762e8f1, 0xc9049a39, 0xc23adc0e), // NETGEAR MA401RA 11Mbps 802.11 WLAN Card
122         PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), // D-Link DCF-660W  11Mbps 802.11b WLAN Card
123         PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001), // Microsoft Wireless Notebook Adapter MN-520
124         PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), // AnyPoint(TM) Wireless II PC Card
125         PCMCIA_DEVICE_PROD_ID1234("D",  "Link DRC-650 11Mbps WLAN Card",  "Version 01.02",  "" , 0x71b18589, 0xf144e3ac, 0x4b74baa0, 0x0), // D-Link DRC-650 802.11b WLAN Card
126         PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), // Adaptec AWN-8030
127         PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7110), // D-Link DWL-650 rev P 802.11b WLAN card
128         // PCMCIA_DEVICE_PROD_ID1234("D-Link",  "DWL-650 Wireless PC Card RevP",  "ISL37101P-10",  "A3", 0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52), // D-Link DWL-650 rev P 802.11b WLAN card
129         PCMCIA_DEVICE_PROD_ID123("INTERSIL",   "I-GATE 11M PC Card / PC Card plus",  "Version 01.02", 0x74c5e40d, 0x8304ff77, 0x4b74baa0), // I-Gate 11M PC Card
130         PCMCIA_DEVICE_PROD_ID1234("BENQ",  "AWL100 PCMCIA ADAPTER",  "ISL37300P",  "Eval-RevA", 0x35dadc74, 0x1f7fedb, 0xc9049a39, 0xc23adc0e), // benQ AWL100 802.11b WLAN Card
131         PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), // benQ AWL100 802.11b WLAN Card
132         // PCMCIA_DEVICE_PROD_ID1("INTERSIL", 0x74c5e40d), // Intersil Prism 2 card
133         // PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), // Intersil Prism 2 card
134
135         PCMCIA_DEVICE_NULL
136 };
137
138 MODULE_DEVICE_TABLE(pcmcia, prism2_cs_ids);
139 #endif
140
141 static struct pcmcia_driver prism2_cs_driver = {
142         .drv = {
143                 .name = "prism2_cs",
144         },
145         .owner = THIS_MODULE,
146 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
147         .suspend = prism2_cs_suspend,
148         .resume = prism2_cs_resume,
149         .remove = prism2_cs_remove,
150         .probe = prism2_cs_probe,
151         .id_table = prism2_cs_ids,
152 #else
153         .attach = prism2sta_attach,
154         .detach = prism2sta_detach,
155 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12)
156         .id_table = prism2_cs_ids,
157         .event =  prism2sta_event,
158 #endif // > 2.6.12
159 #endif // <= 2.6.15
160 };
161 #endif /* kernel_version */
162
163 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
164 #define CS_CHECK(fn, ret) \
165 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
166
167 #define CFG_CHECK(fn, retf) \
168 do { int ret = (retf); \
169 if (ret != 0) { \
170         WLAN_LOG_DEBUG(1, "CardServices(" #fn ") returned %d\n", ret); \
171         cs_error(pdev, fn, ret); \
172         goto next_entry; \
173 } \
174 } while (0)
175
176 static void prism2_cs_remove(struct pcmcia_device *pdev)
177 {
178         struct wlandevice  *wlandev;
179
180 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
181         dev_link_t *link = dev_to_instance(pdev);
182 #endif
183
184         DBFENTER;
185
186 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
187         wlandev = pdev->priv;
188 #else
189         wlandev = link->priv;
190 #endif
191
192         if (wlandev) {
193                 p80211netdev_hwremoved(wlandev);
194                 unregister_wlandev(wlandev);
195                 wlan_unsetup(wlandev);
196                 if (wlandev->priv) {
197                         hfa384x_t *hw = wlandev->priv;
198                         wlandev->priv = NULL;
199                         if (hw) {
200                                 hfa384x_destroy(hw);
201                                 kfree(hw);
202                         }
203                 }
204                 kfree(wlandev);
205         }
206
207 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
208         pdev->priv = NULL;
209         pcmcia_disable_device(pdev);
210 #else
211         if (link->state & DEV_CONFIG) {
212                 if (link->win)
213                         pcmcia_release_window(link->win);
214                 pcmcia_release_configuration(link->handle);
215                 if (link->io.NumPorts1)
216                         pcmcia_release_io(link->handle, &link->io);
217                 if (link->irq.AssignedIRQ)
218                         pcmcia_release_irq(link->handle, &link->irq);
219
220                 link->state &= ~DEV_CONFIG;
221         }
222
223         link->priv = NULL;
224         kfree(link);
225 #endif
226
227         DBFEXIT;
228         return;
229 }
230
231 static int prism2_cs_suspend(struct pcmcia_device *pdev)
232 {
233         struct wlandevice  *wlandev;
234
235 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
236         dev_link_t *link = dev_to_instance(pdev);
237 #endif
238
239         DBFENTER;
240
241 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
242         wlandev = pdev->priv;
243         prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable);
244 #else
245         wlandev = link->priv;
246
247         link->state |= DEV_SUSPEND;
248         if (link->state & DEV_CONFIG) {
249                 prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable);
250                 pcmcia_release_configuration(link->handle);
251         }
252 #endif
253
254         DBFEXIT;
255
256         return 0;
257 }
258
259 static int prism2_cs_resume(struct pcmcia_device *pdev)
260 {
261         struct wlandevice  *wlandev;
262
263 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
264         dev_link_t *link = dev_to_instance(pdev);
265 #endif
266
267         DBFENTER;
268
269 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
270         wlandev = pdev->priv;
271         // XXX do something here?
272 #else
273         wlandev = link->priv;
274         link->state &= ~DEV_SUSPEND;
275         if (link->state & DEV_CONFIG) {
276                 pcmcia_request_configuration(link->handle, &link->conf);
277                 // XXX do something here?
278         }
279 #endif
280
281
282         DBFEXIT;
283
284         return 0;
285 }
286
287 static int prism2_cs_probe(struct pcmcia_device *pdev)
288 {
289         int rval = 0;
290         struct wlandevice *wlandev = NULL;
291         hfa384x_t *hw = NULL;
292
293         config_info_t socketconf;
294         cisparse_t *parse = NULL;
295         tuple_t tuple;
296         uint8_t buf[64];
297         int last_fn, last_ret;
298         cistpl_cftable_entry_t dflt = { 0 };
299
300 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
301         dev_link_t *link;
302 #endif
303
304         DBFENTER;
305
306 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
307         /* Set up interrupt type */
308         pdev->conf.IntType = INT_MEMORY_AND_IO;
309 #else
310         link = kmalloc(sizeof(dev_link_t), GFP_KERNEL);
311         if (link == NULL)
312                 return -ENOMEM;
313         memset(link, 0, sizeof(dev_link_t));
314
315         link->conf.Vcc = 33;
316         link->conf.IntType = INT_MEMORY_AND_IO;
317
318         link->handle = pdev;
319         pdev->instance = link;
320         link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
321
322 #endif
323
324         // VCC crap?
325         parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL);
326
327         wlandev = create_wlan();
328         if (!wlandev || !parse) {
329                 WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info);
330                 rval = -EIO;
331                 goto failed;
332         }
333         hw = wlandev->priv;
334
335         if ( wlan_setup(wlandev) != 0 ) {
336                 WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info);
337                 rval = -EIO;
338                 goto failed;
339         }
340
341         /* Initialize the hw struct for now */
342         hfa384x_create(hw, 0, 0, NULL);
343         hw->wlandev = wlandev;
344
345 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
346         hw->pdev = pdev;
347         pdev->priv = wlandev;
348 #else
349         hw->link = link;
350         link->priv = wlandev;
351 #endif
352
353         tuple.DesiredTuple = CISTPL_CONFIG;
354         tuple.Attributes = 0;
355         tuple.TupleData = buf;
356         tuple.TupleDataMax = sizeof(buf);
357         tuple.TupleOffset = 0;
358         CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
359         CS_CHECK(GetTupleData, pcmcia_get_tuple_data(pdev, &tuple));
360         CS_CHECK(ParseTuple, pcmcia_parse_tuple(pdev, &tuple, parse));
361 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
362         pdev->conf.ConfigBase = parse->config.base;
363         pdev->conf.Present = parse->config.rmask[0];
364 #else
365         link->conf.ConfigBase = parse->config.base;
366         link->conf.Present = parse->config.rmask[0];
367
368         link->conf.Vcc = socketconf.Vcc;
369 #endif
370         CS_CHECK(GetConfigurationInfo,
371                  pcmcia_get_configuration_info(pdev, &socketconf));
372
373         tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
374         CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
375         for (;;) {
376                 cistpl_cftable_entry_t *cfg = &(parse->cftable_entry);
377                 CFG_CHECK(GetTupleData,
378                            pcmcia_get_tuple_data(pdev, &tuple));
379                 CFG_CHECK(ParseTuple,
380                            pcmcia_parse_tuple(pdev, &tuple, parse));
381
382                 if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
383                         dflt = *cfg;
384                 if (cfg->index == 0)
385                         goto next_entry;
386 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
387                 pdev->conf.ConfigIndex = cfg->index;
388 #else
389                 link->conf.ConfigIndex = cfg->index;
390 #endif
391
392                 /* Does this card need audio output? */
393                 if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
394 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
395                         pdev->conf.Attributes |= CONF_ENABLE_SPKR;
396                         pdev->conf.Status = CCSR_AUDIO_ENA;
397 #else
398                         link->conf.Attributes |= CONF_ENABLE_SPKR;
399                         link->conf.Status = CCSR_AUDIO_ENA;
400 #endif
401                 }
402
403                 /* Use power settings for Vcc and Vpp if present */
404                 /*  Note that the CIS values need to be rescaled */
405                 if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
406                         if (socketconf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
407                             10000 && !prism2_ignorevcc) {
408                                 WLAN_LOG_DEBUG(1, "  Vcc mismatch - skipping"
409                                        " this entry\n");
410                                 goto next_entry;
411                         }
412                 } else if (dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
413                         if (socketconf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM] /
414                             10000 && !prism2_ignorevcc) {
415                                 WLAN_LOG_DEBUG(1, "  Vcc (default) mismatch "
416                                        "- skipping this entry\n");
417                                 goto next_entry;
418                         }
419                 }
420
421                 if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
422 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
423                         pdev->conf.Vpp =
424                                 cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
425 #else
426                         link->conf.Vpp1 = link->conf.Vpp2 =
427                                 cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
428 #endif
429                 } else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) {
430 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
431                         pdev->conf.Vpp =
432                                 dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
433 #else
434                         link->conf.Vpp1 = link->conf.Vpp2 =
435                                 dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
436 #endif
437                 }
438
439                 /* Do we need to allocate an interrupt? */
440                 /* HACK: due to a bad CIS....we ALWAYS need an interrupt */
441                 /* if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) */
442 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
443                 pdev->conf.Attributes |= CONF_ENABLE_IRQ;
444 #else
445                 link->conf.Attributes |= CONF_ENABLE_IRQ;
446 #endif
447
448                 /* IO window settings */
449 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
450                 pdev->io.NumPorts1 = pdev->io.NumPorts2 = 0;
451                 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
452                         cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
453                         pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
454                         if (!(io->flags & CISTPL_IO_8BIT))
455                                 pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
456                         if (!(io->flags & CISTPL_IO_16BIT))
457                                 pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
458                         pdev->io.BasePort1 = io->win[0].base;
459                         if  ( pdev->io.BasePort1 != 0 ) {
460                                 WLAN_LOG_WARNING(
461                                 "Brain damaged CIS: hard coded iobase="
462                                 "0x%x, try letting pcmcia_cs decide...\n",
463                                 pdev->io.BasePort1 );
464                                 pdev->io.BasePort1 = 0;
465                         }
466                         pdev->io.NumPorts1 = io->win[0].len;
467                         if (io->nwin > 1) {
468                                 pdev->io.Attributes2 = pdev->io.Attributes1;
469                                 pdev->io.BasePort2 = io->win[1].base;
470                                 pdev->io.NumPorts2 = io->win[1].len;
471                         }
472                 }
473                 /* This reserves IO space but doesn't actually enable it */
474                 CFG_CHECK(RequestIO, pcmcia_request_io(pdev, &pdev->io));
475 #else
476                 link->io.NumPorts1 = link->io.NumPorts2 = 0;
477                 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
478                         cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
479                         link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
480                         if (!(io->flags & CISTPL_IO_8BIT))
481                                 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
482                         if (!(io->flags & CISTPL_IO_16BIT))
483                                 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
484                         link->io.BasePort1 = io->win[0].base;
485                         if  ( link->io.BasePort1 != 0 ) {
486                                 WLAN_LOG_WARNING(
487                                 "Brain damaged CIS: hard coded iobase="
488                                 "0x%x, try letting pcmcia_cs decide...\n",
489                                 link->io.BasePort1 );
490                                 link->io.BasePort1 = 0;
491                         }
492                         link->io.NumPorts1 = io->win[0].len;
493                         if (io->nwin > 1) {
494                                 link->io.Attributes2 = link->io.Attributes1;
495                                 link->io.BasePort2 = io->win[1].base;
496                                 link->io.NumPorts2 = io->win[1].len;
497                         }
498                 }
499                 /* This reserves IO space but doesn't actually enable it */
500                 CFG_CHECK(RequestIO, pcmcia_request_io(pdev, &link->io));
501 #endif
502                 /* If we got this far, we're cool! */
503                 break;
504
505         next_entry:
506                 if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
507                         dflt = *cfg;
508                 CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple));
509
510         }
511
512         /* Let pcmcia know the device name */
513 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
514         pdev->dev_node = &hw->node;
515 #else
516         link->dev = &hw->node;
517 #endif
518
519         /* Register the network device and get assigned a name */
520         SET_MODULE_OWNER(wlandev->netdev);
521         SET_NETDEV_DEV(wlandev->netdev,  &handle_to_dev(pdev));
522         if (register_wlandev(wlandev) != 0) {
523                 WLAN_LOG_NOTICE("prism2sta_cs: register_wlandev() failed.\n");
524                 goto failed;
525         }
526
527         strcpy(hw->node.dev_name, wlandev->name);
528
529         /* Allocate an interrupt line.  Note that this does not assign a */
530         /* handler to the interrupt, unless the 'Handler' member of the */
531         /* irq structure is initialized. */
532 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
533         if (pdev->conf.Attributes & CONF_ENABLE_IRQ) {
534                 pdev->irq.IRQInfo1 = IRQ_LEVEL_ID;
535                 pdev->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
536                 pdev->irq.Handler = hfa384x_interrupt;
537                 pdev->irq.Instance = wlandev;
538                 CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
539         }
540 #else
541         if (link->conf.Attributes & CONF_ENABLE_IRQ) {
542                 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
543                 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
544                 link->irq.Handler = hfa384x_interrupt;
545                 link->irq.Instance = wlandev;
546                 CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &link->irq));
547         }
548 #endif
549
550         /* This actually configures the PCMCIA socket -- setting up */
551         /* the I/O windows and the interrupt mapping, and putting the */
552         /* card and host interface into "Memory and IO" mode. */
553 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
554         CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
555 #else
556         CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &link->conf));
557 #endif
558
559         /* Fill the netdevice with this info */
560 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
561         wlandev->netdev->irq = pdev->irq.AssignedIRQ;
562         wlandev->netdev->base_addr = pdev->io.BasePort1;
563 #else
564         wlandev->netdev->irq = link->irq.AssignedIRQ;
565         wlandev->netdev->base_addr = link->io.BasePort1;
566 #endif
567
568         /* And the rest of the hw structure */
569         hw->irq = wlandev->netdev->irq;
570         hw->iobase = wlandev->netdev->base_addr;
571
572 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
573         link->state |= DEV_CONFIG;
574         link->state &= ~DEV_CONFIG_PENDING;
575 #endif
576
577         /* And now we're done! */
578         wlandev->msdstate = WLAN_MSD_HWPRESENT;
579
580         goto done;
581
582  cs_failed:
583         cs_error(pdev, last_fn, last_ret);
584
585 failed:
586         // wlandev, hw, etc etc..
587 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
588         pdev->priv = NULL;
589 #else
590         pdev->instance = NULL;
591         if (link) {
592                 link->priv = NULL;
593                 kfree(link);
594         }
595 #endif
596         if (wlandev) {
597                 wlan_unsetup(wlandev);
598                 if (wlandev->priv) {
599                         hw = wlandev->priv;
600                         wlandev->priv = NULL;
601                         if (hw) {
602                                 hfa384x_destroy(hw);
603                                 kfree(hw);
604                         }
605                 }
606                 kfree(wlandev);
607         }
608
609 done:
610         if (parse) kfree(parse);
611
612         DBFEXIT;
613         return rval;
614 }
615 #else  // <= 2.6.15
616 #define CS_CHECK(fn, ret) \
617 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
618
619 #define CFG_CHECK(fn, retf) \
620 do { int ret = (retf); \
621 if (ret != 0) { \
622         WLAN_LOG_DEBUG(1, "CardServices(" #fn ") returned %d\n", ret); \
623         cs_error(link->handle, fn, ret); \
624         goto next_entry; \
625 } \
626 } while (0)
627
628 /*----------------------------------------------------------------
629 * prism2sta_attach
630 *
631 * Half of the attach/detach pair.  Creates and registers a device
632 * instance with Card Services.  In this case, it also creates the
633 * wlandev structure and device private structure.  These are
634 * linked to the device instance via its priv member.
635 *
636 * Arguments:
637 *       none
638 *
639 * Returns:
640 *       A valid ptr to dev_link_t on success, NULL otherwise
641 *
642 * Side effects:
643 *
644 *
645 * Call context:
646 *       process thread (insmod/init_module/register_pccard_driver)
647 ----------------------------------------------------------------*/
648 dev_link_t *prism2sta_attach(void)
649 {
650         client_reg_t            client_reg;
651         int                     result;
652         dev_link_t              *link = NULL;
653         wlandevice_t            *wlandev = NULL;
654         hfa384x_t               *hw = NULL;
655
656         DBFENTER;
657
658         /* Alloc our structures */
659         link =          kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
660
661         if (!link || ((wlandev = create_wlan()) == NULL)) {
662                 WLAN_LOG_ERROR("%s: Memory allocation failure.\n", dev_info);
663                 result = -EIO;
664                 goto failed;
665         }
666         hw = wlandev->priv;
667
668         /* Clear all the structs */
669         memset(link, 0, sizeof(struct dev_link_t));
670
671         if ( wlan_setup(wlandev) != 0 ) {
672                 WLAN_LOG_ERROR("%s: wlan_setup() failed.\n", dev_info);
673                 result = -EIO;
674                 goto failed;
675         }
676
677         /* Initialize the hw struct for now */
678         hfa384x_create(hw, 0, 0, NULL);
679         hw->wlandev = wlandev;
680
681         /* Initialize the PC card device object. */
682 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
683         init_timer(&link->release);
684         link->release.function = &prism2sta_release;
685         link->release.data = (u_long)link;
686 #endif
687         link->conf.IntType = INT_MEMORY_AND_IO;
688         link->priv = wlandev;
689 #if (defined(CS_RELEASE_CODE) && (CS_RELEASE_CODE < 0x2911))
690         link->irq.Instance = wlandev;
691 #endif
692
693         /* Link in to the list of devices managed by this driver */
694         link->next = dev_list;
695         dev_list = link;
696
697         /* Register with Card Services */
698         client_reg.dev_info = &dev_info;
699 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) )
700         client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
701 #endif
702
703 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) )
704         client_reg.EventMask =
705                 CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
706                 CS_EVENT_RESET_REQUEST |
707                 CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
708                 CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
709         client_reg.event_handler = &prism2sta_event;
710 #endif
711
712         client_reg.Version = 0x0210;
713         client_reg.event_callback_args.client_data = link;
714
715         result = pcmcia_register_client(&link->handle, &client_reg);
716         if (result != 0) {
717                 cs_error(link->handle, RegisterClient, result);
718                 prism2sta_detach(link);
719                 return NULL;
720         }
721
722         goto done;
723
724  failed:
725         if (link)       kfree(link);
726         if (wlandev)    kfree(wlandev);
727         if (hw)         kfree(hw);
728         link = NULL;
729
730  done:
731         DBFEXIT;
732         return link;
733 }
734
735
736 /*----------------------------------------------------------------
737 * prism2sta_detach
738 *
739 * Remove one of the device instances managed by this driver.
740 *   Search the list for the given instance,
741 *   check our flags for a waiting timer'd release call
742 *   call release
743 *   Deregister the instance with Card Services
744 *   (netdevice) unregister the network device.
745 *   unlink the instance from the list
746 *   free the link, priv, and priv->priv memory
747 * Note: the dev_list variable is a driver scoped static used to
748 *       maintain a list of device instances managed by this
749 *       driver.
750 *
751 * Arguments:
752 *       link    ptr to the instance to detach
753 *
754 * Returns:
755 *       nothing
756 *
757 * Side effects:
758 *       the link structure is gone, the netdevice is gone
759 *
760 * Call context:
761 *       Might be interrupt, don't block.
762 ----------------------------------------------------------------*/
763 void prism2sta_detach(dev_link_t *link)
764 {
765         dev_link_t              **linkp;
766         wlandevice_t            *wlandev;
767         hfa384x_t               *hw;
768
769         DBFENTER;
770
771         /* Locate prev device structure */
772         for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) {
773                 if (*linkp == link) break;
774         }
775
776         if (*linkp != NULL) {
777 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
778                 unsigned long   flags;
779                 /* Get rid of any timer'd release call */
780                 save_flags(flags);
781                 cli();
782 #endif
783
784 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
785                 if (link->state & DEV_RELEASE_PENDING) {
786                         del_timer_sync(&link->release);
787                         link->state &= ~DEV_RELEASE_PENDING;
788                 }
789 #endif
790
791 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
792                 restore_flags(flags);
793 #endif
794
795                 /* If link says we're still config'd, call release */
796                 if (link->state & DEV_CONFIG) {
797                         prism2sta_release((u_long)link);
798                         if (link->state & DEV_STALE_CONFIG) {
799                                 link->state |= DEV_STALE_LINK;
800                                 return;
801                         }
802                 }
803
804                 /* Tell Card Services we're not around any more */
805                 if (link->handle) {
806                         pcmcia_deregister_client(link->handle);
807                 }
808
809                 /* Unlink device structure, free bits */
810                 *linkp = link->next;
811                 if ( link->priv != NULL ) {
812                         wlandev = (wlandevice_t*)link->priv;
813                         p80211netdev_hwremoved(wlandev);
814                         if (link->dev != NULL) {
815                                 unregister_wlandev(wlandev);
816                         }
817                         wlan_unsetup(wlandev);
818                         if (wlandev->priv) {
819                                 hw = wlandev->priv;
820                                 wlandev->priv = NULL;
821                                 if (hw) {
822                                         hfa384x_destroy(hw);
823                                         kfree(hw);
824                                 }
825                         }
826                         link->priv = NULL;
827                         kfree(wlandev);
828                 }
829                 kfree(link);
830         }
831
832         DBFEXIT;
833         return;
834 }
835
836 /*----------------------------------------------------------------
837 * prism2sta_config
838 *
839 * Half of the config/release pair.  Usually called in response to
840 * a card insertion event.  At this point, we _know_ there's some
841 * physical device present.  That means we can start poking around
842 * at the CIS and at any device specific config data we want.
843 *
844 * Note the gotos and the macros.  I recoded this once without
845 * them, and it got incredibly ugly.  It's actually simpler with
846 * them.
847 *
848 * Arguments:
849 *       link    the dev_link_t structure created in attach that
850 *               represents this device instance.
851 *
852 * Returns:
853 *       nothing
854 *
855 * Side effects:
856 *       Resources (irq, io, mem) are allocated
857 *       The pcmcia dev_link->node->name is set
858 *       (For netcards) The device structure is finished and,
859 *         most importantly, registered.  This means that there
860 *         is now a _named_ device that can be configured from
861 *         userland.
862 *
863 * Call context:
864 *       May be called from a timer.  Don't block!
865 ----------------------------------------------------------------*/
866 #define CS_CHECK(fn, ret) \
867 do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
868
869 #define CFG_CHECK(fn, retf) \
870 do { int ret = (retf); \
871 if (ret != 0) { \
872         WLAN_LOG_DEBUG(1, "CardServices(" #fn ") returned %d\n", ret); \
873         cs_error(link->handle, fn, ret); \
874         goto next_entry; \
875 } \
876 } while (0)
877
878 void prism2sta_config(dev_link_t *link)
879 {
880         client_handle_t         handle;
881         wlandevice_t            *wlandev;
882         hfa384x_t               *hw;
883         int                     last_fn;
884         int                     last_ret;
885         tuple_t                 tuple;
886         cisparse_t              parse;
887         config_info_t           socketconf;
888         UINT8                   buf[64];
889         int                     minVcc = 0;
890         int                     maxVcc = 0;
891         cistpl_cftable_entry_t  dflt = { 0 };
892
893         DBFENTER;
894
895         handle = link->handle;
896         wlandev = (wlandevice_t*)link->priv;
897         hw = wlandev->priv;
898
899         /* Collect the config register info */
900         tuple.DesiredTuple = CISTPL_CONFIG;
901         tuple.Attributes = 0;
902         tuple.TupleData = buf;
903         tuple.TupleDataMax = sizeof(buf);
904         tuple.TupleOffset = 0;
905         CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
906         CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
907         CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
908
909         link->conf.ConfigBase = parse.config.base;
910         link->conf.Present = parse.config.rmask[0];
911
912         /* Configure card */
913         link->state |= DEV_CONFIG;
914
915         /* Acquire the current socket config (need Vcc setting) */
916         CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &socketconf));
917
918         /* Loop through the config table entries until we find one that works */
919         /* Assumes a complete and valid CIS */
920         tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
921         CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
922         while (1) {
923                 cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
924                 CFG_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
925                 CFG_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
926
927                 if (cfg->index == 0) goto next_entry;
928                 link->conf.ConfigIndex = cfg->index;
929
930                 /* Lets print out the Vcc that the controller+pcmcia-cs set
931                  * for us, cause that's what we're going to use.
932                  */
933                 WLAN_LOG_DEBUG(1,"Initial Vcc=%d/10v\n", socketconf.Vcc);
934                 if (prism2_ignorevcc) {
935                         link->conf.Vcc = socketconf.Vcc;
936                         goto skipvcc;
937                 }
938
939                 /* Use power settings for Vcc and Vpp if present */
940                 /* Note that the CIS values need to be rescaled */
941                 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
942                         WLAN_LOG_DEBUG(1, "Vcc obtained from curtupl.VNOM\n");
943                         minVcc = maxVcc =
944                                 cfg->vcc.param[CISTPL_POWER_VNOM]/10000;
945                 } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
946                         WLAN_LOG_DEBUG(1, "Vcc set from dflt.VNOM\n");
947                         minVcc = maxVcc =
948                                 dflt.vcc.param[CISTPL_POWER_VNOM]/10000;
949                 } else if ((cfg->vcc.present & (1<<CISTPL_POWER_VMAX)) &&
950                            (cfg->vcc.present & (1<<CISTPL_POWER_VMIN)) ) {
951                         WLAN_LOG_DEBUG(1, "Vcc set from curtupl(VMIN,VMAX)\n");                 minVcc = cfg->vcc.param[CISTPL_POWER_VMIN]/10000;
952                         maxVcc = cfg->vcc.param[CISTPL_POWER_VMAX]/10000;
953                 } else if ((dflt.vcc.present & (1<<CISTPL_POWER_VMAX)) &&
954                            (dflt.vcc.present & (1<<CISTPL_POWER_VMIN)) ) {
955                         WLAN_LOG_DEBUG(1, "Vcc set from dflt(VMIN,VMAX)\n");
956                         minVcc = dflt.vcc.param[CISTPL_POWER_VMIN]/10000;
957                         maxVcc = dflt.vcc.param[CISTPL_POWER_VMAX]/10000;
958                 }
959
960                 if ( socketconf.Vcc >= minVcc && socketconf.Vcc <= maxVcc) {
961                         link->conf.Vcc = socketconf.Vcc;
962                 } else {
963                         /* [MSM]: Note that I've given up trying to change
964                          * the Vcc if a change is indicated.  It seems the
965                          * system&socketcontroller&card vendors can't seem
966                          * to get it right, so I'm tired of trying to hack
967                          * my way around it.  pcmcia-cs does its best using
968                          * the voltage sense pins but sometimes the controller
969                          * lies.  Then, even if we have a good read on the VS
970                          * pins, some system designs will silently ignore our
971                          * requests to set the voltage.  Additionally, some
972                          * vendors have 3.3v indicated on their sense pins,
973                          * but 5v specified in the CIS or vice-versa.  I've
974                          * had it.  My only recommendation is "let the buyer
975                          * beware".  Your system might supply 5v to a 3v card
976                          * (possibly causing damage) or a 3v capable system
977                          * might supply 5v to a 3v capable card (wasting
978                          * precious battery life).
979                          * My only recommendation (if you care) is to get
980                          * yourself an extender card (I don't know where, I
981                          * have only one myself) and a meter and test it for
982                          * yourself.
983                          */
984                         goto next_entry;
985                 }
986 skipvcc:
987                 WLAN_LOG_DEBUG(1, "link->conf.Vcc=%d\n", link->conf.Vcc);
988
989                 /* Do we need to allocate an interrupt? */
990                 /* HACK: due to a bad CIS....we ALWAYS need an interrupt */
991                 /* if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) */
992                         link->conf.Attributes |= CONF_ENABLE_IRQ;
993
994                 /* IO window settings */
995                 link->io.NumPorts1 = link->io.NumPorts2 = 0;
996                 if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
997                         cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
998                         link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
999                         if (!(io->flags & CISTPL_IO_8BIT))
1000                                 link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
1001                         if (!(io->flags & CISTPL_IO_16BIT))
1002                                 link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
1003                         link->io.BasePort1 = io->win[0].base;
1004                         if  ( link->io.BasePort1 != 0 ) {
1005                                 WLAN_LOG_WARNING(
1006                                 "Brain damaged CIS: hard coded iobase="
1007                                 "0x%x, try letting pcmcia_cs decide...\n",
1008                                 link->io.BasePort1 );
1009                                 link->io.BasePort1 = 0;
1010                         }
1011                         link->io.NumPorts1 = io->win[0].len;
1012                         if (io->nwin > 1) {
1013                                 link->io.Attributes2 = link->io.Attributes1;
1014                                 link->io.BasePort2 = io->win[1].base;
1015                                 link->io.NumPorts2 = io->win[1].len;
1016                         }
1017                 }
1018
1019                 /* This reserves IO space but doesn't actually enable it */
1020                 CFG_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io));
1021
1022                 /* If we got this far, we're cool! */
1023                 break;
1024
1025 next_entry:
1026                 if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
1027                         dflt = *cfg;
1028                 CS_CHECK(GetNextTuple,
1029                          pcmcia_get_next_tuple(handle, &tuple));
1030         }
1031
1032         /* Allocate an interrupt line.  Note that this does not assign a */
1033         /* handler to the interrupt, unless the 'Handler' member of the */
1034         /* irq structure is initialized. */
1035         if (link->conf.Attributes & CONF_ENABLE_IRQ)
1036         {
1037 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11) )
1038                 int                     i;
1039                 link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
1040                 if (irq_list[0] == -1)
1041                         link->irq.IRQInfo2 = irq_mask;
1042                 else
1043                         for (i=0; i<4; i++)
1044                                 link->irq.IRQInfo2 |= 1 << irq_list[i];
1045 #else
1046                 link->irq.IRQInfo1 = IRQ_LEVEL_ID;
1047 #endif
1048                 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
1049                 link->irq.Handler = hfa384x_interrupt;
1050                 link->irq.Instance = wlandev;
1051                 CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
1052         }
1053
1054         /* This actually configures the PCMCIA socket -- setting up */
1055         /* the I/O windows and the interrupt mapping, and putting the */
1056         /* card and host interface into "Memory and IO" mode. */
1057         CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf));
1058
1059         /* Fill the netdevice with this info */
1060         wlandev->netdev->irq = link->irq.AssignedIRQ;
1061         wlandev->netdev->base_addr = link->io.BasePort1;
1062
1063         /* Report what we've done */
1064         WLAN_LOG_INFO("%s: index 0x%02x: Vcc %d.%d",
1065                 dev_info, link->conf.ConfigIndex,
1066                 link->conf.Vcc/10, link->conf.Vcc%10);
1067         if (link->conf.Vpp1)
1068                 printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
1069         if (link->conf.Attributes & CONF_ENABLE_IRQ)
1070                 printk(", irq %d", link->irq.AssignedIRQ);
1071         if (link->io.NumPorts1)
1072                 printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1);
1073         if (link->io.NumPorts2)
1074                 printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1);
1075         printk("\n");
1076
1077         link->state &= ~DEV_CONFIG_PENDING;
1078
1079         /* Let pcmcia know the device name */
1080         link->dev = &hw->node;
1081
1082         /* Register the network device and get assigned a name */
1083         SET_MODULE_OWNER(wlandev->netdev);
1084 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,11) )
1085         SET_NETDEV_DEV(wlandev->netdev,  &handle_to_dev(link->handle));
1086 #endif
1087         if (register_wlandev(wlandev) != 0) {
1088                 WLAN_LOG_NOTICE("prism2sta_cs: register_wlandev() failed.\n");
1089                 goto failed;
1090         }
1091
1092         strcpy(hw->node.dev_name, wlandev->name);
1093
1094         /* Any device custom config/query stuff should be done here */
1095         /* For a netdevice, we should at least grab the mac address */
1096
1097         return;
1098 cs_failed:
1099         cs_error(link->handle, last_fn, last_ret);
1100         WLAN_LOG_ERROR("NextTuple failure? It's probably a Vcc mismatch.\n");
1101
1102 failed:
1103         prism2sta_release((u_long)link);
1104         return;
1105 }
1106
1107 /*----------------------------------------------------------------
1108 * prism2sta_release
1109 *
1110 * Half of the config/release pair.  Usually called in response to
1111 * a card ejection event.  Checks to make sure no higher layers
1112 * are still (or think they are) using the card via the link->open
1113 * field.
1114 *
1115 * NOTE: Don't forget to increment the link->open variable in the
1116 *  device_open method, and decrement it in the device_close
1117 *  method.
1118 *
1119 * Arguments:
1120 *       arg     a generic 32 bit variable.  It's the value that
1121 *               we assigned to link->release.data in sta_attach().
1122 *
1123 * Returns:
1124 *       nothing
1125 *
1126 * Side effects:
1127 *       All resources should be released after this function
1128 *       executes and finds the device !open.
1129 *
1130 * Call context:
1131 *       Possibly in a timer context.  Don't do anything that'll
1132 *       block.
1133 ----------------------------------------------------------------*/
1134 void prism2sta_release(u_long arg)
1135 {
1136         dev_link_t      *link = (dev_link_t *)arg;
1137
1138         DBFENTER;
1139
1140         /* First thing we should do is get the MSD back to the
1141          * HWPRESENT state.  I.e. everything quiescent.
1142          */
1143         prism2sta_ifstate(link->priv, P80211ENUM_ifstate_disable);
1144
1145         if (link->open) {
1146                 /* TODO: I don't think we're even using this bit of code
1147                  * and I don't think it's hurting us at the moment.
1148                  */
1149                 WLAN_LOG_DEBUG(1,
1150                         "prism2sta_cs: release postponed, '%s' still open\n",
1151                         link->dev->dev_name);
1152                 link->state |= DEV_STALE_CONFIG;
1153                 return;
1154         }
1155
1156         pcmcia_release_configuration(link->handle);
1157         pcmcia_release_io(link->handle, &link->io);
1158         pcmcia_release_irq(link->handle, &link->irq);
1159
1160         link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING);
1161
1162         DBFEXIT;
1163 }
1164
1165 /*----------------------------------------------------------------
1166 * prism2sta_event
1167 *
1168 * Handler for card services events.
1169 *
1170 * Arguments:
1171 *       event           The event code
1172 *       priority        hi/low - REMOVAL is the only hi
1173 *       args            ptr to card services struct containing info about
1174 *                       pcmcia status
1175 *
1176 * Returns:
1177 *       Zero on success, non-zero otherwise
1178 *
1179 * Side effects:
1180 *
1181 *
1182 * Call context:
1183 *       Both interrupt and process thread, depends on the event.
1184 ----------------------------------------------------------------*/
1185 static int
1186 prism2sta_event (
1187         event_t event,
1188         int priority,
1189         event_callback_args_t *args)
1190 {
1191         int                     result = 0;
1192         dev_link_t              *link = (dev_link_t *) args->client_data;
1193         wlandevice_t            *wlandev = (wlandevice_t*)link->priv;
1194         hfa384x_t               *hw = NULL;
1195
1196         DBFENTER;
1197
1198         if (wlandev) hw = wlandev->priv;
1199
1200         switch (event)
1201         {
1202         case CS_EVENT_CARD_INSERTION:
1203                 WLAN_LOG_DEBUG(5,"event is INSERTION\n");
1204                 link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
1205                 prism2sta_config(link);
1206                 if (!(link->state & DEV_CONFIG)) {
1207                         wlandev->netdev->irq = 0;
1208                         WLAN_LOG_ERROR(
1209                                 "%s: Initialization failed!\n", dev_info);
1210                         wlandev->msdstate = WLAN_MSD_HWFAIL;
1211                         break;
1212                 }
1213
1214                 /* Fill in the rest of the hw struct */
1215                 hw->irq = wlandev->netdev->irq;
1216                 hw->iobase = wlandev->netdev->base_addr;
1217                 hw->link = link;
1218
1219                 if (prism2_doreset) {
1220                         result = hfa384x_corereset(hw,
1221                                         prism2_reset_holdtime,
1222                                         prism2_reset_settletime, 0);
1223                         if ( result ) {
1224                                 WLAN_LOG_ERROR(
1225                                         "corereset() failed, result=%d.\n",
1226                                         result);
1227                                 wlandev->msdstate = WLAN_MSD_HWFAIL;
1228                                 break;
1229                         }
1230                 }
1231
1232 #if 0
1233                 /*
1234                  * TODO: test_hostif() not implemented yet.
1235                  */
1236                 result = hfa384x_test_hostif(hw);
1237                 if (result) {
1238                         WLAN_LOG_ERROR(
1239                         "test_hostif() failed, result=%d.\n", result);
1240                         wlandev->msdstate = WLAN_MSD_HWFAIL;
1241                         break;
1242                 }
1243 #endif
1244                 wlandev->msdstate = WLAN_MSD_HWPRESENT;
1245                 break;
1246
1247         case CS_EVENT_CARD_REMOVAL:
1248                 WLAN_LOG_DEBUG(5,"event is REMOVAL\n");
1249                 link->state &= ~DEV_PRESENT;
1250
1251                 if (wlandev) {
1252                         p80211netdev_hwremoved(wlandev);
1253                 }
1254
1255 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
1256                 if (link->state & DEV_CONFIG)
1257                 {
1258                         link->release.expires = jiffies + (HZ/20);
1259                         add_timer(&link->release);
1260                 }
1261 #endif
1262                 break;
1263         case CS_EVENT_RESET_REQUEST:
1264                 WLAN_LOG_DEBUG(5,"event is RESET_REQUEST\n");
1265                 WLAN_LOG_NOTICE(
1266                         "prism2 card reset not supported "
1267                         "due to post-reset user mode configuration "
1268                         "requirements.\n");
1269                 WLAN_LOG_NOTICE(
1270                         "  From user mode, use "
1271                         "'cardctl suspend;cardctl resume' "
1272                         "instead.\n");
1273                 break;
1274         case CS_EVENT_RESET_PHYSICAL:
1275         case CS_EVENT_CARD_RESET:
1276                 WLAN_LOG_WARNING("Rx'd CS_EVENT_RESET_xxx, should not "
1277                         "be possible since RESET_REQUEST was denied.\n");
1278                 break;
1279
1280         case CS_EVENT_PM_SUSPEND:
1281                 WLAN_LOG_DEBUG(5,"event is SUSPEND\n");
1282                 link->state |= DEV_SUSPEND;
1283                 if (link->state & DEV_CONFIG)
1284                 {
1285                         prism2sta_ifstate(wlandev, P80211ENUM_ifstate_disable);
1286                         pcmcia_release_configuration(link->handle);
1287                 }
1288                 break;
1289
1290         case CS_EVENT_PM_RESUME:
1291                 WLAN_LOG_DEBUG(5,"event is RESUME\n");
1292                 link->state &= ~DEV_SUSPEND;
1293                 if (link->state & DEV_CONFIG) {
1294                         pcmcia_request_configuration(link->handle, &link->conf);
1295                 }
1296                 break;
1297         }
1298
1299         DBFEXIT;
1300         return 0;  /* noone else does anthing with the return value */
1301 }
1302 #endif // <= 2.6.15
1303
1304
1305
1306 int hfa384x_corereset(hfa384x_t *hw, int holdtime, int settletime, int genesis)
1307 {
1308         int             result = 0;
1309         conf_reg_t      reg;
1310         UINT8           corsave;
1311         DBFENTER;
1312
1313         WLAN_LOG_DEBUG(3, "Doing reset via CardServices().\n");
1314
1315         /* Collect COR */
1316         reg.Function = 0;
1317         reg.Action = CS_READ;
1318         reg.Offset = CISREG_COR;
1319 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
1320         result = pcmcia_access_configuration_register(hw->pdev, &reg);
1321 #else
1322         result = pcmcia_access_configuration_register(
1323                         hw->link->handle,
1324                         &reg);
1325 #endif
1326         if (result != CS_SUCCESS ) {
1327                 WLAN_LOG_ERROR(
1328                         ":0: AccessConfigurationRegister(CS_READ) failed,"
1329                         "result=%d.\n", result);
1330                 result = -EIO;
1331         }
1332         corsave = reg.Value;
1333
1334         /* Write reset bit (BIT7) */
1335         reg.Value |= BIT7;
1336         reg.Action = CS_WRITE;
1337         reg.Offset = CISREG_COR;
1338 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
1339         result = pcmcia_access_configuration_register(hw->pdev, &reg);
1340 #else
1341         result = pcmcia_access_configuration_register(
1342                         hw->link->handle,
1343                         &reg);
1344 #endif
1345         if (result != CS_SUCCESS ) {
1346                 WLAN_LOG_ERROR(
1347                         ":1: AccessConfigurationRegister(CS_WRITE) failed,"
1348                         "result=%d.\n", result);
1349                 result = -EIO;
1350         }
1351
1352         /* Hold for holdtime */
1353         mdelay(holdtime);
1354
1355         if (genesis) {
1356                 reg.Value = genesis;
1357                 reg.Action = CS_WRITE;
1358                 reg.Offset = CISREG_CCSR;
1359 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
1360                 result = pcmcia_access_configuration_register(hw->pdev, &reg);
1361 #else
1362                 result = pcmcia_access_configuration_register(
1363                                       hw->link->handle,
1364                                       &reg);
1365 #endif
1366                 if (result != CS_SUCCESS ) {
1367                         WLAN_LOG_ERROR(
1368                                 ":1: AccessConfigurationRegister(CS_WRITE) failed,"
1369                                 "result=%d.\n", result);
1370                         result = -EIO;
1371                 }
1372         }
1373
1374         /* Hold for holdtime */
1375         mdelay(holdtime);
1376
1377         /* Clear reset bit */
1378         reg.Value &= ~BIT7;
1379         reg.Action = CS_WRITE;
1380         reg.Offset = CISREG_COR;
1381 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
1382         result = pcmcia_access_configuration_register(hw->pdev, &reg);
1383 #else
1384         result = pcmcia_access_configuration_register(
1385                                       hw->link->handle,
1386                                       &reg);
1387 #endif
1388         if (result != CS_SUCCESS ) {
1389                 WLAN_LOG_ERROR(
1390                         ":2: AccessConfigurationRegister(CS_WRITE) failed,"
1391                         "result=%d.\n", result);
1392                 result = -EIO;
1393                 goto done;
1394         }
1395
1396         /* Wait for settletime */
1397         mdelay(settletime);
1398
1399         /* Set non-reset bits back what they were */
1400         reg.Value = corsave;
1401         reg.Action = CS_WRITE;
1402         reg.Offset = CISREG_COR;
1403 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,16)
1404         result = pcmcia_access_configuration_register(hw->pdev, &reg);
1405 #else
1406         result = pcmcia_access_configuration_register(
1407                                       hw->link->handle,
1408                                       &reg);
1409 #endif
1410         if (result != CS_SUCCESS ) {
1411                 WLAN_LOG_ERROR(
1412                         ":2: AccessConfigurationRegister(CS_WRITE) failed,"
1413                         "result=%d.\n", result);
1414                 result = -EIO;
1415                 goto done;
1416         }
1417
1418 done:
1419         DBFEXIT;
1420         return result;
1421 }
1422
1423 #ifdef MODULE
1424
1425 static int __init prism2cs_init(void)
1426 {
1427 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68))
1428         servinfo_t      serv;
1429 #endif
1430
1431         DBFENTER;
1432
1433         WLAN_LOG_NOTICE("%s Loaded\n", version);
1434         WLAN_LOG_NOTICE("dev_info is: %s\n", dev_info);
1435
1436 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68))
1437         pcmcia_get_card_services_info(&serv);
1438         if ( serv.Revision != CS_RELEASE_CODE )
1439         {
1440                 printk(KERN_NOTICE"%s: CardServices release does not match!\n", dev_info);
1441                 return -1;
1442         }
1443
1444         /* This call will result in a call to prism2sta_attach */
1445         /*   and eventually prism2sta_detach */
1446         register_pccard_driver( &dev_info, &prism2sta_attach, &prism2sta_detach);
1447 #else
1448         pcmcia_register_driver(&prism2_cs_driver);
1449 #endif
1450
1451         DBFEXIT;
1452         return 0;
1453 }
1454
1455 static void __exit prism2cs_cleanup(void)
1456 {
1457 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68))
1458         dev_link_t *link = dev_list;
1459         dev_link_t *nlink;
1460         DBFENTER;
1461
1462 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) )
1463         for (link=dev_list; link != NULL; link = nlink) {
1464                 nlink = link->next;
1465                 if ( link->state & DEV_CONFIG ) {
1466                         prism2sta_release((u_long)link);
1467                 }
1468                 prism2sta_detach(link); /* remember detach() frees link */
1469         }
1470 #endif
1471
1472         unregister_pccard_driver( &dev_info);
1473 #else
1474         pcmcia_unregister_driver(&prism2_cs_driver);
1475 #endif
1476
1477         printk(KERN_NOTICE "%s Unloaded\n", version);
1478
1479         DBFEXIT;
1480         return;
1481 }
1482
1483 module_init(prism2cs_init);
1484 module_exit(prism2cs_cleanup);
1485
1486 #endif // MODULE
1487