1*4882a593Smuzhiyun /*** -*- linux-c -*- **********************************************************
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun Copyright 2000-2001 ATMEL Corporation.
6*4882a593Smuzhiyun Copyright 2003 Simon Kelley.
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun This code was developed from version 2.1.1 of the Atmel drivers,
9*4882a593Smuzhiyun released by Atmel corp. under the GPL in December 2002. It also
10*4882a593Smuzhiyun includes code from the Linux aironet drivers (C) Benjamin Reed,
11*4882a593Smuzhiyun and the Linux PCMCIA package, (C) David Hinds.
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun For all queries about this code, please contact the current author,
14*4882a593Smuzhiyun Simon Kelley <simon@thekelleys.org.uk> and not Atmel Corporation.
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun This program is free software; you can redistribute it and/or modify
17*4882a593Smuzhiyun it under the terms of the GNU General Public License as published by
18*4882a593Smuzhiyun the Free Software Foundation; either version 2 of the License, or
19*4882a593Smuzhiyun (at your option) any later version.
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun This software is distributed in the hope that it will be useful,
22*4882a593Smuzhiyun but WITHOUT ANY WARRANTY; without even the implied warranty of
23*4882a593Smuzhiyun MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24*4882a593Smuzhiyun GNU General Public License for more details.
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun You should have received a copy of the GNU General Public License
27*4882a593Smuzhiyun along with Atmel wireless lan drivers; if not, see
28*4882a593Smuzhiyun <http://www.gnu.org/licenses/>.
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun ******************************************************************************/
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #ifdef __IN_PCMCIA_PACKAGE__
33*4882a593Smuzhiyun #include <pcmcia/k_compat.h>
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun #include <linux/kernel.h>
36*4882a593Smuzhiyun #include <linux/module.h>
37*4882a593Smuzhiyun #include <linux/ptrace.h>
38*4882a593Smuzhiyun #include <linux/slab.h>
39*4882a593Smuzhiyun #include <linux/string.h>
40*4882a593Smuzhiyun #include <linux/netdevice.h>
41*4882a593Smuzhiyun #include <linux/moduleparam.h>
42*4882a593Smuzhiyun #include <linux/device.h>
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #include <pcmcia/cistpl.h>
45*4882a593Smuzhiyun #include <pcmcia/cisreg.h>
46*4882a593Smuzhiyun #include <pcmcia/ds.h>
47*4882a593Smuzhiyun #include <pcmcia/ciscode.h>
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #include <asm/io.h>
50*4882a593Smuzhiyun #include <linux/wireless.h>
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #include "atmel.h"
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /*====================================================================*/
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun MODULE_AUTHOR("Simon Kelley");
58*4882a593Smuzhiyun MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards.");
59*4882a593Smuzhiyun MODULE_LICENSE("GPL");
60*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards");
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /*====================================================================*/
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun static int atmel_config(struct pcmcia_device *link);
65*4882a593Smuzhiyun static void atmel_release(struct pcmcia_device *link);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun static void atmel_detach(struct pcmcia_device *p_dev);
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun struct local_info {
70*4882a593Smuzhiyun struct net_device *eth_dev;
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun
atmel_probe(struct pcmcia_device * p_dev)73*4882a593Smuzhiyun static int atmel_probe(struct pcmcia_device *p_dev)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun struct local_info *local;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun dev_dbg(&p_dev->dev, "atmel_attach()\n");
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun /* Allocate space for private device-specific data */
80*4882a593Smuzhiyun local = kzalloc(sizeof(*local), GFP_KERNEL);
81*4882a593Smuzhiyun if (!local)
82*4882a593Smuzhiyun return -ENOMEM;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun p_dev->priv = local;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun return atmel_config(p_dev);
87*4882a593Smuzhiyun } /* atmel_attach */
88*4882a593Smuzhiyun
atmel_detach(struct pcmcia_device * link)89*4882a593Smuzhiyun static void atmel_detach(struct pcmcia_device *link)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun dev_dbg(&link->dev, "atmel_detach\n");
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun atmel_release(link);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun kfree(link->priv);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* Call-back function to interrogate PCMCIA-specific information
99*4882a593Smuzhiyun about the current existence of the card */
card_present(void * arg)100*4882a593Smuzhiyun static int card_present(void *arg)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun struct pcmcia_device *link = (struct pcmcia_device *)arg;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun if (pcmcia_dev_present(link))
105*4882a593Smuzhiyun return 1;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun return 0;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
atmel_config_check(struct pcmcia_device * p_dev,void * priv_data)110*4882a593Smuzhiyun static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun if (p_dev->config_index == 0)
113*4882a593Smuzhiyun return -EINVAL;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun return pcmcia_request_io(p_dev);
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
atmel_config(struct pcmcia_device * link)118*4882a593Smuzhiyun static int atmel_config(struct pcmcia_device *link)
119*4882a593Smuzhiyun {
120*4882a593Smuzhiyun int ret;
121*4882a593Smuzhiyun const struct pcmcia_device_id *did;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun did = dev_get_drvdata(&link->dev);
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun dev_dbg(&link->dev, "atmel_config\n");
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
128*4882a593Smuzhiyun CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun if (pcmcia_loop_config(link, atmel_config_check, NULL))
131*4882a593Smuzhiyun goto failed;
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if (!link->irq) {
134*4882a593Smuzhiyun dev_err(&link->dev, "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config.");
135*4882a593Smuzhiyun goto failed;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun ret = pcmcia_enable_device(link);
139*4882a593Smuzhiyun if (ret)
140*4882a593Smuzhiyun goto failed;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun ((struct local_info *)link->priv)->eth_dev =
143*4882a593Smuzhiyun init_atmel_card(link->irq,
144*4882a593Smuzhiyun link->resource[0]->start,
145*4882a593Smuzhiyun did ? did->driver_info : ATMEL_FW_TYPE_NONE,
146*4882a593Smuzhiyun &link->dev,
147*4882a593Smuzhiyun card_present,
148*4882a593Smuzhiyun link);
149*4882a593Smuzhiyun if (!((struct local_info *)link->priv)->eth_dev)
150*4882a593Smuzhiyun goto failed;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun return 0;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun failed:
156*4882a593Smuzhiyun atmel_release(link);
157*4882a593Smuzhiyun return -ENODEV;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
atmel_release(struct pcmcia_device * link)160*4882a593Smuzhiyun static void atmel_release(struct pcmcia_device *link)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun struct net_device *dev = ((struct local_info *)link->priv)->eth_dev;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun dev_dbg(&link->dev, "atmel_release\n");
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun if (dev)
167*4882a593Smuzhiyun stop_atmel_card(dev);
168*4882a593Smuzhiyun ((struct local_info *)link->priv)->eth_dev = NULL;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun pcmcia_disable_device(link);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
atmel_suspend(struct pcmcia_device * link)173*4882a593Smuzhiyun static int atmel_suspend(struct pcmcia_device *link)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun struct local_info *local = link->priv;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun netif_device_detach(local->eth_dev);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun return 0;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
atmel_resume(struct pcmcia_device * link)182*4882a593Smuzhiyun static int atmel_resume(struct pcmcia_device *link)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun struct local_info *local = link->priv;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun atmel_open(local->eth_dev);
187*4882a593Smuzhiyun netif_device_attach(local->eth_dev);
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return 0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /*====================================================================*/
193*4882a593Smuzhiyun /* We use the driver_info field to store the correct firmware type for a card. */
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun #define PCMCIA_DEVICE_MANF_CARD_INFO(manf, card, info) { \
196*4882a593Smuzhiyun .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
197*4882a593Smuzhiyun PCMCIA_DEV_ID_MATCH_CARD_ID, \
198*4882a593Smuzhiyun .manf_id = (manf), \
199*4882a593Smuzhiyun .card_id = (card), \
200*4882a593Smuzhiyun .driver_info = (kernel_ulong_t)(info), }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun #define PCMCIA_DEVICE_PROD_ID12_INFO(v1, v2, vh1, vh2, info) { \
203*4882a593Smuzhiyun .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
204*4882a593Smuzhiyun PCMCIA_DEV_ID_MATCH_PROD_ID2, \
205*4882a593Smuzhiyun .prod_id = { (v1), (v2), NULL, NULL }, \
206*4882a593Smuzhiyun .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
207*4882a593Smuzhiyun .driver_info = (kernel_ulong_t)(info), }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun static const struct pcmcia_device_id atmel_ids[] = {
210*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM),
211*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM),
212*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E),
213*4882a593Smuzhiyun PCMCIA_DEVICE_MANF_CARD_INFO(0xd601, 0x0007, ATMEL_FW_TYPE_502),
214*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9, ATMEL_FW_TYPE_502E),
215*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f, ATMEL_FW_TYPE_502),
216*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_D", 0xabda4164, 0x3675d704, ATMEL_FW_TYPE_502D),
217*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C502AR_E", 0xabda4164, 0x4172e792, ATMEL_FW_TYPE_502E),
218*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504_R", 0xabda4164, 0x917f3d72, ATMEL_FW_TYPE_504_2958),
219*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504", 0xabda4164, 0x5040670a, ATMEL_FW_TYPE_504),
220*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f, ATMEL_FW_TYPE_504A_2958),
221*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5, ATMEL_FW_TYPE_502),
222*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b, ATMEL_FW_TYPE_502E),
223*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6, ATMEL_FW_TYPE_502),
224*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("IEEE 802.11b", "Wireless LAN Card S", 0x5b878724, 0x5fba533a, ATMEL_FW_TYPE_504_2958),
225*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68, ATMEL_FW_TYPE_502),
226*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W", 0xc4f8b18b, 0x30f38774, ATMEL_FW_TYPE_502D),
227*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377, ATMEL_FW_TYPE_502),
228*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("Wireless", "PC_CARD", 0xa407ecdd, 0x119f6314, ATMEL_FW_TYPE_502D),
229*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4, ATMEL_FW_TYPE_502D),
230*4882a593Smuzhiyun PCMCIA_DEVICE_PROD_ID12_INFO("LG", "LW2100N", 0xb474d43a, 0x6b1fec94, ATMEL_FW_TYPE_502E),
231*4882a593Smuzhiyun PCMCIA_DEVICE_NULL
232*4882a593Smuzhiyun };
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun static struct pcmcia_driver atmel_driver = {
237*4882a593Smuzhiyun .owner = THIS_MODULE,
238*4882a593Smuzhiyun .name = "atmel_cs",
239*4882a593Smuzhiyun .probe = atmel_probe,
240*4882a593Smuzhiyun .remove = atmel_detach,
241*4882a593Smuzhiyun .id_table = atmel_ids,
242*4882a593Smuzhiyun .suspend = atmel_suspend,
243*4882a593Smuzhiyun .resume = atmel_resume,
244*4882a593Smuzhiyun };
245*4882a593Smuzhiyun module_pcmcia_driver(atmel_driver);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun /*
248*4882a593Smuzhiyun This program is free software; you can redistribute it and/or
249*4882a593Smuzhiyun modify it under the terms of the GNU General Public License
250*4882a593Smuzhiyun as published by the Free Software Foundation; either version 2
251*4882a593Smuzhiyun of the License, or (at your option) any later version.
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun This program is distributed in the hope that it will be useful,
254*4882a593Smuzhiyun but WITHOUT ANY WARRANTY; without even the implied warranty of
255*4882a593Smuzhiyun MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
256*4882a593Smuzhiyun GNU General Public License for more details.
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun In addition:
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun Redistribution and use in source and binary forms, with or without
261*4882a593Smuzhiyun modification, are permitted provided that the following conditions
262*4882a593Smuzhiyun are met:
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun 1. Redistributions of source code must retain the above copyright
265*4882a593Smuzhiyun notice, this list of conditions and the following disclaimer.
266*4882a593Smuzhiyun 2. Redistributions in binary form must reproduce the above copyright
267*4882a593Smuzhiyun notice, this list of conditions and the following disclaimer in the
268*4882a593Smuzhiyun documentation and/or other materials provided with the distribution.
269*4882a593Smuzhiyun 3. The name of the author may not be used to endorse or promote
270*4882a593Smuzhiyun products derived from this software without specific prior written
271*4882a593Smuzhiyun permission.
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
274*4882a593Smuzhiyun IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
275*4882a593Smuzhiyun WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
276*4882a593Smuzhiyun ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
277*4882a593Smuzhiyun INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
278*4882a593Smuzhiyun (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
279*4882a593Smuzhiyun SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
280*4882a593Smuzhiyun HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
281*4882a593Smuzhiyun STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
282*4882a593Smuzhiyun IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
283*4882a593Smuzhiyun POSSIBILITY OF SUCH DAMAGE.
284*4882a593Smuzhiyun */
285