xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/atmel/atmel_cs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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