1298e50adSKalle Valo // SPDX-License-Identifier: GPL-2.0-only
2298e50adSKalle Valo /*=============================================================================
3298e50adSKalle Valo  *
4298e50adSKalle Valo  * A  PCMCIA client driver for the Raylink wireless LAN card.
5298e50adSKalle Valo  * The starting point for this module was the skeleton.c in the
6298e50adSKalle Valo  * PCMCIA 2.9.12 package written by David Hinds, dahinds@users.sourceforge.net
7298e50adSKalle Valo  *
8298e50adSKalle Valo  * Copyright (c) 1998  Corey Thomas (corey@world.std.com)
9298e50adSKalle Valo  *
10298e50adSKalle Valo  * Changes:
11298e50adSKalle Valo  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/08/2000
12298e50adSKalle Valo  * - reorganize kmallocs in ray_attach, checking all for failure
13298e50adSKalle Valo  *   and releasing the previous allocations if one fails
14298e50adSKalle Valo  *
15298e50adSKalle Valo  * Daniele Bellucci <bellucda@tiscali.it> - 07/10/2003
16298e50adSKalle Valo  * - Audit copy_to_user in ioctl(SIOCGIWESSID)
17298e50adSKalle Valo  *
18298e50adSKalle Valo =============================================================================*/
19298e50adSKalle Valo 
20298e50adSKalle Valo #include <linux/module.h>
21298e50adSKalle Valo #include <linux/kernel.h>
22298e50adSKalle Valo #include <linux/proc_fs.h>
23298e50adSKalle Valo #include <linux/ptrace.h>
24298e50adSKalle Valo #include <linux/seq_file.h>
25298e50adSKalle Valo #include <linux/string.h>
26298e50adSKalle Valo #include <linux/timer.h>
27298e50adSKalle Valo #include <linux/init.h>
28298e50adSKalle Valo #include <linux/netdevice.h>
29298e50adSKalle Valo #include <linux/etherdevice.h>
30298e50adSKalle Valo #include <linux/if_arp.h>
31298e50adSKalle Valo #include <linux/ioport.h>
32298e50adSKalle Valo #include <linux/skbuff.h>
33298e50adSKalle Valo #include <linux/ieee80211.h>
34298e50adSKalle Valo 
35298e50adSKalle Valo #include <pcmcia/cistpl.h>
36298e50adSKalle Valo #include <pcmcia/cisreg.h>
37298e50adSKalle Valo #include <pcmcia/ds.h>
38298e50adSKalle Valo 
39298e50adSKalle Valo #include <linux/wireless.h>
40298e50adSKalle Valo #include <net/iw_handler.h>
41298e50adSKalle Valo 
42298e50adSKalle Valo #include <asm/io.h>
43298e50adSKalle Valo #include <asm/byteorder.h>
44298e50adSKalle Valo #include <linux/uaccess.h>
45298e50adSKalle Valo 
46298e50adSKalle Valo /* Warning : these stuff will slow down the driver... */
47298e50adSKalle Valo #define WIRELESS_SPY		/* Enable spying addresses */
48298e50adSKalle Valo /* Definitions we need for spy */
49298e50adSKalle Valo typedef struct iw_statistics iw_stats;
50298e50adSKalle Valo typedef u_char mac_addr[ETH_ALEN];	/* Hardware address */
51298e50adSKalle Valo 
52298e50adSKalle Valo #include "rayctl.h"
53298e50adSKalle Valo #include "ray_cs.h"
54298e50adSKalle Valo 
55298e50adSKalle Valo 
56298e50adSKalle Valo /** Prototypes based on PCMCIA skeleton driver *******************************/
57298e50adSKalle Valo static int ray_config(struct pcmcia_device *link);
58298e50adSKalle Valo static void ray_release(struct pcmcia_device *link);
59298e50adSKalle Valo static void ray_detach(struct pcmcia_device *p_dev);
60298e50adSKalle Valo 
61298e50adSKalle Valo /***** Prototypes indicated by device structure ******************************/
62298e50adSKalle Valo static int ray_dev_close(struct net_device *dev);
63298e50adSKalle Valo static int ray_dev_config(struct net_device *dev, struct ifmap *map);
64298e50adSKalle Valo static struct net_device_stats *ray_get_stats(struct net_device *dev);
65298e50adSKalle Valo static int ray_dev_init(struct net_device *dev);
66298e50adSKalle Valo 
67298e50adSKalle Valo static int ray_open(struct net_device *dev);
68298e50adSKalle Valo static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
69298e50adSKalle Valo 					    struct net_device *dev);
70298e50adSKalle Valo static void set_multicast_list(struct net_device *dev);
71298e50adSKalle Valo static void ray_update_multi_list(struct net_device *dev, int all);
72298e50adSKalle Valo static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
73298e50adSKalle Valo 			   unsigned char *data, int len);
74298e50adSKalle Valo static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx,
75298e50adSKalle Valo 			     UCHAR msg_type, unsigned char *data);
76298e50adSKalle Valo static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len);
77298e50adSKalle Valo static iw_stats *ray_get_wireless_stats(struct net_device *dev);
78298e50adSKalle Valo static const struct iw_handler_def ray_handler_def;
79298e50adSKalle Valo 
80298e50adSKalle Valo /***** Prototypes for raylink functions **************************************/
81298e50adSKalle Valo static void authenticate(ray_dev_t *local);
82298e50adSKalle Valo static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type);
83298e50adSKalle Valo static void authenticate_timeout(struct timer_list *t);
84298e50adSKalle Valo static int get_free_ccs(ray_dev_t *local);
85298e50adSKalle Valo static int get_free_tx_ccs(ray_dev_t *local);
86298e50adSKalle Valo static void init_startup_params(ray_dev_t *local);
87298e50adSKalle Valo static int parse_addr(char *in_str, UCHAR *out);
88298e50adSKalle Valo static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, UCHAR type);
89298e50adSKalle Valo static int ray_init(struct net_device *dev);
90298e50adSKalle Valo static int interrupt_ecf(ray_dev_t *local, int ccs);
91298e50adSKalle Valo static void ray_reset(struct net_device *dev);
92298e50adSKalle Valo static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len);
93298e50adSKalle Valo static void verify_dl_startup(struct timer_list *t);
94298e50adSKalle Valo 
95298e50adSKalle Valo /* Prototypes for interrpt time functions **********************************/
96298e50adSKalle Valo static irqreturn_t ray_interrupt(int reg, void *dev_id);
97298e50adSKalle Valo static void clear_interrupt(ray_dev_t *local);
98298e50adSKalle Valo static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
99298e50adSKalle Valo 			      unsigned int pkt_addr, int rx_len);
100298e50adSKalle Valo static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len);
101298e50adSKalle Valo static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs);
102298e50adSKalle Valo static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs);
103298e50adSKalle Valo static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs,
104298e50adSKalle Valo 			    unsigned int pkt_addr, int rx_len);
105298e50adSKalle Valo static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
106298e50adSKalle Valo 		    unsigned int pkt_addr, int rx_len);
107298e50adSKalle Valo static void associate(ray_dev_t *local);
108298e50adSKalle Valo 
109298e50adSKalle Valo /* Card command functions */
110298e50adSKalle Valo static int dl_startup_params(struct net_device *dev);
111298e50adSKalle Valo static void join_net(struct timer_list *t);
112298e50adSKalle Valo static void start_net(struct timer_list *t);
113298e50adSKalle Valo 
114298e50adSKalle Valo /*===========================================================================*/
115298e50adSKalle Valo /* Parameters that can be set with 'insmod' */
116298e50adSKalle Valo 
117298e50adSKalle Valo /* ADHOC=0, Infrastructure=1 */
118298e50adSKalle Valo static int net_type = ADHOC;
119298e50adSKalle Valo 
120298e50adSKalle Valo /* Hop dwell time in Kus (1024 us units defined by 802.11) */
121298e50adSKalle Valo static int hop_dwell = 128;
122298e50adSKalle Valo 
123298e50adSKalle Valo /* Beacon period in Kus */
124298e50adSKalle Valo static int beacon_period = 256;
125298e50adSKalle Valo 
126298e50adSKalle Valo /* power save mode (0 = off, 1 = save power) */
127298e50adSKalle Valo static int psm;
128298e50adSKalle Valo 
129298e50adSKalle Valo /* String for network's Extended Service Set ID. 32 Characters max */
130298e50adSKalle Valo static char *essid;
131298e50adSKalle Valo 
132298e50adSKalle Valo /* Default to encapsulation unless translation requested */
133298e50adSKalle Valo static bool translate = true;
134298e50adSKalle Valo 
135298e50adSKalle Valo static int country = USA;
136298e50adSKalle Valo 
137298e50adSKalle Valo static int sniffer;
138298e50adSKalle Valo 
139298e50adSKalle Valo static int bc;
140298e50adSKalle Valo 
141298e50adSKalle Valo /* 48 bit physical card address if overriding card's real physical
142298e50adSKalle Valo  * address is required.  Since IEEE 802.11 addresses are 48 bits
143298e50adSKalle Valo  * like ethernet, an int can't be used, so a string is used. To
144298e50adSKalle Valo  * allow use of addresses starting with a decimal digit, the first
145298e50adSKalle Valo  * character must be a letter and will be ignored. This letter is
146298e50adSKalle Valo  * followed by up to 12 hex digits which are the address.  If less
147298e50adSKalle Valo  * than 12 digits are used, the address will be left filled with 0's.
148298e50adSKalle Valo  * Note that bit 0 of the first byte is the broadcast bit, and evil
149298e50adSKalle Valo  * things will happen if it is not 0 in a card address.
150298e50adSKalle Valo  */
151298e50adSKalle Valo static char *phy_addr = NULL;
152298e50adSKalle Valo 
153298e50adSKalle Valo static unsigned int ray_mem_speed = 500;
154298e50adSKalle Valo 
155298e50adSKalle Valo /* WARNING: THIS DRIVER IS NOT CAPABLE OF HANDLING MULTIPLE DEVICES! */
156298e50adSKalle Valo static struct pcmcia_device *this_device = NULL;
157298e50adSKalle Valo 
158298e50adSKalle Valo MODULE_AUTHOR("Corey Thomas <corey@world.std.com>");
159298e50adSKalle Valo MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver");
160298e50adSKalle Valo MODULE_LICENSE("GPL");
161298e50adSKalle Valo 
162298e50adSKalle Valo module_param(net_type, int, 0);
163298e50adSKalle Valo module_param(hop_dwell, int, 0);
164298e50adSKalle Valo module_param(beacon_period, int, 0);
165298e50adSKalle Valo module_param(psm, int, 0);
166298e50adSKalle Valo module_param(essid, charp, 0);
167298e50adSKalle Valo module_param(translate, bool, 0);
168298e50adSKalle Valo module_param(country, int, 0);
169298e50adSKalle Valo module_param(sniffer, int, 0);
170298e50adSKalle Valo module_param(bc, int, 0);
171298e50adSKalle Valo module_param(phy_addr, charp, 0);
172298e50adSKalle Valo module_param(ray_mem_speed, int, 0);
173298e50adSKalle Valo 
174298e50adSKalle Valo static const UCHAR b5_default_startup_parms[] = {
175298e50adSKalle Valo 	0, 0,			/* Adhoc station */
176298e50adSKalle Valo 	'L', 'I', 'N', 'U', 'X', 0, 0, 0,	/* 32 char ESSID */
177298e50adSKalle Valo 	0, 0, 0, 0, 0, 0, 0, 0,
178298e50adSKalle Valo 	0, 0, 0, 0, 0, 0, 0, 0,
179298e50adSKalle Valo 	0, 0, 0, 0, 0, 0, 0, 0,
180298e50adSKalle Valo 	1, 0,			/* Active scan, CA Mode */
181298e50adSKalle Valo 	0, 0, 0, 0, 0, 0,	/* No default MAC addr  */
182298e50adSKalle Valo 	0x7f, 0xff,		/* Frag threshold */
183298e50adSKalle Valo 	0x00, 0x80,		/* Hop time 128 Kus */
184298e50adSKalle Valo 	0x01, 0x00,		/* Beacon period 256 Kus */
185298e50adSKalle Valo 	0x01, 0x07, 0xa3,	/* DTIM, retries, ack timeout */
186298e50adSKalle Valo 	0x1d, 0x82, 0x4e,	/* SIFS, DIFS, PIFS */
187298e50adSKalle Valo 	0x7f, 0xff,		/* RTS threshold */
188298e50adSKalle Valo 	0x04, 0xe2, 0x38, 0xA4,	/* scan_dwell, max_scan_dwell */
189298e50adSKalle Valo 	0x05,			/* assoc resp timeout thresh */
190298e50adSKalle Valo 	0x08, 0x02, 0x08,	/* adhoc, infra, super cycle max */
191298e50adSKalle Valo 	0,			/* Promiscuous mode */
192298e50adSKalle Valo 	0x0c, 0x0bd,		/* Unique word */
193298e50adSKalle Valo 	0x32,			/* Slot time */
194298e50adSKalle Valo 	0xff, 0xff,		/* roam-low snr, low snr count */
195298e50adSKalle Valo 	0x05, 0xff,		/* Infra, adhoc missed bcn thresh */
196298e50adSKalle Valo 	0x01, 0x0b, 0x4f,	/* USA, hop pattern, hop pat length */
197298e50adSKalle Valo /* b4 - b5 differences start here */
198298e50adSKalle Valo 	0x00, 0x3f,		/* CW max */
199298e50adSKalle Valo 	0x00, 0x0f,		/* CW min */
200298e50adSKalle Valo 	0x04, 0x08,		/* Noise gain, limit offset */
201298e50adSKalle Valo 	0x28, 0x28,		/* det rssi, med busy offsets */
202298e50adSKalle Valo 	7,			/* det sync thresh */
203298e50adSKalle Valo 	0, 2, 2,		/* test mode, min, max */
204298e50adSKalle Valo 	0,			/* allow broadcast SSID probe resp */
205298e50adSKalle Valo 	0, 0,			/* privacy must start, can join */
206298e50adSKalle Valo 	2, 0, 0, 0, 0, 0, 0, 0	/* basic rate set */
207298e50adSKalle Valo };
208298e50adSKalle Valo 
209298e50adSKalle Valo static const UCHAR b4_default_startup_parms[] = {
210298e50adSKalle Valo 	0, 0,			/* Adhoc station */
211298e50adSKalle Valo 	'L', 'I', 'N', 'U', 'X', 0, 0, 0,	/* 32 char ESSID */
212298e50adSKalle Valo 	0, 0, 0, 0, 0, 0, 0, 0,
213298e50adSKalle Valo 	0, 0, 0, 0, 0, 0, 0, 0,
214298e50adSKalle Valo 	0, 0, 0, 0, 0, 0, 0, 0,
215298e50adSKalle Valo 	1, 0,			/* Active scan, CA Mode */
216298e50adSKalle Valo 	0, 0, 0, 0, 0, 0,	/* No default MAC addr  */
217298e50adSKalle Valo 	0x7f, 0xff,		/* Frag threshold */
218298e50adSKalle Valo 	0x02, 0x00,		/* Hop time */
219298e50adSKalle Valo 	0x00, 0x01,		/* Beacon period */
220298e50adSKalle Valo 	0x01, 0x07, 0xa3,	/* DTIM, retries, ack timeout */
221298e50adSKalle Valo 	0x1d, 0x82, 0xce,	/* SIFS, DIFS, PIFS */
222298e50adSKalle Valo 	0x7f, 0xff,		/* RTS threshold */
223298e50adSKalle Valo 	0xfb, 0x1e, 0xc7, 0x5c,	/* scan_dwell, max_scan_dwell */
224298e50adSKalle Valo 	0x05,			/* assoc resp timeout thresh */
225298e50adSKalle Valo 	0x04, 0x02, 0x4,	/* adhoc, infra, super cycle max */
226298e50adSKalle Valo 	0,			/* Promiscuous mode */
227298e50adSKalle Valo 	0x0c, 0x0bd,		/* Unique word */
228298e50adSKalle Valo 	0x4e,			/* Slot time (TBD seems wrong) */
229298e50adSKalle Valo 	0xff, 0xff,		/* roam-low snr, low snr count */
230298e50adSKalle Valo 	0x05, 0xff,		/* Infra, adhoc missed bcn thresh */
231298e50adSKalle Valo 	0x01, 0x0b, 0x4e,	/* USA, hop pattern, hop pat length */
232298e50adSKalle Valo /* b4 - b5 differences start here */
233298e50adSKalle Valo 	0x3f, 0x0f,		/* CW max, min */
234298e50adSKalle Valo 	0x04, 0x08,		/* Noise gain, limit offset */
235298e50adSKalle Valo 	0x28, 0x28,		/* det rssi, med busy offsets */
236298e50adSKalle Valo 	7,			/* det sync thresh */
237298e50adSKalle Valo 	0, 2, 2,		/* test mode, min, max */
238298e50adSKalle Valo 	0,			/* rx/tx delay */
239298e50adSKalle Valo 	0, 0, 0, 0, 0, 0,	/* current BSS id */
240298e50adSKalle Valo 	0			/* hop set */
241298e50adSKalle Valo };
242298e50adSKalle Valo 
243298e50adSKalle Valo /*===========================================================================*/
244298e50adSKalle Valo static const u8 eth2_llc[] = { 0xaa, 0xaa, 3, 0, 0, 0 };
245298e50adSKalle Valo 
246298e50adSKalle Valo static const char hop_pattern_length[] = { 1,
247298e50adSKalle Valo 	USA_HOP_MOD, EUROPE_HOP_MOD,
248298e50adSKalle Valo 	JAPAN_HOP_MOD, KOREA_HOP_MOD,
249298e50adSKalle Valo 	SPAIN_HOP_MOD, FRANCE_HOP_MOD,
250298e50adSKalle Valo 	ISRAEL_HOP_MOD, AUSTRALIA_HOP_MOD,
251298e50adSKalle Valo 	JAPAN_TEST_HOP_MOD
252298e50adSKalle Valo };
253298e50adSKalle Valo 
254298e50adSKalle Valo static const char rcsid[] =
255298e50adSKalle Valo     "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>";
256298e50adSKalle Valo 
257298e50adSKalle Valo static const struct net_device_ops ray_netdev_ops = {
258298e50adSKalle Valo 	.ndo_init 		= ray_dev_init,
259298e50adSKalle Valo 	.ndo_open 		= ray_open,
260298e50adSKalle Valo 	.ndo_stop 		= ray_dev_close,
261298e50adSKalle Valo 	.ndo_start_xmit		= ray_dev_start_xmit,
262298e50adSKalle Valo 	.ndo_set_config		= ray_dev_config,
263298e50adSKalle Valo 	.ndo_get_stats		= ray_get_stats,
264298e50adSKalle Valo 	.ndo_set_rx_mode	= set_multicast_list,
265298e50adSKalle Valo 	.ndo_set_mac_address 	= eth_mac_addr,
266298e50adSKalle Valo 	.ndo_validate_addr	= eth_validate_addr,
267298e50adSKalle Valo };
268298e50adSKalle Valo 
ray_probe(struct pcmcia_device * p_dev)269298e50adSKalle Valo static int ray_probe(struct pcmcia_device *p_dev)
270298e50adSKalle Valo {
271298e50adSKalle Valo 	ray_dev_t *local;
272298e50adSKalle Valo 	struct net_device *dev;
2734f8d66a9SChristophe JAILLET 	int ret;
274298e50adSKalle Valo 
275298e50adSKalle Valo 	dev_dbg(&p_dev->dev, "ray_attach()\n");
276298e50adSKalle Valo 
277298e50adSKalle Valo 	/* Allocate space for private device-specific data */
278298e50adSKalle Valo 	dev = alloc_etherdev(sizeof(ray_dev_t));
279298e50adSKalle Valo 	if (!dev)
2804f8d66a9SChristophe JAILLET 		return -ENOMEM;
281298e50adSKalle Valo 
282298e50adSKalle Valo 	local = netdev_priv(dev);
283298e50adSKalle Valo 	local->finder = p_dev;
284298e50adSKalle Valo 
285298e50adSKalle Valo 	/* The io structure describes IO port mapping. None used here */
286298e50adSKalle Valo 	p_dev->resource[0]->end = 0;
287298e50adSKalle Valo 	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
288298e50adSKalle Valo 
289298e50adSKalle Valo 	/* General socket configuration */
290298e50adSKalle Valo 	p_dev->config_flags |= CONF_ENABLE_IRQ;
291298e50adSKalle Valo 	p_dev->config_index = 1;
292298e50adSKalle Valo 
293298e50adSKalle Valo 	p_dev->priv = dev;
294298e50adSKalle Valo 
295298e50adSKalle Valo 	local->finder = p_dev;
296298e50adSKalle Valo 	local->card_status = CARD_INSERTED;
297298e50adSKalle Valo 	local->authentication_state = UNAUTHENTICATED;
298298e50adSKalle Valo 	local->num_multi = 0;
299298e50adSKalle Valo 	dev_dbg(&p_dev->dev, "ray_attach p_dev = %p,  dev = %p,  local = %p, intr = %p\n",
300298e50adSKalle Valo 	      p_dev, dev, local, &ray_interrupt);
301298e50adSKalle Valo 
302298e50adSKalle Valo 	/* Raylink entries in the device structure */
303298e50adSKalle Valo 	dev->netdev_ops = &ray_netdev_ops;
304298e50adSKalle Valo 	dev->wireless_handlers = &ray_handler_def;
305298e50adSKalle Valo #ifdef WIRELESS_SPY
306298e50adSKalle Valo 	local->wireless_data.spy_data = &local->spy_data;
307298e50adSKalle Valo 	dev->wireless_data = &local->wireless_data;
308298e50adSKalle Valo #endif /* WIRELESS_SPY */
309298e50adSKalle Valo 
310298e50adSKalle Valo 
311298e50adSKalle Valo 	dev_dbg(&p_dev->dev, "ray_cs ray_attach calling ether_setup.)\n");
312298e50adSKalle Valo 	netif_stop_queue(dev);
313298e50adSKalle Valo 
314298e50adSKalle Valo 	timer_setup(&local->timer, NULL, 0);
315298e50adSKalle Valo 
316298e50adSKalle Valo 	this_device = p_dev;
3174f8d66a9SChristophe JAILLET 	ret = ray_config(p_dev);
3184f8d66a9SChristophe JAILLET 	if (ret)
3194f8d66a9SChristophe JAILLET 		goto err_free_dev;
320298e50adSKalle Valo 
3214f8d66a9SChristophe JAILLET 	return 0;
3224f8d66a9SChristophe JAILLET 
3234f8d66a9SChristophe JAILLET err_free_dev:
3244f8d66a9SChristophe JAILLET 	free_netdev(dev);
3254f8d66a9SChristophe JAILLET 	return ret;
3264f8d66a9SChristophe JAILLET }
327298e50adSKalle Valo 
ray_detach(struct pcmcia_device * link)328298e50adSKalle Valo static void ray_detach(struct pcmcia_device *link)
329298e50adSKalle Valo {
330298e50adSKalle Valo 	struct net_device *dev;
331298e50adSKalle Valo 
332298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_detach\n");
333298e50adSKalle Valo 
334298e50adSKalle Valo 	this_device = NULL;
335298e50adSKalle Valo 	dev = link->priv;
336298e50adSKalle Valo 
337298e50adSKalle Valo 	ray_release(link);
338298e50adSKalle Valo 
339298e50adSKalle Valo 	if (link->priv) {
340298e50adSKalle Valo 		unregister_netdev(dev);
341298e50adSKalle Valo 		free_netdev(dev);
342298e50adSKalle Valo 	}
343298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_cs ray_detach ending\n");
344298e50adSKalle Valo } /* ray_detach */
345298e50adSKalle Valo 
346298e50adSKalle Valo #define MAX_TUPLE_SIZE 128
ray_config(struct pcmcia_device * link)347298e50adSKalle Valo static int ray_config(struct pcmcia_device *link)
348298e50adSKalle Valo {
349298e50adSKalle Valo 	int ret = 0;
350298e50adSKalle Valo 	int i;
351298e50adSKalle Valo 	struct net_device *dev = (struct net_device *)link->priv;
352298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
353298e50adSKalle Valo 
354298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_config\n");
355298e50adSKalle Valo 
356298e50adSKalle Valo 	/* Determine card type and firmware version */
357298e50adSKalle Valo 	printk(KERN_INFO "ray_cs Detected: %s%s%s%s\n",
358298e50adSKalle Valo 	       link->prod_id[0] ? link->prod_id[0] : " ",
359298e50adSKalle Valo 	       link->prod_id[1] ? link->prod_id[1] : " ",
360298e50adSKalle Valo 	       link->prod_id[2] ? link->prod_id[2] : " ",
361298e50adSKalle Valo 	       link->prod_id[3] ? link->prod_id[3] : " ");
362298e50adSKalle Valo 
363298e50adSKalle Valo 	/* Now allocate an interrupt line.  Note that this does not
364298e50adSKalle Valo 	   actually assign a handler to the interrupt.
365298e50adSKalle Valo 	 */
366298e50adSKalle Valo 	ret = pcmcia_request_irq(link, ray_interrupt);
367298e50adSKalle Valo 	if (ret)
368298e50adSKalle Valo 		goto failed;
369298e50adSKalle Valo 	dev->irq = link->irq;
370298e50adSKalle Valo 
371298e50adSKalle Valo 	ret = pcmcia_enable_device(link);
372298e50adSKalle Valo 	if (ret)
373298e50adSKalle Valo 		goto failed;
374298e50adSKalle Valo 
375298e50adSKalle Valo /*** Set up 32k window for shared memory (transmit and control) ************/
376298e50adSKalle Valo 	link->resource[2]->flags |= WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
377298e50adSKalle Valo 	link->resource[2]->start = 0;
378298e50adSKalle Valo 	link->resource[2]->end = 0x8000;
379298e50adSKalle Valo 	ret = pcmcia_request_window(link, link->resource[2], ray_mem_speed);
380298e50adSKalle Valo 	if (ret)
381298e50adSKalle Valo 		goto failed;
382298e50adSKalle Valo 	ret = pcmcia_map_mem_page(link, link->resource[2], 0);
383298e50adSKalle Valo 	if (ret)
384298e50adSKalle Valo 		goto failed;
385298e50adSKalle Valo 	local->sram = ioremap(link->resource[2]->start,
386298e50adSKalle Valo 			resource_size(link->resource[2]));
387298e50adSKalle Valo 	if (!local->sram)
388298e50adSKalle Valo 		goto failed;
389298e50adSKalle Valo 
390298e50adSKalle Valo /*** Set up 16k window for shared memory (receive buffer) ***************/
391298e50adSKalle Valo 	link->resource[3]->flags |=
392298e50adSKalle Valo 	    WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
393298e50adSKalle Valo 	link->resource[3]->start = 0;
394298e50adSKalle Valo 	link->resource[3]->end = 0x4000;
395298e50adSKalle Valo 	ret = pcmcia_request_window(link, link->resource[3], ray_mem_speed);
396298e50adSKalle Valo 	if (ret)
397298e50adSKalle Valo 		goto failed;
398298e50adSKalle Valo 	ret = pcmcia_map_mem_page(link, link->resource[3], 0x8000);
399298e50adSKalle Valo 	if (ret)
400298e50adSKalle Valo 		goto failed;
401298e50adSKalle Valo 	local->rmem = ioremap(link->resource[3]->start,
402298e50adSKalle Valo 			resource_size(link->resource[3]));
403298e50adSKalle Valo 	if (!local->rmem)
404298e50adSKalle Valo 		goto failed;
405298e50adSKalle Valo 
406298e50adSKalle Valo /*** Set up window for attribute memory ***********************************/
407298e50adSKalle Valo 	link->resource[4]->flags |=
408298e50adSKalle Valo 	    WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT;
409298e50adSKalle Valo 	link->resource[4]->start = 0;
410298e50adSKalle Valo 	link->resource[4]->end = 0x1000;
411298e50adSKalle Valo 	ret = pcmcia_request_window(link, link->resource[4], ray_mem_speed);
412298e50adSKalle Valo 	if (ret)
413298e50adSKalle Valo 		goto failed;
414298e50adSKalle Valo 	ret = pcmcia_map_mem_page(link, link->resource[4], 0);
415298e50adSKalle Valo 	if (ret)
416298e50adSKalle Valo 		goto failed;
417298e50adSKalle Valo 	local->amem = ioremap(link->resource[4]->start,
418298e50adSKalle Valo 			resource_size(link->resource[4]));
419298e50adSKalle Valo 	if (!local->amem)
420298e50adSKalle Valo 		goto failed;
421298e50adSKalle Valo 
422298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram);
423298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem);
424298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_config amem=%p\n", local->amem);
425298e50adSKalle Valo 	if (ray_init(dev) < 0) {
426298e50adSKalle Valo 		ray_release(link);
427298e50adSKalle Valo 		return -ENODEV;
428298e50adSKalle Valo 	}
429298e50adSKalle Valo 
430298e50adSKalle Valo 	SET_NETDEV_DEV(dev, &link->dev);
431298e50adSKalle Valo 	i = register_netdev(dev);
432298e50adSKalle Valo 	if (i != 0) {
433298e50adSKalle Valo 		printk("ray_config register_netdev() failed\n");
434298e50adSKalle Valo 		ray_release(link);
435298e50adSKalle Valo 		return i;
436298e50adSKalle Valo 	}
437298e50adSKalle Valo 
438298e50adSKalle Valo 	printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n",
439298e50adSKalle Valo 	       dev->name, dev->irq, dev->dev_addr);
440298e50adSKalle Valo 
441298e50adSKalle Valo 	return 0;
442298e50adSKalle Valo 
443298e50adSKalle Valo failed:
444298e50adSKalle Valo 	ray_release(link);
445298e50adSKalle Valo 	return -ENODEV;
446298e50adSKalle Valo } /* ray_config */
447298e50adSKalle Valo 
ccs_base(ray_dev_t * dev)448298e50adSKalle Valo static inline struct ccs __iomem *ccs_base(ray_dev_t *dev)
449298e50adSKalle Valo {
450298e50adSKalle Valo 	return dev->sram + CCS_BASE;
451298e50adSKalle Valo }
452298e50adSKalle Valo 
rcs_base(ray_dev_t * dev)453298e50adSKalle Valo static inline struct rcs __iomem *rcs_base(ray_dev_t *dev)
454298e50adSKalle Valo {
455298e50adSKalle Valo 	/*
456298e50adSKalle Valo 	 * This looks nonsensical, since there is a separate
457298e50adSKalle Valo 	 * RCS_BASE. But the difference between a "struct rcs"
458298e50adSKalle Valo 	 * and a "struct ccs" ends up being in the _index_ off
459298e50adSKalle Valo 	 * the base, so the base pointer is the same for both
460298e50adSKalle Valo 	 * ccs/rcs.
461298e50adSKalle Valo 	 */
462298e50adSKalle Valo 	return dev->sram + CCS_BASE;
463298e50adSKalle Valo }
464298e50adSKalle Valo 
465298e50adSKalle Valo /*===========================================================================*/
ray_init(struct net_device * dev)466298e50adSKalle Valo static int ray_init(struct net_device *dev)
467298e50adSKalle Valo {
468298e50adSKalle Valo 	int i;
469298e50adSKalle Valo 	struct ccs __iomem *pccs;
470298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
471298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
472298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_init(0x%p)\n", dev);
473298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
474298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_init - device not present\n");
475298e50adSKalle Valo 		return -1;
476298e50adSKalle Valo 	}
477298e50adSKalle Valo 
478298e50adSKalle Valo 	local->net_type = net_type;
479298e50adSKalle Valo 	local->sta_type = TYPE_STA;
480298e50adSKalle Valo 
481298e50adSKalle Valo 	/* Copy the startup results to local memory */
482298e50adSKalle Valo 	memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,
483298e50adSKalle Valo 		      sizeof(struct startup_res_6));
484298e50adSKalle Valo 
485298e50adSKalle Valo 	/* Check Power up test status and get mac address from card */
486298e50adSKalle Valo 	if (local->startup_res.startup_word != 0x80) {
487298e50adSKalle Valo 		printk(KERN_INFO "ray_init ERROR card status = %2x\n",
488298e50adSKalle Valo 		       local->startup_res.startup_word);
489298e50adSKalle Valo 		local->card_status = CARD_INIT_ERROR;
490298e50adSKalle Valo 		return -1;
491298e50adSKalle Valo 	}
492298e50adSKalle Valo 
493298e50adSKalle Valo 	local->fw_ver = local->startup_res.firmware_version[0];
494298e50adSKalle Valo 	local->fw_bld = local->startup_res.firmware_version[1];
495298e50adSKalle Valo 	local->fw_var = local->startup_res.firmware_version[2];
496298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_init firmware version %d.%d\n", local->fw_ver,
497298e50adSKalle Valo 	      local->fw_bld);
498298e50adSKalle Valo 
499298e50adSKalle Valo 	local->tib_length = 0x20;
500298e50adSKalle Valo 	if ((local->fw_ver == 5) && (local->fw_bld >= 30))
501298e50adSKalle Valo 		local->tib_length = local->startup_res.tib_length;
502298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_init tib_length = 0x%02x\n", local->tib_length);
503298e50adSKalle Valo 	/* Initialize CCS's to buffer free state */
504298e50adSKalle Valo 	pccs = ccs_base(local);
505298e50adSKalle Valo 	for (i = 0; i < NUMBER_OF_CCS; i++) {
506298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
507298e50adSKalle Valo 	}
508298e50adSKalle Valo 	init_startup_params(local);
509298e50adSKalle Valo 
510298e50adSKalle Valo 	/* copy mac address to startup parameters */
511298e50adSKalle Valo 	if (!parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) {
512298e50adSKalle Valo 		memcpy(&local->sparm.b4.a_mac_addr,
513298e50adSKalle Valo 		       &local->startup_res.station_addr, ADDRLEN);
514298e50adSKalle Valo 	}
515298e50adSKalle Valo 
516298e50adSKalle Valo 	clear_interrupt(local);	/* Clear any interrupt from the card */
517298e50adSKalle Valo 	local->card_status = CARD_AWAITING_PARAM;
518298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_init ending\n");
519298e50adSKalle Valo 	return 0;
520298e50adSKalle Valo } /* ray_init */
521298e50adSKalle Valo 
522298e50adSKalle Valo /*===========================================================================*/
523298e50adSKalle Valo /* Download startup parameters to the card and command it to read them       */
dl_startup_params(struct net_device * dev)524298e50adSKalle Valo static int dl_startup_params(struct net_device *dev)
525298e50adSKalle Valo {
526298e50adSKalle Valo 	int ccsindex;
527298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
528298e50adSKalle Valo 	struct ccs __iomem *pccs;
529298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
530298e50adSKalle Valo 
531298e50adSKalle Valo 	dev_dbg(&link->dev, "dl_startup_params entered\n");
532298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
533298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs dl_startup_params - device not present\n");
534298e50adSKalle Valo 		return -1;
535298e50adSKalle Valo 	}
536298e50adSKalle Valo 
537298e50adSKalle Valo 	/* Copy parameters to host to ECF area */
538298e50adSKalle Valo 	if (local->fw_ver == 0x55)
539298e50adSKalle Valo 		memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4,
540298e50adSKalle Valo 			    sizeof(struct b4_startup_params));
541298e50adSKalle Valo 	else
542298e50adSKalle Valo 		memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5,
543298e50adSKalle Valo 			    sizeof(struct b5_startup_params));
544298e50adSKalle Valo 
545298e50adSKalle Valo 	/* Fill in the CCS fields for the ECF */
546298e50adSKalle Valo 	if ((ccsindex = get_free_ccs(local)) < 0)
547298e50adSKalle Valo 		return -1;
548298e50adSKalle Valo 	local->dl_param_ccs = ccsindex;
549298e50adSKalle Valo 	pccs = ccs_base(local) + ccsindex;
550298e50adSKalle Valo 	writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd);
551298e50adSKalle Valo 	dev_dbg(&link->dev, "dl_startup_params start ccsindex = %d\n",
552298e50adSKalle Valo 	      local->dl_param_ccs);
553298e50adSKalle Valo 	/* Interrupt the firmware to process the command */
554298e50adSKalle Valo 	if (interrupt_ecf(local, ccsindex)) {
555298e50adSKalle Valo 		printk(KERN_INFO "ray dl_startup_params failed - "
556298e50adSKalle Valo 		       "ECF not ready for intr\n");
557298e50adSKalle Valo 		local->card_status = CARD_DL_PARAM_ERROR;
558298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
559298e50adSKalle Valo 		return -2;
560298e50adSKalle Valo 	}
561298e50adSKalle Valo 	local->card_status = CARD_DL_PARAM;
562298e50adSKalle Valo 	/* Start kernel timer to wait for dl startup to complete. */
563298e50adSKalle Valo 	local->timer.expires = jiffies + HZ / 2;
564298e50adSKalle Valo 	local->timer.function = verify_dl_startup;
565298e50adSKalle Valo 	add_timer(&local->timer);
566298e50adSKalle Valo 	dev_dbg(&link->dev,
567298e50adSKalle Valo 	      "ray_cs dl_startup_params started timer for verify_dl_startup\n");
568298e50adSKalle Valo 	return 0;
569298e50adSKalle Valo } /* dl_startup_params */
570298e50adSKalle Valo 
571298e50adSKalle Valo /*===========================================================================*/
init_startup_params(ray_dev_t * local)572298e50adSKalle Valo static void init_startup_params(ray_dev_t *local)
573298e50adSKalle Valo {
574298e50adSKalle Valo 	int i;
575298e50adSKalle Valo 
576298e50adSKalle Valo 	if (country > JAPAN_TEST)
577298e50adSKalle Valo 		country = USA;
578298e50adSKalle Valo 	else if (country < USA)
579298e50adSKalle Valo 		country = USA;
580298e50adSKalle Valo 	/* structure for hop time and beacon period is defined here using
581298e50adSKalle Valo 	 * New 802.11D6.1 format.  Card firmware is still using old format
582298e50adSKalle Valo 	 * until version 6.
583298e50adSKalle Valo 	 *    Before                    After
584298e50adSKalle Valo 	 *    a_hop_time ms byte        a_hop_time ms byte
585298e50adSKalle Valo 	 *    a_hop_time 2s byte        a_hop_time ls byte
586298e50adSKalle Valo 	 *    a_hop_time ls byte        a_beacon_period ms byte
587298e50adSKalle Valo 	 *    a_beacon_period           a_beacon_period ls byte
588298e50adSKalle Valo 	 *
589298e50adSKalle Valo 	 *    a_hop_time = uS           a_hop_time = KuS
590298e50adSKalle Valo 	 *    a_beacon_period = hops    a_beacon_period = KuS
591298e50adSKalle Valo 	 *//* 64ms = 010000 */
592298e50adSKalle Valo 	if (local->fw_ver == 0x55) {
593298e50adSKalle Valo 		memcpy(&local->sparm.b4, b4_default_startup_parms,
594298e50adSKalle Valo 		       sizeof(struct b4_startup_params));
595298e50adSKalle Valo 		/* Translate sane kus input values to old build 4/5 format */
596298e50adSKalle Valo 		/* i = hop time in uS truncated to 3 bytes */
597298e50adSKalle Valo 		i = (hop_dwell * 1024) & 0xffffff;
598298e50adSKalle Valo 		local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff;
599298e50adSKalle Valo 		local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff;
600298e50adSKalle Valo 		local->sparm.b4.a_beacon_period[0] = 0;
601298e50adSKalle Valo 		local->sparm.b4.a_beacon_period[1] =
602298e50adSKalle Valo 		    ((beacon_period / hop_dwell) - 1) & 0xff;
603298e50adSKalle Valo 		local->sparm.b4.a_curr_country_code = country;
604298e50adSKalle Valo 		local->sparm.b4.a_hop_pattern_length =
605298e50adSKalle Valo 		    hop_pattern_length[(int)country] - 1;
606298e50adSKalle Valo 		if (bc) {
607298e50adSKalle Valo 			local->sparm.b4.a_ack_timeout = 0x50;
608298e50adSKalle Valo 			local->sparm.b4.a_sifs = 0x3f;
609298e50adSKalle Valo 		}
610298e50adSKalle Valo 	} else { /* Version 5 uses real kus values */
611298e50adSKalle Valo 		memcpy((UCHAR *) &local->sparm.b5, b5_default_startup_parms,
612298e50adSKalle Valo 		       sizeof(struct b5_startup_params));
613298e50adSKalle Valo 
614298e50adSKalle Valo 		local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff;
615298e50adSKalle Valo 		local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff;
616298e50adSKalle Valo 		local->sparm.b5.a_beacon_period[0] =
617298e50adSKalle Valo 		    (beacon_period >> 8) & 0xff;
618298e50adSKalle Valo 		local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff;
619298e50adSKalle Valo 		if (psm)
620298e50adSKalle Valo 			local->sparm.b5.a_power_mgt_state = 1;
621298e50adSKalle Valo 		local->sparm.b5.a_curr_country_code = country;
622298e50adSKalle Valo 		local->sparm.b5.a_hop_pattern_length =
623298e50adSKalle Valo 		    hop_pattern_length[(int)country];
624298e50adSKalle Valo 	}
625298e50adSKalle Valo 
626298e50adSKalle Valo 	local->sparm.b4.a_network_type = net_type & 0x01;
627298e50adSKalle Valo 	local->sparm.b4.a_acting_as_ap_status = TYPE_STA;
628298e50adSKalle Valo 
629298e50adSKalle Valo 	if (essid != NULL)
630*707a13c7SKalle Valo 		strscpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE);
631298e50adSKalle Valo } /* init_startup_params */
632298e50adSKalle Valo 
633298e50adSKalle Valo /*===========================================================================*/
verify_dl_startup(struct timer_list * t)634298e50adSKalle Valo static void verify_dl_startup(struct timer_list *t)
635298e50adSKalle Valo {
636298e50adSKalle Valo 	ray_dev_t *local = from_timer(local, t, timer);
637298e50adSKalle Valo 	struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs;
638298e50adSKalle Valo 	UCHAR status;
639298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
640298e50adSKalle Valo 
641298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
642298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs verify_dl_startup - device not present\n");
643298e50adSKalle Valo 		return;
644298e50adSKalle Valo 	}
645298e50adSKalle Valo #if 0
646298e50adSKalle Valo 	{
647298e50adSKalle Valo 		int i;
648298e50adSKalle Valo 		printk(KERN_DEBUG
649298e50adSKalle Valo 		       "verify_dl_startup parameters sent via ccs %d:\n",
650298e50adSKalle Valo 		       local->dl_param_ccs);
651298e50adSKalle Valo 		for (i = 0; i < sizeof(struct b5_startup_params); i++) {
652298e50adSKalle Valo 			printk(" %2x",
653298e50adSKalle Valo 			       (unsigned int)readb(local->sram +
654298e50adSKalle Valo 						   HOST_TO_ECF_BASE + i));
655298e50adSKalle Valo 		}
656298e50adSKalle Valo 		printk("\n");
657298e50adSKalle Valo 	}
658298e50adSKalle Valo #endif
659298e50adSKalle Valo 
660298e50adSKalle Valo 	status = readb(&pccs->buffer_status);
661298e50adSKalle Valo 	if (status != CCS_BUFFER_FREE) {
662298e50adSKalle Valo 		printk(KERN_INFO
663298e50adSKalle Valo 		       "Download startup params failed.  Status = %d\n",
664298e50adSKalle Valo 		       status);
665298e50adSKalle Valo 		local->card_status = CARD_DL_PARAM_ERROR;
666298e50adSKalle Valo 		return;
667298e50adSKalle Valo 	}
668298e50adSKalle Valo 	if (local->sparm.b4.a_network_type == ADHOC)
669298e50adSKalle Valo 		start_net(&local->timer);
670298e50adSKalle Valo 	else
671298e50adSKalle Valo 		join_net(&local->timer);
672298e50adSKalle Valo } /* end verify_dl_startup */
673298e50adSKalle Valo 
674298e50adSKalle Valo /*===========================================================================*/
675298e50adSKalle Valo /* Command card to start a network */
start_net(struct timer_list * t)676298e50adSKalle Valo static void start_net(struct timer_list *t)
677298e50adSKalle Valo {
678298e50adSKalle Valo 	ray_dev_t *local = from_timer(local, t, timer);
679298e50adSKalle Valo 	struct ccs __iomem *pccs;
680298e50adSKalle Valo 	int ccsindex;
681298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
682298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
683298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs start_net - device not present\n");
684298e50adSKalle Valo 		return;
685298e50adSKalle Valo 	}
686298e50adSKalle Valo 	/* Fill in the CCS fields for the ECF */
687298e50adSKalle Valo 	if ((ccsindex = get_free_ccs(local)) < 0)
688298e50adSKalle Valo 		return;
689298e50adSKalle Valo 	pccs = ccs_base(local) + ccsindex;
690298e50adSKalle Valo 	writeb(CCS_START_NETWORK, &pccs->cmd);
691298e50adSKalle Valo 	writeb(0, &pccs->var.start_network.update_param);
692298e50adSKalle Valo 	/* Interrupt the firmware to process the command */
693298e50adSKalle Valo 	if (interrupt_ecf(local, ccsindex)) {
694298e50adSKalle Valo 		dev_dbg(&link->dev, "ray start net failed - card not ready for intr\n");
695298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
696298e50adSKalle Valo 		return;
697298e50adSKalle Valo 	}
698298e50adSKalle Valo 	local->card_status = CARD_DOING_ACQ;
699298e50adSKalle Valo } /* end start_net */
700298e50adSKalle Valo 
701298e50adSKalle Valo /*===========================================================================*/
702298e50adSKalle Valo /* Command card to join a network */
join_net(struct timer_list * t)703298e50adSKalle Valo static void join_net(struct timer_list *t)
704298e50adSKalle Valo {
705298e50adSKalle Valo 	ray_dev_t *local = from_timer(local, t, timer);
706298e50adSKalle Valo 
707298e50adSKalle Valo 	struct ccs __iomem *pccs;
708298e50adSKalle Valo 	int ccsindex;
709298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
710298e50adSKalle Valo 
711298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
712298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs join_net - device not present\n");
713298e50adSKalle Valo 		return;
714298e50adSKalle Valo 	}
715298e50adSKalle Valo 	/* Fill in the CCS fields for the ECF */
716298e50adSKalle Valo 	if ((ccsindex = get_free_ccs(local)) < 0)
717298e50adSKalle Valo 		return;
718298e50adSKalle Valo 	pccs = ccs_base(local) + ccsindex;
719298e50adSKalle Valo 	writeb(CCS_JOIN_NETWORK, &pccs->cmd);
720298e50adSKalle Valo 	writeb(0, &pccs->var.join_network.update_param);
721298e50adSKalle Valo 	writeb(0, &pccs->var.join_network.net_initiated);
722298e50adSKalle Valo 	/* Interrupt the firmware to process the command */
723298e50adSKalle Valo 	if (interrupt_ecf(local, ccsindex)) {
724298e50adSKalle Valo 		dev_dbg(&link->dev, "ray join net failed - card not ready for intr\n");
725298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
726298e50adSKalle Valo 		return;
727298e50adSKalle Valo 	}
728298e50adSKalle Valo 	local->card_status = CARD_DOING_ACQ;
729298e50adSKalle Valo }
730298e50adSKalle Valo 
731298e50adSKalle Valo 
ray_release(struct pcmcia_device * link)732298e50adSKalle Valo static void ray_release(struct pcmcia_device *link)
733298e50adSKalle Valo {
734298e50adSKalle Valo 	struct net_device *dev = link->priv;
735298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
736298e50adSKalle Valo 
737298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_release\n");
738298e50adSKalle Valo 
739daef0205SDongliang Mu 	del_timer_sync(&local->timer);
740298e50adSKalle Valo 
741072210c7SDongliang Mu 	if (local->sram)
742298e50adSKalle Valo 		iounmap(local->sram);
743072210c7SDongliang Mu 	if (local->rmem)
744298e50adSKalle Valo 		iounmap(local->rmem);
745072210c7SDongliang Mu 	if (local->amem)
746298e50adSKalle Valo 		iounmap(local->amem);
747298e50adSKalle Valo 	pcmcia_disable_device(link);
748298e50adSKalle Valo 
749298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_release ending\n");
750298e50adSKalle Valo }
751298e50adSKalle Valo 
ray_suspend(struct pcmcia_device * link)752298e50adSKalle Valo static int ray_suspend(struct pcmcia_device *link)
753298e50adSKalle Valo {
754298e50adSKalle Valo 	struct net_device *dev = link->priv;
755298e50adSKalle Valo 
756298e50adSKalle Valo 	if (link->open)
757298e50adSKalle Valo 		netif_device_detach(dev);
758298e50adSKalle Valo 
759298e50adSKalle Valo 	return 0;
760298e50adSKalle Valo }
761298e50adSKalle Valo 
ray_resume(struct pcmcia_device * link)762298e50adSKalle Valo static int ray_resume(struct pcmcia_device *link)
763298e50adSKalle Valo {
764298e50adSKalle Valo 	struct net_device *dev = link->priv;
765298e50adSKalle Valo 
766298e50adSKalle Valo 	if (link->open) {
767298e50adSKalle Valo 		ray_reset(dev);
768298e50adSKalle Valo 		netif_device_attach(dev);
769298e50adSKalle Valo 	}
770298e50adSKalle Valo 
771298e50adSKalle Valo 	return 0;
772298e50adSKalle Valo }
773298e50adSKalle Valo 
774298e50adSKalle Valo /*===========================================================================*/
ray_dev_init(struct net_device * dev)775298e50adSKalle Valo static int ray_dev_init(struct net_device *dev)
776298e50adSKalle Valo {
777298e50adSKalle Valo #ifdef RAY_IMMEDIATE_INIT
778298e50adSKalle Valo 	int i;
779298e50adSKalle Valo #endif /* RAY_IMMEDIATE_INIT */
780298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
781298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
782298e50adSKalle Valo 
783298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_dev_init(dev=%p)\n", dev);
784298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
785298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_dev_init - device not present\n");
786298e50adSKalle Valo 		return -1;
787298e50adSKalle Valo 	}
788298e50adSKalle Valo #ifdef RAY_IMMEDIATE_INIT
789298e50adSKalle Valo 	/* Download startup parameters */
790298e50adSKalle Valo 	if ((i = dl_startup_params(dev)) < 0) {
791298e50adSKalle Valo 		printk(KERN_INFO "ray_dev_init dl_startup_params failed - "
792298e50adSKalle Valo 		       "returns 0x%x\n", i);
793298e50adSKalle Valo 		return -1;
794298e50adSKalle Valo 	}
795298e50adSKalle Valo #else /* RAY_IMMEDIATE_INIT */
796298e50adSKalle Valo 	/* Postpone the card init so that we can still configure the card,
797298e50adSKalle Valo 	 * for example using the Wireless Extensions. The init will happen
798298e50adSKalle Valo 	 * in ray_open() - Jean II */
799298e50adSKalle Valo 	dev_dbg(&link->dev,
800298e50adSKalle Valo 	      "ray_dev_init: postponing card init to ray_open() ; Status = %d\n",
801298e50adSKalle Valo 	      local->card_status);
802298e50adSKalle Valo #endif /* RAY_IMMEDIATE_INIT */
803298e50adSKalle Valo 
804298e50adSKalle Valo 	/* copy mac and broadcast addresses to linux device */
805298e50adSKalle Valo 	eth_hw_addr_set(dev, local->sparm.b4.a_mac_addr);
806298e50adSKalle Valo 	eth_broadcast_addr(dev->broadcast);
807298e50adSKalle Valo 
808298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_dev_init ending\n");
809298e50adSKalle Valo 	return 0;
810298e50adSKalle Valo }
811298e50adSKalle Valo 
812298e50adSKalle Valo /*===========================================================================*/
ray_dev_config(struct net_device * dev,struct ifmap * map)813298e50adSKalle Valo static int ray_dev_config(struct net_device *dev, struct ifmap *map)
814298e50adSKalle Valo {
815298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
816298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
817298e50adSKalle Valo 	/* Dummy routine to satisfy device structure */
818298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_dev_config(dev=%p,ifmap=%p)\n", dev, map);
819298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
820298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_dev_config - device not present\n");
821298e50adSKalle Valo 		return -1;
822298e50adSKalle Valo 	}
823298e50adSKalle Valo 
824298e50adSKalle Valo 	return 0;
825298e50adSKalle Valo }
826298e50adSKalle Valo 
827298e50adSKalle Valo /*===========================================================================*/
ray_dev_start_xmit(struct sk_buff * skb,struct net_device * dev)828298e50adSKalle Valo static netdev_tx_t ray_dev_start_xmit(struct sk_buff *skb,
829298e50adSKalle Valo 					    struct net_device *dev)
830298e50adSKalle Valo {
831298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
832298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
833298e50adSKalle Valo 	short length = skb->len;
834298e50adSKalle Valo 
835298e50adSKalle Valo 	if (!pcmcia_dev_present(link)) {
836298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_dev_start_xmit - device not present\n");
837298e50adSKalle Valo 		dev_kfree_skb(skb);
838298e50adSKalle Valo 		return NETDEV_TX_OK;
839298e50adSKalle Valo 	}
840298e50adSKalle Valo 
841298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev);
842298e50adSKalle Valo 	if (local->authentication_state == NEED_TO_AUTH) {
843298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs Sending authentication request.\n");
844298e50adSKalle Valo 		if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) {
845298e50adSKalle Valo 			local->authentication_state = AUTHENTICATED;
846298e50adSKalle Valo 			netif_stop_queue(dev);
847298e50adSKalle Valo 			return NETDEV_TX_BUSY;
848298e50adSKalle Valo 		}
849298e50adSKalle Valo 	}
850298e50adSKalle Valo 
851298e50adSKalle Valo 	if (length < ETH_ZLEN) {
852298e50adSKalle Valo 		if (skb_padto(skb, ETH_ZLEN))
853298e50adSKalle Valo 			return NETDEV_TX_OK;
854298e50adSKalle Valo 		length = ETH_ZLEN;
855298e50adSKalle Valo 	}
856298e50adSKalle Valo 	switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) {
857298e50adSKalle Valo 	case XMIT_NO_CCS:
858298e50adSKalle Valo 	case XMIT_NEED_AUTH:
859298e50adSKalle Valo 		netif_stop_queue(dev);
860298e50adSKalle Valo 		return NETDEV_TX_BUSY;
861298e50adSKalle Valo 	case XMIT_NO_INTR:
862298e50adSKalle Valo 	case XMIT_MSG_BAD:
863298e50adSKalle Valo 	case XMIT_OK:
864298e50adSKalle Valo 	default:
865298e50adSKalle Valo 		dev_kfree_skb(skb);
866298e50adSKalle Valo 	}
867298e50adSKalle Valo 
868298e50adSKalle Valo 	return NETDEV_TX_OK;
869298e50adSKalle Valo } /* ray_dev_start_xmit */
870298e50adSKalle Valo 
871298e50adSKalle Valo /*===========================================================================*/
ray_hw_xmit(unsigned char * data,int len,struct net_device * dev,UCHAR msg_type)872298e50adSKalle Valo static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev,
873298e50adSKalle Valo 		       UCHAR msg_type)
874298e50adSKalle Valo {
875298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
876298e50adSKalle Valo 	struct ccs __iomem *pccs;
877298e50adSKalle Valo 	int ccsindex;
878298e50adSKalle Valo 	int offset;
879298e50adSKalle Valo 	struct tx_msg __iomem *ptx;	/* Address of xmit buffer in PC space */
880298e50adSKalle Valo 	short int addr;		/* Address of xmit buffer in card space */
881298e50adSKalle Valo 
882298e50adSKalle Valo 	pr_debug("ray_hw_xmit(data=%p, len=%d, dev=%p)\n", data, len, dev);
883298e50adSKalle Valo 	if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) {
884298e50adSKalle Valo 		printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",
885298e50adSKalle Valo 		       len);
886298e50adSKalle Valo 		return XMIT_MSG_BAD;
887298e50adSKalle Valo 	}
888298e50adSKalle Valo 	switch (ccsindex = get_free_tx_ccs(local)) {
889298e50adSKalle Valo 	case ECCSBUSY:
890298e50adSKalle Valo 		pr_debug("ray_hw_xmit tx_ccs table busy\n");
891298e50adSKalle Valo 		fallthrough;
892298e50adSKalle Valo 	case ECCSFULL:
893298e50adSKalle Valo 		pr_debug("ray_hw_xmit No free tx ccs\n");
894298e50adSKalle Valo 		fallthrough;
895298e50adSKalle Valo 	case ECARDGONE:
896298e50adSKalle Valo 		netif_stop_queue(dev);
897298e50adSKalle Valo 		return XMIT_NO_CCS;
898298e50adSKalle Valo 	default:
899298e50adSKalle Valo 		break;
900298e50adSKalle Valo 	}
901298e50adSKalle Valo 	addr = TX_BUF_BASE + (ccsindex << 11);
902298e50adSKalle Valo 
903298e50adSKalle Valo 	if (msg_type == DATA_TYPE) {
904298e50adSKalle Valo 		local->stats.tx_bytes += len;
905298e50adSKalle Valo 		local->stats.tx_packets++;
906298e50adSKalle Valo 	}
907298e50adSKalle Valo 
908298e50adSKalle Valo 	ptx = local->sram + addr;
909298e50adSKalle Valo 
910298e50adSKalle Valo 	ray_build_header(local, ptx, msg_type, data);
911298e50adSKalle Valo 	if (translate) {
912298e50adSKalle Valo 		offset = translate_frame(local, ptx, data, len);
913298e50adSKalle Valo 	} else { /* Encapsulate frame */
914298e50adSKalle Valo 		/* TBD TIB length will move address of ptx->var */
915298e50adSKalle Valo 		memcpy_toio(&ptx->var, data, len);
916298e50adSKalle Valo 		offset = 0;
917298e50adSKalle Valo 	}
918298e50adSKalle Valo 
919298e50adSKalle Valo 	/* fill in the CCS */
920298e50adSKalle Valo 	pccs = ccs_base(local) + ccsindex;
921298e50adSKalle Valo 	len += TX_HEADER_LENGTH + offset;
922298e50adSKalle Valo 	writeb(CCS_TX_REQUEST, &pccs->cmd);
923298e50adSKalle Valo 	writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]);
924298e50adSKalle Valo 	writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]);
925298e50adSKalle Valo 	writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]);
926298e50adSKalle Valo 	writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]);
927298e50adSKalle Valo /* TBD still need psm_cam? */
928298e50adSKalle Valo 	writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode);
929298e50adSKalle Valo 	writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate);
930298e50adSKalle Valo 	writeb(0, &pccs->var.tx_request.antenna);
931298e50adSKalle Valo 	pr_debug("ray_hw_xmit default_tx_rate = 0x%x\n",
932298e50adSKalle Valo 	      local->net_default_tx_rate);
933298e50adSKalle Valo 
934298e50adSKalle Valo 	/* Interrupt the firmware to process the command */
935298e50adSKalle Valo 	if (interrupt_ecf(local, ccsindex)) {
936298e50adSKalle Valo 		pr_debug("ray_hw_xmit failed - ECF not ready for intr\n");
937298e50adSKalle Valo /* TBD very inefficient to copy packet to buffer, and then not
938298e50adSKalle Valo    send it, but the alternative is to queue the messages and that
939298e50adSKalle Valo    won't be done for a while.  Maybe set tbusy until a CCS is free?
940298e50adSKalle Valo */
941298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
942298e50adSKalle Valo 		return XMIT_NO_INTR;
943298e50adSKalle Valo 	}
944298e50adSKalle Valo 	return XMIT_OK;
945298e50adSKalle Valo } /* end ray_hw_xmit */
946298e50adSKalle Valo 
947298e50adSKalle Valo /*===========================================================================*/
translate_frame(ray_dev_t * local,struct tx_msg __iomem * ptx,unsigned char * data,int len)948298e50adSKalle Valo static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
949298e50adSKalle Valo 			   unsigned char *data, int len)
950298e50adSKalle Valo {
951298e50adSKalle Valo 	__be16 proto = ((struct ethhdr *)data)->h_proto;
952298e50adSKalle Valo 	if (ntohs(proto) >= ETH_P_802_3_MIN) { /* DIX II ethernet frame */
953298e50adSKalle Valo 		pr_debug("ray_cs translate_frame DIX II\n");
954298e50adSKalle Valo 		/* Copy LLC header to card buffer */
955298e50adSKalle Valo 		memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc));
956298e50adSKalle Valo 		memcpy_toio(((void __iomem *)&ptx->var) + sizeof(eth2_llc),
957298e50adSKalle Valo 			    (UCHAR *) &proto, 2);
958298e50adSKalle Valo 		if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) {
959298e50adSKalle Valo 			/* This is the selective translation table, only 2 entries */
960298e50adSKalle Valo 			writeb(0xf8,
961298e50adSKalle Valo 			       &((struct snaphdr_t __iomem *)ptx->var)->org[2]);
962298e50adSKalle Valo 		}
963298e50adSKalle Valo 		/* Copy body of ethernet packet without ethernet header */
964298e50adSKalle Valo 		memcpy_toio((void __iomem *)&ptx->var +
965298e50adSKalle Valo 			    sizeof(struct snaphdr_t), data + ETH_HLEN,
966298e50adSKalle Valo 			    len - ETH_HLEN);
967298e50adSKalle Valo 		return (int)sizeof(struct snaphdr_t) - ETH_HLEN;
968298e50adSKalle Valo 	} else { /* already  802 type, and proto is length */
969298e50adSKalle Valo 		pr_debug("ray_cs translate_frame 802\n");
970298e50adSKalle Valo 		if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */
971298e50adSKalle Valo 			pr_debug("ray_cs translate_frame evil IPX\n");
972298e50adSKalle Valo 			memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN);
973298e50adSKalle Valo 			return 0 - ETH_HLEN;
974298e50adSKalle Valo 		}
975298e50adSKalle Valo 		memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN);
976298e50adSKalle Valo 		return 0 - ETH_HLEN;
977298e50adSKalle Valo 	}
978298e50adSKalle Valo 	/* TBD do other frame types */
979298e50adSKalle Valo } /* end translate_frame */
980298e50adSKalle Valo 
981298e50adSKalle Valo /*===========================================================================*/
ray_build_header(ray_dev_t * local,struct tx_msg __iomem * ptx,UCHAR msg_type,unsigned char * data)982298e50adSKalle Valo static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx,
983298e50adSKalle Valo 			     UCHAR msg_type, unsigned char *data)
984298e50adSKalle Valo {
985298e50adSKalle Valo 	writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1);
986298e50adSKalle Valo /*** IEEE 802.11 Address field assignments *************
987298e50adSKalle Valo 		TODS	FROMDS	addr_1		addr_2		addr_3	addr_4
988298e50adSKalle Valo Adhoc		0	0	dest		src (terminal)	BSSID	N/A
989298e50adSKalle Valo AP to Terminal	0	1	dest		AP(BSSID)	source	N/A
990298e50adSKalle Valo Terminal to AP	1	0	AP(BSSID)	src (terminal)	dest	N/A
991298e50adSKalle Valo AP to AP	1	1	dest AP		src AP		dest	source
992298e50adSKalle Valo *******************************************************/
993298e50adSKalle Valo 	if (local->net_type == ADHOC) {
994298e50adSKalle Valo 		writeb(0, &ptx->mac.frame_ctl_2);
995298e50adSKalle Valo 		memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest,
996298e50adSKalle Valo 			    ADDRLEN);
997298e50adSKalle Valo 		memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source,
998298e50adSKalle Valo 			    ADDRLEN);
999298e50adSKalle Valo 		memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
1000298e50adSKalle Valo 	} else { /* infrastructure */
1001298e50adSKalle Valo 
1002298e50adSKalle Valo 		if (local->sparm.b4.a_acting_as_ap_status) {
1003298e50adSKalle Valo 			writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2);
1004298e50adSKalle Valo 			memcpy_toio(ptx->mac.addr_1,
1005298e50adSKalle Valo 				    ((struct ethhdr *)data)->h_dest, ADDRLEN);
1006298e50adSKalle Valo 			memcpy_toio(ptx->mac.addr_2, local->bss_id, 6);
1007298e50adSKalle Valo 			memcpy_toio(ptx->mac.addr_3,
1008298e50adSKalle Valo 				    ((struct ethhdr *)data)->h_source, ADDRLEN);
1009298e50adSKalle Valo 		} else { /* Terminal */
1010298e50adSKalle Valo 
1011298e50adSKalle Valo 			writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2);
1012298e50adSKalle Valo 			memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN);
1013298e50adSKalle Valo 			memcpy_toio(ptx->mac.addr_2,
1014298e50adSKalle Valo 				    ((struct ethhdr *)data)->h_source, ADDRLEN);
1015298e50adSKalle Valo 			memcpy_toio(ptx->mac.addr_3,
1016298e50adSKalle Valo 				    ((struct ethhdr *)data)->h_dest, ADDRLEN);
1017298e50adSKalle Valo 		}
1018298e50adSKalle Valo 	}
1019298e50adSKalle Valo } /* end encapsulate_frame */
1020298e50adSKalle Valo 
1021298e50adSKalle Valo /*====================================================================*/
1022298e50adSKalle Valo 
1023298e50adSKalle Valo /*------------------------------------------------------------------*/
1024298e50adSKalle Valo /*
1025298e50adSKalle Valo  * Wireless Handler : get protocol name
1026298e50adSKalle Valo  */
ray_get_name(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1027298e50adSKalle Valo static int ray_get_name(struct net_device *dev, struct iw_request_info *info,
1028298e50adSKalle Valo 			union iwreq_data *wrqu, char *extra)
1029298e50adSKalle Valo {
1030298e50adSKalle Valo 	strcpy(wrqu->name, "IEEE 802.11-FH");
1031298e50adSKalle Valo 	return 0;
1032298e50adSKalle Valo }
1033298e50adSKalle Valo 
1034298e50adSKalle Valo /*------------------------------------------------------------------*/
1035298e50adSKalle Valo /*
1036298e50adSKalle Valo  * Wireless Handler : set frequency
1037298e50adSKalle Valo  */
ray_set_freq(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1038298e50adSKalle Valo static int ray_set_freq(struct net_device *dev, struct iw_request_info *info,
1039298e50adSKalle Valo 			union iwreq_data *wrqu, char *extra)
1040298e50adSKalle Valo {
1041298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1042298e50adSKalle Valo 	int err = -EINPROGRESS;	/* Call commit handler */
1043298e50adSKalle Valo 
1044298e50adSKalle Valo 	/* Reject if card is already initialised */
1045298e50adSKalle Valo 	if (local->card_status != CARD_AWAITING_PARAM)
1046298e50adSKalle Valo 		return -EBUSY;
1047298e50adSKalle Valo 
1048298e50adSKalle Valo 	/* Setting by channel number */
1049298e50adSKalle Valo 	if ((wrqu->freq.m > USA_HOP_MOD) || (wrqu->freq.e > 0))
1050298e50adSKalle Valo 		err = -EOPNOTSUPP;
1051298e50adSKalle Valo 	else
1052298e50adSKalle Valo 		local->sparm.b5.a_hop_pattern = wrqu->freq.m;
1053298e50adSKalle Valo 
1054298e50adSKalle Valo 	return err;
1055298e50adSKalle Valo }
1056298e50adSKalle Valo 
1057298e50adSKalle Valo /*------------------------------------------------------------------*/
1058298e50adSKalle Valo /*
1059298e50adSKalle Valo  * Wireless Handler : get frequency
1060298e50adSKalle Valo  */
ray_get_freq(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1061298e50adSKalle Valo static int ray_get_freq(struct net_device *dev, struct iw_request_info *info,
1062298e50adSKalle Valo 			union iwreq_data *wrqu, char *extra)
1063298e50adSKalle Valo {
1064298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1065298e50adSKalle Valo 
1066298e50adSKalle Valo 	wrqu->freq.m = local->sparm.b5.a_hop_pattern;
1067298e50adSKalle Valo 	wrqu->freq.e = 0;
1068298e50adSKalle Valo 	return 0;
1069298e50adSKalle Valo }
1070298e50adSKalle Valo 
1071298e50adSKalle Valo /*------------------------------------------------------------------*/
1072298e50adSKalle Valo /*
1073298e50adSKalle Valo  * Wireless Handler : set ESSID
1074298e50adSKalle Valo  */
ray_set_essid(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1075298e50adSKalle Valo static int ray_set_essid(struct net_device *dev, struct iw_request_info *info,
1076298e50adSKalle Valo 			 union iwreq_data *wrqu, char *extra)
1077298e50adSKalle Valo {
1078298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1079298e50adSKalle Valo 
1080298e50adSKalle Valo 	/* Reject if card is already initialised */
1081298e50adSKalle Valo 	if (local->card_status != CARD_AWAITING_PARAM)
1082298e50adSKalle Valo 		return -EBUSY;
1083298e50adSKalle Valo 
1084298e50adSKalle Valo 	/* Check if we asked for `any' */
1085298e50adSKalle Valo 	if (wrqu->essid.flags == 0)
1086298e50adSKalle Valo 		/* Corey : can you do that ? */
1087298e50adSKalle Valo 		return -EOPNOTSUPP;
1088298e50adSKalle Valo 
1089298e50adSKalle Valo 	/* Check the size of the string */
1090298e50adSKalle Valo 	if (wrqu->essid.length > IW_ESSID_MAX_SIZE)
1091298e50adSKalle Valo 		return -E2BIG;
1092298e50adSKalle Valo 
1093298e50adSKalle Valo 	/* Set the ESSID in the card */
1094298e50adSKalle Valo 	memset(local->sparm.b5.a_current_ess_id, 0, IW_ESSID_MAX_SIZE);
1095298e50adSKalle Valo 	memcpy(local->sparm.b5.a_current_ess_id, extra, wrqu->essid.length);
1096298e50adSKalle Valo 
1097298e50adSKalle Valo 	return -EINPROGRESS;	/* Call commit handler */
1098298e50adSKalle Valo }
1099298e50adSKalle Valo 
1100298e50adSKalle Valo /*------------------------------------------------------------------*/
1101298e50adSKalle Valo /*
1102298e50adSKalle Valo  * Wireless Handler : get ESSID
1103298e50adSKalle Valo  */
ray_get_essid(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1104298e50adSKalle Valo static int ray_get_essid(struct net_device *dev, struct iw_request_info *info,
1105298e50adSKalle Valo 			 union iwreq_data *wrqu, char *extra)
1106298e50adSKalle Valo {
1107298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1108298e50adSKalle Valo 	UCHAR tmp[IW_ESSID_MAX_SIZE + 1];
1109298e50adSKalle Valo 
1110298e50adSKalle Valo 	/* Get the essid that was set */
1111298e50adSKalle Valo 	memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
1112298e50adSKalle Valo 	memcpy(tmp, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
1113298e50adSKalle Valo 	tmp[IW_ESSID_MAX_SIZE] = '\0';
1114298e50adSKalle Valo 
1115298e50adSKalle Valo 	/* Push it out ! */
1116298e50adSKalle Valo 	wrqu->essid.length = strlen(tmp);
1117298e50adSKalle Valo 	wrqu->essid.flags = 1;	/* active */
1118298e50adSKalle Valo 
1119298e50adSKalle Valo 	return 0;
1120298e50adSKalle Valo }
1121298e50adSKalle Valo 
1122298e50adSKalle Valo /*------------------------------------------------------------------*/
1123298e50adSKalle Valo /*
1124298e50adSKalle Valo  * Wireless Handler : get AP address
1125298e50adSKalle Valo  */
ray_get_wap(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1126298e50adSKalle Valo static int ray_get_wap(struct net_device *dev, struct iw_request_info *info,
1127298e50adSKalle Valo 		       union iwreq_data *wrqu, char *extra)
1128298e50adSKalle Valo {
1129298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1130298e50adSKalle Valo 
1131298e50adSKalle Valo 	memcpy(wrqu->ap_addr.sa_data, local->bss_id, ETH_ALEN);
1132298e50adSKalle Valo 	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
1133298e50adSKalle Valo 
1134298e50adSKalle Valo 	return 0;
1135298e50adSKalle Valo }
1136298e50adSKalle Valo 
1137298e50adSKalle Valo /*------------------------------------------------------------------*/
1138298e50adSKalle Valo /*
1139298e50adSKalle Valo  * Wireless Handler : set Bit-Rate
1140298e50adSKalle Valo  */
ray_set_rate(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1141298e50adSKalle Valo static int ray_set_rate(struct net_device *dev, struct iw_request_info *info,
1142298e50adSKalle Valo 			union iwreq_data *wrqu, char *extra)
1143298e50adSKalle Valo {
1144298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1145298e50adSKalle Valo 
1146298e50adSKalle Valo 	/* Reject if card is already initialised */
1147298e50adSKalle Valo 	if (local->card_status != CARD_AWAITING_PARAM)
1148298e50adSKalle Valo 		return -EBUSY;
1149298e50adSKalle Valo 
1150298e50adSKalle Valo 	/* Check if rate is in range */
1151298e50adSKalle Valo 	if ((wrqu->bitrate.value != 1000000) && (wrqu->bitrate.value != 2000000))
1152298e50adSKalle Valo 		return -EINVAL;
1153298e50adSKalle Valo 
1154298e50adSKalle Valo 	/* Hack for 1.5 Mb/s instead of 2 Mb/s */
1155298e50adSKalle Valo 	if ((local->fw_ver == 0x55) &&	/* Please check */
1156298e50adSKalle Valo 	    (wrqu->bitrate.value == 2000000))
1157298e50adSKalle Valo 		local->net_default_tx_rate = 3;
1158298e50adSKalle Valo 	else
1159298e50adSKalle Valo 		local->net_default_tx_rate = wrqu->bitrate.value / 500000;
1160298e50adSKalle Valo 
1161298e50adSKalle Valo 	return 0;
1162298e50adSKalle Valo }
1163298e50adSKalle Valo 
1164298e50adSKalle Valo /*------------------------------------------------------------------*/
1165298e50adSKalle Valo /*
1166298e50adSKalle Valo  * Wireless Handler : get Bit-Rate
1167298e50adSKalle Valo  */
ray_get_rate(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1168298e50adSKalle Valo static int ray_get_rate(struct net_device *dev, struct iw_request_info *info,
1169298e50adSKalle Valo 			union iwreq_data *wrqu, char *extra)
1170298e50adSKalle Valo {
1171298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1172298e50adSKalle Valo 
1173298e50adSKalle Valo 	if (local->net_default_tx_rate == 3)
1174298e50adSKalle Valo 		wrqu->bitrate.value = 2000000;	/* Hum... */
1175298e50adSKalle Valo 	else
1176298e50adSKalle Valo 		wrqu->bitrate.value = local->net_default_tx_rate * 500000;
1177298e50adSKalle Valo 	wrqu->bitrate.fixed = 0;	/* We are in auto mode */
1178298e50adSKalle Valo 
1179298e50adSKalle Valo 	return 0;
1180298e50adSKalle Valo }
1181298e50adSKalle Valo 
1182298e50adSKalle Valo /*------------------------------------------------------------------*/
1183298e50adSKalle Valo /*
1184298e50adSKalle Valo  * Wireless Handler : set RTS threshold
1185298e50adSKalle Valo  */
ray_set_rts(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1186298e50adSKalle Valo static int ray_set_rts(struct net_device *dev, struct iw_request_info *info,
1187298e50adSKalle Valo 		       union iwreq_data *wrqu, char *extra)
1188298e50adSKalle Valo {
1189298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1190298e50adSKalle Valo 	int rthr = wrqu->rts.value;
1191298e50adSKalle Valo 
1192298e50adSKalle Valo 	/* Reject if card is already initialised */
1193298e50adSKalle Valo 	if (local->card_status != CARD_AWAITING_PARAM)
1194298e50adSKalle Valo 		return -EBUSY;
1195298e50adSKalle Valo 
1196298e50adSKalle Valo 	/* if(wrq->u.rts.fixed == 0) we should complain */
1197298e50adSKalle Valo 	if (wrqu->rts.disabled)
1198298e50adSKalle Valo 		rthr = 32767;
1199298e50adSKalle Valo 	else {
1200298e50adSKalle Valo 		if ((rthr < 0) || (rthr > 2347))   /* What's the max packet size ??? */
1201298e50adSKalle Valo 			return -EINVAL;
1202298e50adSKalle Valo 	}
1203298e50adSKalle Valo 	local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF;
1204298e50adSKalle Valo 	local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF;
1205298e50adSKalle Valo 
1206298e50adSKalle Valo 	return -EINPROGRESS;	/* Call commit handler */
1207298e50adSKalle Valo }
1208298e50adSKalle Valo 
1209298e50adSKalle Valo /*------------------------------------------------------------------*/
1210298e50adSKalle Valo /*
1211298e50adSKalle Valo  * Wireless Handler : get RTS threshold
1212298e50adSKalle Valo  */
ray_get_rts(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1213298e50adSKalle Valo static int ray_get_rts(struct net_device *dev, struct iw_request_info *info,
1214298e50adSKalle Valo 		       union iwreq_data *wrqu, char *extra)
1215298e50adSKalle Valo {
1216298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1217298e50adSKalle Valo 
1218298e50adSKalle Valo 	wrqu->rts.value = (local->sparm.b5.a_rts_threshold[0] << 8)
1219298e50adSKalle Valo 	    + local->sparm.b5.a_rts_threshold[1];
1220298e50adSKalle Valo 	wrqu->rts.disabled = (wrqu->rts.value == 32767);
1221298e50adSKalle Valo 	wrqu->rts.fixed = 1;
1222298e50adSKalle Valo 
1223298e50adSKalle Valo 	return 0;
1224298e50adSKalle Valo }
1225298e50adSKalle Valo 
1226298e50adSKalle Valo /*------------------------------------------------------------------*/
1227298e50adSKalle Valo /*
1228298e50adSKalle Valo  * Wireless Handler : set Fragmentation threshold
1229298e50adSKalle Valo  */
ray_set_frag(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1230298e50adSKalle Valo static int ray_set_frag(struct net_device *dev, struct iw_request_info *info,
1231298e50adSKalle Valo 			union iwreq_data *wrqu, char *extra)
1232298e50adSKalle Valo {
1233298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1234298e50adSKalle Valo 	int fthr = wrqu->frag.value;
1235298e50adSKalle Valo 
1236298e50adSKalle Valo 	/* Reject if card is already initialised */
1237298e50adSKalle Valo 	if (local->card_status != CARD_AWAITING_PARAM)
1238298e50adSKalle Valo 		return -EBUSY;
1239298e50adSKalle Valo 
1240298e50adSKalle Valo 	/* if(wrq->u.frag.fixed == 0) should complain */
1241298e50adSKalle Valo 	if (wrqu->frag.disabled)
1242298e50adSKalle Valo 		fthr = 32767;
1243298e50adSKalle Valo 	else {
1244298e50adSKalle Valo 		if ((fthr < 256) || (fthr > 2347))	/* To check out ! */
1245298e50adSKalle Valo 			return -EINVAL;
1246298e50adSKalle Valo 	}
1247298e50adSKalle Valo 	local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF;
1248298e50adSKalle Valo 	local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF;
1249298e50adSKalle Valo 
1250298e50adSKalle Valo 	return -EINPROGRESS;	/* Call commit handler */
1251298e50adSKalle Valo }
1252298e50adSKalle Valo 
1253298e50adSKalle Valo /*------------------------------------------------------------------*/
1254298e50adSKalle Valo /*
1255298e50adSKalle Valo  * Wireless Handler : get Fragmentation threshold
1256298e50adSKalle Valo  */
ray_get_frag(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1257298e50adSKalle Valo static int ray_get_frag(struct net_device *dev, struct iw_request_info *info,
1258298e50adSKalle Valo 			union iwreq_data *wrqu, char *extra)
1259298e50adSKalle Valo {
1260298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1261298e50adSKalle Valo 
1262298e50adSKalle Valo 	wrqu->frag.value = (local->sparm.b5.a_frag_threshold[0] << 8)
1263298e50adSKalle Valo 	    + local->sparm.b5.a_frag_threshold[1];
1264298e50adSKalle Valo 	wrqu->frag.disabled = (wrqu->frag.value == 32767);
1265298e50adSKalle Valo 	wrqu->frag.fixed = 1;
1266298e50adSKalle Valo 
1267298e50adSKalle Valo 	return 0;
1268298e50adSKalle Valo }
1269298e50adSKalle Valo 
1270298e50adSKalle Valo /*------------------------------------------------------------------*/
1271298e50adSKalle Valo /*
1272298e50adSKalle Valo  * Wireless Handler : set Mode of Operation
1273298e50adSKalle Valo  */
ray_set_mode(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1274298e50adSKalle Valo static int ray_set_mode(struct net_device *dev, struct iw_request_info *info,
1275298e50adSKalle Valo 			union iwreq_data *wrqu, char *extra)
1276298e50adSKalle Valo {
1277298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1278298e50adSKalle Valo 	int err = -EINPROGRESS;	/* Call commit handler */
1279298e50adSKalle Valo 	char card_mode = 1;
1280298e50adSKalle Valo 
1281298e50adSKalle Valo 	/* Reject if card is already initialised */
1282298e50adSKalle Valo 	if (local->card_status != CARD_AWAITING_PARAM)
1283298e50adSKalle Valo 		return -EBUSY;
1284298e50adSKalle Valo 
1285298e50adSKalle Valo 	switch (wrqu->mode) {
1286298e50adSKalle Valo 	case IW_MODE_ADHOC:
1287298e50adSKalle Valo 		card_mode = 0;
1288298e50adSKalle Valo 		fallthrough;
1289298e50adSKalle Valo 	case IW_MODE_INFRA:
1290298e50adSKalle Valo 		local->sparm.b5.a_network_type = card_mode;
1291298e50adSKalle Valo 		break;
1292298e50adSKalle Valo 	default:
1293298e50adSKalle Valo 		err = -EINVAL;
1294298e50adSKalle Valo 	}
1295298e50adSKalle Valo 
1296298e50adSKalle Valo 	return err;
1297298e50adSKalle Valo }
1298298e50adSKalle Valo 
1299298e50adSKalle Valo /*------------------------------------------------------------------*/
1300298e50adSKalle Valo /*
1301298e50adSKalle Valo  * Wireless Handler : get Mode of Operation
1302298e50adSKalle Valo  */
ray_get_mode(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1303298e50adSKalle Valo static int ray_get_mode(struct net_device *dev, struct iw_request_info *info,
1304298e50adSKalle Valo 			union iwreq_data *wrqu, char *extra)
1305298e50adSKalle Valo {
1306298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1307298e50adSKalle Valo 
1308298e50adSKalle Valo 	if (local->sparm.b5.a_network_type)
1309298e50adSKalle Valo 		wrqu->mode = IW_MODE_INFRA;
1310298e50adSKalle Valo 	else
1311298e50adSKalle Valo 		wrqu->mode = IW_MODE_ADHOC;
1312298e50adSKalle Valo 
1313298e50adSKalle Valo 	return 0;
1314298e50adSKalle Valo }
1315298e50adSKalle Valo 
1316298e50adSKalle Valo /*------------------------------------------------------------------*/
1317298e50adSKalle Valo /*
1318298e50adSKalle Valo  * Wireless Handler : get range info
1319298e50adSKalle Valo  */
ray_get_range(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1320298e50adSKalle Valo static int ray_get_range(struct net_device *dev, struct iw_request_info *info,
1321298e50adSKalle Valo 			 union iwreq_data *wrqu, char *extra)
1322298e50adSKalle Valo {
1323298e50adSKalle Valo 	struct iw_range *range = (struct iw_range *)extra;
1324298e50adSKalle Valo 
1325298e50adSKalle Valo 	memset(range, 0, sizeof(struct iw_range));
1326298e50adSKalle Valo 
1327298e50adSKalle Valo 	/* Set the length (very important for backward compatibility) */
1328298e50adSKalle Valo 	wrqu->data.length = sizeof(struct iw_range);
1329298e50adSKalle Valo 
1330298e50adSKalle Valo 	/* Set the Wireless Extension versions */
1331298e50adSKalle Valo 	range->we_version_compiled = WIRELESS_EXT;
1332298e50adSKalle Valo 	range->we_version_source = 9;
1333298e50adSKalle Valo 
1334298e50adSKalle Valo 	/* Set information in the range struct */
1335298e50adSKalle Valo 	range->throughput = 1.1 * 1000 * 1000;	/* Put the right number here */
1336298e50adSKalle Valo 	range->num_channels = hop_pattern_length[(int)country];
1337298e50adSKalle Valo 	range->num_frequency = 0;
1338298e50adSKalle Valo 	range->max_qual.qual = 0;
1339298e50adSKalle Valo 	range->max_qual.level = 255;	/* What's the correct value ? */
1340298e50adSKalle Valo 	range->max_qual.noise = 255;	/* Idem */
1341298e50adSKalle Valo 	range->num_bitrates = 2;
1342298e50adSKalle Valo 	range->bitrate[0] = 1000000;	/* 1 Mb/s */
1343298e50adSKalle Valo 	range->bitrate[1] = 2000000;	/* 2 Mb/s */
1344298e50adSKalle Valo 	return 0;
1345298e50adSKalle Valo }
1346298e50adSKalle Valo 
1347298e50adSKalle Valo /*------------------------------------------------------------------*/
1348298e50adSKalle Valo /*
1349298e50adSKalle Valo  * Wireless Private Handler : set framing mode
1350298e50adSKalle Valo  */
ray_set_framing(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1351298e50adSKalle Valo static int ray_set_framing(struct net_device *dev, struct iw_request_info *info,
1352298e50adSKalle Valo 			   union iwreq_data *wrqu, char *extra)
1353298e50adSKalle Valo {
1354298e50adSKalle Valo 	translate = !!*(extra);	/* Set framing mode */
1355298e50adSKalle Valo 
1356298e50adSKalle Valo 	return 0;
1357298e50adSKalle Valo }
1358298e50adSKalle Valo 
1359298e50adSKalle Valo /*------------------------------------------------------------------*/
1360298e50adSKalle Valo /*
1361298e50adSKalle Valo  * Wireless Private Handler : get framing mode
1362298e50adSKalle Valo  */
ray_get_framing(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1363298e50adSKalle Valo static int ray_get_framing(struct net_device *dev, struct iw_request_info *info,
1364298e50adSKalle Valo 			   union iwreq_data *wrqu, char *extra)
1365298e50adSKalle Valo {
1366298e50adSKalle Valo 	*(extra) = translate;
1367298e50adSKalle Valo 
1368298e50adSKalle Valo 	return 0;
1369298e50adSKalle Valo }
1370298e50adSKalle Valo 
1371298e50adSKalle Valo /*------------------------------------------------------------------*/
1372298e50adSKalle Valo /*
1373298e50adSKalle Valo  * Wireless Private Handler : get country
1374298e50adSKalle Valo  */
ray_get_country(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1375298e50adSKalle Valo static int ray_get_country(struct net_device *dev, struct iw_request_info *info,
1376298e50adSKalle Valo 			   union iwreq_data *wrqu, char *extra)
1377298e50adSKalle Valo {
1378298e50adSKalle Valo 	*(extra) = country;
1379298e50adSKalle Valo 
1380298e50adSKalle Valo 	return 0;
1381298e50adSKalle Valo }
1382298e50adSKalle Valo 
1383298e50adSKalle Valo /*------------------------------------------------------------------*/
1384298e50adSKalle Valo /*
1385298e50adSKalle Valo  * Commit handler : called after a bunch of SET operations
1386298e50adSKalle Valo  */
ray_commit(struct net_device * dev,struct iw_request_info * info,union iwreq_data * wrqu,char * extra)1387298e50adSKalle Valo static int ray_commit(struct net_device *dev, struct iw_request_info *info,
1388298e50adSKalle Valo 		      union iwreq_data *wrqu, char *extra)
1389298e50adSKalle Valo {
1390298e50adSKalle Valo 	return 0;
1391298e50adSKalle Valo }
1392298e50adSKalle Valo 
1393298e50adSKalle Valo /*------------------------------------------------------------------*/
1394298e50adSKalle Valo /*
1395298e50adSKalle Valo  * Stats handler : return Wireless Stats
1396298e50adSKalle Valo  */
ray_get_wireless_stats(struct net_device * dev)1397298e50adSKalle Valo static iw_stats *ray_get_wireless_stats(struct net_device *dev)
1398298e50adSKalle Valo {
1399298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1400298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
1401298e50adSKalle Valo 	struct status __iomem *p = local->sram + STATUS_BASE;
1402298e50adSKalle Valo 
1403298e50adSKalle Valo 	local->wstats.status = local->card_status;
1404298e50adSKalle Valo #ifdef WIRELESS_SPY
1405298e50adSKalle Valo 	if ((local->spy_data.spy_number > 0)
1406298e50adSKalle Valo 	    && (local->sparm.b5.a_network_type == 0)) {
1407298e50adSKalle Valo 		/* Get it from the first node in spy list */
1408298e50adSKalle Valo 		local->wstats.qual.qual = local->spy_data.spy_stat[0].qual;
1409298e50adSKalle Valo 		local->wstats.qual.level = local->spy_data.spy_stat[0].level;
1410298e50adSKalle Valo 		local->wstats.qual.noise = local->spy_data.spy_stat[0].noise;
1411298e50adSKalle Valo 		local->wstats.qual.updated =
1412298e50adSKalle Valo 		    local->spy_data.spy_stat[0].updated;
1413298e50adSKalle Valo 	}
1414298e50adSKalle Valo #endif /* WIRELESS_SPY */
1415298e50adSKalle Valo 
1416298e50adSKalle Valo 	if (pcmcia_dev_present(link)) {
1417298e50adSKalle Valo 		local->wstats.qual.noise = readb(&p->rxnoise);
1418298e50adSKalle Valo 		local->wstats.qual.updated |= 4;
1419298e50adSKalle Valo 	}
1420298e50adSKalle Valo 
1421298e50adSKalle Valo 	return &local->wstats;
1422298e50adSKalle Valo } /* end ray_get_wireless_stats */
1423298e50adSKalle Valo 
1424298e50adSKalle Valo /*------------------------------------------------------------------*/
1425298e50adSKalle Valo /*
1426298e50adSKalle Valo  * Structures to export the Wireless Handlers
1427298e50adSKalle Valo  */
1428298e50adSKalle Valo 
1429298e50adSKalle Valo static const iw_handler ray_handler[] = {
1430298e50adSKalle Valo 	IW_HANDLER(SIOCSIWCOMMIT, ray_commit),
1431298e50adSKalle Valo 	IW_HANDLER(SIOCGIWNAME, ray_get_name),
1432298e50adSKalle Valo 	IW_HANDLER(SIOCSIWFREQ, ray_set_freq),
1433298e50adSKalle Valo 	IW_HANDLER(SIOCGIWFREQ, ray_get_freq),
1434298e50adSKalle Valo 	IW_HANDLER(SIOCSIWMODE, ray_set_mode),
1435298e50adSKalle Valo 	IW_HANDLER(SIOCGIWMODE, ray_get_mode),
1436298e50adSKalle Valo 	IW_HANDLER(SIOCGIWRANGE, ray_get_range),
1437298e50adSKalle Valo #ifdef WIRELESS_SPY
1438298e50adSKalle Valo 	IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy),
1439298e50adSKalle Valo 	IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy),
1440298e50adSKalle Valo 	IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy),
1441298e50adSKalle Valo 	IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy),
1442298e50adSKalle Valo #endif /* WIRELESS_SPY */
1443298e50adSKalle Valo 	IW_HANDLER(SIOCGIWAP, ray_get_wap),
1444298e50adSKalle Valo 	IW_HANDLER(SIOCSIWESSID, ray_set_essid),
1445298e50adSKalle Valo 	IW_HANDLER(SIOCGIWESSID, ray_get_essid),
1446298e50adSKalle Valo 	IW_HANDLER(SIOCSIWRATE, ray_set_rate),
1447298e50adSKalle Valo 	IW_HANDLER(SIOCGIWRATE, ray_get_rate),
1448298e50adSKalle Valo 	IW_HANDLER(SIOCSIWRTS, ray_set_rts),
1449298e50adSKalle Valo 	IW_HANDLER(SIOCGIWRTS, ray_get_rts),
1450298e50adSKalle Valo 	IW_HANDLER(SIOCSIWFRAG, ray_set_frag),
1451298e50adSKalle Valo 	IW_HANDLER(SIOCGIWFRAG, ray_get_frag),
1452298e50adSKalle Valo };
1453298e50adSKalle Valo 
1454298e50adSKalle Valo #define SIOCSIPFRAMING	SIOCIWFIRSTPRIV	/* Set framing mode */
1455298e50adSKalle Valo #define SIOCGIPFRAMING	SIOCIWFIRSTPRIV + 1	/* Get framing mode */
1456298e50adSKalle Valo #define SIOCGIPCOUNTRY	SIOCIWFIRSTPRIV + 3	/* Get country code */
1457298e50adSKalle Valo 
1458298e50adSKalle Valo static const iw_handler ray_private_handler[] = {
1459298e50adSKalle Valo 	[0] = ray_set_framing,
1460298e50adSKalle Valo 	[1] = ray_get_framing,
1461298e50adSKalle Valo 	[3] = ray_get_country,
1462298e50adSKalle Valo };
1463298e50adSKalle Valo 
1464298e50adSKalle Valo static const struct iw_priv_args ray_private_args[] = {
1465298e50adSKalle Valo /* cmd,		set_args,	get_args,	name */
1466298e50adSKalle Valo 	{SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0,
1467298e50adSKalle Valo 	 "set_framing"},
1468298e50adSKalle Valo 	{SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
1469298e50adSKalle Valo 	 "get_framing"},
1470298e50adSKalle Valo 	{SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
1471298e50adSKalle Valo 	 "get_country"},
1472298e50adSKalle Valo };
1473298e50adSKalle Valo 
1474298e50adSKalle Valo static const struct iw_handler_def ray_handler_def = {
1475298e50adSKalle Valo 	.num_standard = ARRAY_SIZE(ray_handler),
1476298e50adSKalle Valo 	.num_private = ARRAY_SIZE(ray_private_handler),
1477298e50adSKalle Valo 	.num_private_args = ARRAY_SIZE(ray_private_args),
1478298e50adSKalle Valo 	.standard = ray_handler,
1479298e50adSKalle Valo 	.private = ray_private_handler,
1480298e50adSKalle Valo 	.private_args = ray_private_args,
1481298e50adSKalle Valo 	.get_wireless_stats = ray_get_wireless_stats,
1482298e50adSKalle Valo };
1483298e50adSKalle Valo 
1484298e50adSKalle Valo /*===========================================================================*/
ray_open(struct net_device * dev)1485298e50adSKalle Valo static int ray_open(struct net_device *dev)
1486298e50adSKalle Valo {
1487298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1488298e50adSKalle Valo 	struct pcmcia_device *link;
1489298e50adSKalle Valo 	link = local->finder;
1490298e50adSKalle Valo 
1491298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_open('%s')\n", dev->name);
1492298e50adSKalle Valo 
1493298e50adSKalle Valo 	if (link->open == 0)
1494298e50adSKalle Valo 		local->num_multi = 0;
1495298e50adSKalle Valo 	link->open++;
1496298e50adSKalle Valo 
1497298e50adSKalle Valo 	/* If the card is not started, time to start it ! - Jean II */
1498298e50adSKalle Valo 	if (local->card_status == CARD_AWAITING_PARAM) {
1499298e50adSKalle Valo 		int i;
1500298e50adSKalle Valo 
1501298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_open: doing init now !\n");
1502298e50adSKalle Valo 
1503298e50adSKalle Valo 		/* Download startup parameters */
1504298e50adSKalle Valo 		if ((i = dl_startup_params(dev)) < 0) {
1505298e50adSKalle Valo 			printk(KERN_INFO
1506298e50adSKalle Valo 			       "ray_dev_init dl_startup_params failed - "
1507298e50adSKalle Valo 			       "returns 0x%x\n", i);
1508298e50adSKalle Valo 			return -1;
1509298e50adSKalle Valo 		}
1510298e50adSKalle Valo 	}
1511298e50adSKalle Valo 
1512298e50adSKalle Valo 	if (sniffer)
1513298e50adSKalle Valo 		netif_stop_queue(dev);
1514298e50adSKalle Valo 	else
1515298e50adSKalle Valo 		netif_start_queue(dev);
1516298e50adSKalle Valo 
1517298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_open ending\n");
1518298e50adSKalle Valo 	return 0;
1519298e50adSKalle Valo } /* end ray_open */
1520298e50adSKalle Valo 
1521298e50adSKalle Valo /*===========================================================================*/
ray_dev_close(struct net_device * dev)1522298e50adSKalle Valo static int ray_dev_close(struct net_device *dev)
1523298e50adSKalle Valo {
1524298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1525298e50adSKalle Valo 	struct pcmcia_device *link;
1526298e50adSKalle Valo 	link = local->finder;
1527298e50adSKalle Valo 
1528298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_dev_close('%s')\n", dev->name);
1529298e50adSKalle Valo 
1530298e50adSKalle Valo 	link->open--;
1531298e50adSKalle Valo 	netif_stop_queue(dev);
1532298e50adSKalle Valo 
1533298e50adSKalle Valo 	/* In here, we should stop the hardware (stop card from beeing active)
1534298e50adSKalle Valo 	 * and set local->card_status to CARD_AWAITING_PARAM, so that while the
1535298e50adSKalle Valo 	 * card is closed we can chage its configuration.
1536298e50adSKalle Valo 	 * Probably also need a COR reset to get sane state - Jean II */
1537298e50adSKalle Valo 
1538298e50adSKalle Valo 	return 0;
1539298e50adSKalle Valo } /* end ray_dev_close */
1540298e50adSKalle Valo 
1541298e50adSKalle Valo /*===========================================================================*/
ray_reset(struct net_device * dev)1542298e50adSKalle Valo static void ray_reset(struct net_device *dev)
1543298e50adSKalle Valo {
1544298e50adSKalle Valo 	pr_debug("ray_reset entered\n");
1545298e50adSKalle Valo }
1546298e50adSKalle Valo 
1547298e50adSKalle Valo /*===========================================================================*/
1548298e50adSKalle Valo /* Cause a firmware interrupt if it is ready for one                         */
1549298e50adSKalle Valo /* Return nonzero if not ready                                               */
interrupt_ecf(ray_dev_t * local,int ccs)1550298e50adSKalle Valo static int interrupt_ecf(ray_dev_t *local, int ccs)
1551298e50adSKalle Valo {
1552298e50adSKalle Valo 	int i = 50;
1553298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
1554298e50adSKalle Valo 
1555298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
1556298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs interrupt_ecf - device not present\n");
1557298e50adSKalle Valo 		return -1;
1558298e50adSKalle Valo 	}
1559298e50adSKalle Valo 	dev_dbg(&link->dev, "interrupt_ecf(local=%p, ccs = 0x%x\n", local, ccs);
1560298e50adSKalle Valo 
1561298e50adSKalle Valo 	while (i &&
1562298e50adSKalle Valo 	       (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) &
1563298e50adSKalle Valo 		ECF_INTR_SET))
1564298e50adSKalle Valo 		i--;
1565298e50adSKalle Valo 	if (i == 0) {
1566298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs interrupt_ecf card not ready for interrupt\n");
1567298e50adSKalle Valo 		return -1;
1568298e50adSKalle Valo 	}
1569298e50adSKalle Valo 	/* Fill the mailbox, then kick the card */
1570298e50adSKalle Valo 	writeb(ccs, local->sram + SCB_BASE);
1571298e50adSKalle Valo 	writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET);
1572298e50adSKalle Valo 	return 0;
1573298e50adSKalle Valo } /* interrupt_ecf */
1574298e50adSKalle Valo 
1575298e50adSKalle Valo /*===========================================================================*/
1576298e50adSKalle Valo /* Get next free transmit CCS                                                */
1577298e50adSKalle Valo /* Return - index of current tx ccs                                          */
get_free_tx_ccs(ray_dev_t * local)1578298e50adSKalle Valo static int get_free_tx_ccs(ray_dev_t *local)
1579298e50adSKalle Valo {
1580298e50adSKalle Valo 	int i;
1581298e50adSKalle Valo 	struct ccs __iomem *pccs = ccs_base(local);
1582298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
1583298e50adSKalle Valo 
1584298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
1585298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs get_free_tx_ccs - device not present\n");
1586298e50adSKalle Valo 		return ECARDGONE;
1587298e50adSKalle Valo 	}
1588298e50adSKalle Valo 
1589298e50adSKalle Valo 	if (test_and_set_bit(0, &local->tx_ccs_lock)) {
1590298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs tx_ccs_lock busy\n");
1591298e50adSKalle Valo 		return ECCSBUSY;
1592298e50adSKalle Valo 	}
1593298e50adSKalle Valo 
1594298e50adSKalle Valo 	for (i = 0; i < NUMBER_OF_TX_CCS; i++) {
1595298e50adSKalle Valo 		if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) {
1596298e50adSKalle Valo 			writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status);
1597298e50adSKalle Valo 			writeb(CCS_END_LIST, &(pccs + i)->link);
1598298e50adSKalle Valo 			local->tx_ccs_lock = 0;
1599298e50adSKalle Valo 			return i;
1600298e50adSKalle Valo 		}
1601298e50adSKalle Valo 	}
1602298e50adSKalle Valo 	local->tx_ccs_lock = 0;
1603298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_cs ERROR no free tx CCS for raylink card\n");
1604298e50adSKalle Valo 	return ECCSFULL;
1605298e50adSKalle Valo } /* get_free_tx_ccs */
1606298e50adSKalle Valo 
1607298e50adSKalle Valo /*===========================================================================*/
1608298e50adSKalle Valo /* Get next free CCS                                                         */
1609298e50adSKalle Valo /* Return - index of current ccs                                             */
get_free_ccs(ray_dev_t * local)1610298e50adSKalle Valo static int get_free_ccs(ray_dev_t *local)
1611298e50adSKalle Valo {
1612298e50adSKalle Valo 	int i;
1613298e50adSKalle Valo 	struct ccs __iomem *pccs = ccs_base(local);
1614298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
1615298e50adSKalle Valo 
1616298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
1617298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs get_free_ccs - device not present\n");
1618298e50adSKalle Valo 		return ECARDGONE;
1619298e50adSKalle Valo 	}
1620298e50adSKalle Valo 	if (test_and_set_bit(0, &local->ccs_lock)) {
1621298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs ccs_lock busy\n");
1622298e50adSKalle Valo 		return ECCSBUSY;
1623298e50adSKalle Valo 	}
1624298e50adSKalle Valo 
1625298e50adSKalle Valo 	for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) {
1626298e50adSKalle Valo 		if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) {
1627298e50adSKalle Valo 			writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status);
1628298e50adSKalle Valo 			writeb(CCS_END_LIST, &(pccs + i)->link);
1629298e50adSKalle Valo 			local->ccs_lock = 0;
1630298e50adSKalle Valo 			return i;
1631298e50adSKalle Valo 		}
1632298e50adSKalle Valo 	}
1633298e50adSKalle Valo 	local->ccs_lock = 0;
1634298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_cs ERROR no free CCS for raylink card\n");
1635298e50adSKalle Valo 	return ECCSFULL;
1636298e50adSKalle Valo } /* get_free_ccs */
1637298e50adSKalle Valo 
1638298e50adSKalle Valo /*===========================================================================*/
authenticate_timeout(struct timer_list * t)1639298e50adSKalle Valo static void authenticate_timeout(struct timer_list *t)
1640298e50adSKalle Valo {
1641298e50adSKalle Valo 	ray_dev_t *local = from_timer(local, t, timer);
1642298e50adSKalle Valo 	del_timer(&local->timer);
1643298e50adSKalle Valo 	printk(KERN_INFO "ray_cs Authentication with access point failed"
1644298e50adSKalle Valo 	       " - timeout\n");
1645298e50adSKalle Valo 	join_net(&local->timer);
1646298e50adSKalle Valo }
1647298e50adSKalle Valo 
1648298e50adSKalle Valo /*===========================================================================*/
parse_addr(char * in_str,UCHAR * out)1649298e50adSKalle Valo static int parse_addr(char *in_str, UCHAR *out)
1650298e50adSKalle Valo {
1651298e50adSKalle Valo 	int i, k;
1652298e50adSKalle Valo 	int len;
1653298e50adSKalle Valo 
1654298e50adSKalle Valo 	if (in_str == NULL)
1655298e50adSKalle Valo 		return 0;
1656298e50adSKalle Valo 	len = strnlen(in_str, ADDRLEN * 2 + 1) - 1;
1657298e50adSKalle Valo 	if (len < 1)
1658298e50adSKalle Valo 		return 0;
1659298e50adSKalle Valo 	memset(out, 0, ADDRLEN);
1660298e50adSKalle Valo 
1661298e50adSKalle Valo 	i = 5;
1662298e50adSKalle Valo 
1663298e50adSKalle Valo 	while (len > 0) {
1664298e50adSKalle Valo 		if ((k = hex_to_bin(in_str[len--])) != -1)
1665298e50adSKalle Valo 			out[i] = k;
1666298e50adSKalle Valo 		else
1667298e50adSKalle Valo 			return 0;
1668298e50adSKalle Valo 
1669298e50adSKalle Valo 		if (len == 0)
1670298e50adSKalle Valo 			break;
1671298e50adSKalle Valo 		if ((k = hex_to_bin(in_str[len--])) != -1)
1672298e50adSKalle Valo 			out[i] += k << 4;
1673298e50adSKalle Valo 		else
1674298e50adSKalle Valo 			return 0;
1675298e50adSKalle Valo 		if (!i--)
1676298e50adSKalle Valo 			break;
1677298e50adSKalle Valo 	}
1678298e50adSKalle Valo 	return 1;
1679298e50adSKalle Valo }
1680298e50adSKalle Valo 
1681298e50adSKalle Valo /*===========================================================================*/
ray_get_stats(struct net_device * dev)1682298e50adSKalle Valo static struct net_device_stats *ray_get_stats(struct net_device *dev)
1683298e50adSKalle Valo {
1684298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1685298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
1686298e50adSKalle Valo 	struct status __iomem *p = local->sram + STATUS_BASE;
1687298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
1688298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs net_device_stats - device not present\n");
1689298e50adSKalle Valo 		return &local->stats;
1690298e50adSKalle Valo 	}
1691298e50adSKalle Valo 	if (readb(&p->mrx_overflow_for_host)) {
1692298e50adSKalle Valo 		local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow));
1693298e50adSKalle Valo 		writeb(0, &p->mrx_overflow);
1694298e50adSKalle Valo 		writeb(0, &p->mrx_overflow_for_host);
1695298e50adSKalle Valo 	}
1696298e50adSKalle Valo 	if (readb(&p->mrx_checksum_error_for_host)) {
1697298e50adSKalle Valo 		local->stats.rx_crc_errors +=
1698298e50adSKalle Valo 		    swab16(readw(&p->mrx_checksum_error));
1699298e50adSKalle Valo 		writeb(0, &p->mrx_checksum_error);
1700298e50adSKalle Valo 		writeb(0, &p->mrx_checksum_error_for_host);
1701298e50adSKalle Valo 	}
1702298e50adSKalle Valo 	if (readb(&p->rx_hec_error_for_host)) {
1703298e50adSKalle Valo 		local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error));
1704298e50adSKalle Valo 		writeb(0, &p->rx_hec_error);
1705298e50adSKalle Valo 		writeb(0, &p->rx_hec_error_for_host);
1706298e50adSKalle Valo 	}
1707298e50adSKalle Valo 	return &local->stats;
1708298e50adSKalle Valo }
1709298e50adSKalle Valo 
1710298e50adSKalle Valo /*===========================================================================*/
ray_update_parm(struct net_device * dev,UCHAR objid,UCHAR * value,int len)1711298e50adSKalle Valo static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value,
1712298e50adSKalle Valo 			    int len)
1713298e50adSKalle Valo {
1714298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1715298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
1716298e50adSKalle Valo 	int ccsindex;
1717298e50adSKalle Valo 	int i;
1718298e50adSKalle Valo 	struct ccs __iomem *pccs;
1719298e50adSKalle Valo 
1720298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
1721298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_update_parm - device not present\n");
1722298e50adSKalle Valo 		return;
1723298e50adSKalle Valo 	}
1724298e50adSKalle Valo 
1725298e50adSKalle Valo 	if ((ccsindex = get_free_ccs(local)) < 0) {
1726298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_update_parm - No free ccs\n");
1727298e50adSKalle Valo 		return;
1728298e50adSKalle Valo 	}
1729298e50adSKalle Valo 	pccs = ccs_base(local) + ccsindex;
1730298e50adSKalle Valo 	writeb(CCS_UPDATE_PARAMS, &pccs->cmd);
1731298e50adSKalle Valo 	writeb(objid, &pccs->var.update_param.object_id);
1732298e50adSKalle Valo 	writeb(1, &pccs->var.update_param.number_objects);
1733298e50adSKalle Valo 	writeb(0, &pccs->var.update_param.failure_cause);
1734298e50adSKalle Valo 	for (i = 0; i < len; i++) {
1735298e50adSKalle Valo 		writeb(value[i], local->sram + HOST_TO_ECF_BASE);
1736298e50adSKalle Valo 	}
1737298e50adSKalle Valo 	/* Interrupt the firmware to process the command */
1738298e50adSKalle Valo 	if (interrupt_ecf(local, ccsindex)) {
1739298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n");
1740298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
1741298e50adSKalle Valo 	}
1742298e50adSKalle Valo }
1743298e50adSKalle Valo 
1744298e50adSKalle Valo /*===========================================================================*/
ray_update_multi_list(struct net_device * dev,int all)1745298e50adSKalle Valo static void ray_update_multi_list(struct net_device *dev, int all)
1746298e50adSKalle Valo {
1747298e50adSKalle Valo 	int ccsindex;
1748298e50adSKalle Valo 	struct ccs __iomem *pccs;
1749298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1750298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
1751298e50adSKalle Valo 	void __iomem *p = local->sram + HOST_TO_ECF_BASE;
1752298e50adSKalle Valo 
1753298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
1754298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_update_multi_list - device not present\n");
1755298e50adSKalle Valo 		return;
1756298e50adSKalle Valo 	} else
1757298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_update_multi_list(%p)\n", dev);
1758298e50adSKalle Valo 	if ((ccsindex = get_free_ccs(local)) < 0) {
1759298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_update_multi - No free ccs\n");
1760298e50adSKalle Valo 		return;
1761298e50adSKalle Valo 	}
1762298e50adSKalle Valo 	pccs = ccs_base(local) + ccsindex;
1763298e50adSKalle Valo 	writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd);
1764298e50adSKalle Valo 
1765298e50adSKalle Valo 	if (all) {
1766298e50adSKalle Valo 		writeb(0xff, &pccs->var);
1767298e50adSKalle Valo 		local->num_multi = 0xff;
1768298e50adSKalle Valo 	} else {
1769298e50adSKalle Valo 		struct netdev_hw_addr *ha;
1770298e50adSKalle Valo 		int i = 0;
1771298e50adSKalle Valo 
1772298e50adSKalle Valo 		/* Copy the kernel's list of MC addresses to card */
1773298e50adSKalle Valo 		netdev_for_each_mc_addr(ha, dev) {
1774298e50adSKalle Valo 			memcpy_toio(p, ha->addr, ETH_ALEN);
1775298e50adSKalle Valo 			dev_dbg(&link->dev, "ray_update_multi add addr %pm\n",
1776298e50adSKalle Valo 				ha->addr);
1777298e50adSKalle Valo 			p += ETH_ALEN;
1778298e50adSKalle Valo 			i++;
1779298e50adSKalle Valo 		}
1780298e50adSKalle Valo 		if (i > 256 / ADDRLEN)
1781298e50adSKalle Valo 			i = 256 / ADDRLEN;
1782298e50adSKalle Valo 		writeb((UCHAR) i, &pccs->var);
1783298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs update_multi %d addresses in list\n", i);
1784298e50adSKalle Valo 		/* Interrupt the firmware to process the command */
1785298e50adSKalle Valo 		local->num_multi = i;
1786298e50adSKalle Valo 	}
1787298e50adSKalle Valo 	if (interrupt_ecf(local, ccsindex)) {
1788298e50adSKalle Valo 		dev_dbg(&link->dev,
1789298e50adSKalle Valo 		      "ray_cs update_multi failed - ECF not ready for intr\n");
1790298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
1791298e50adSKalle Valo 	}
1792298e50adSKalle Valo } /* end ray_update_multi_list */
1793298e50adSKalle Valo 
1794298e50adSKalle Valo /*===========================================================================*/
set_multicast_list(struct net_device * dev)1795298e50adSKalle Valo static void set_multicast_list(struct net_device *dev)
1796298e50adSKalle Valo {
1797298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
1798298e50adSKalle Valo 	UCHAR promisc;
1799298e50adSKalle Valo 
1800298e50adSKalle Valo 	pr_debug("ray_cs set_multicast_list(%p)\n", dev);
1801298e50adSKalle Valo 
1802298e50adSKalle Valo 	if (dev->flags & IFF_PROMISC) {
1803298e50adSKalle Valo 		if (local->sparm.b5.a_promiscuous_mode == 0) {
1804298e50adSKalle Valo 			pr_debug("ray_cs set_multicast_list promisc on\n");
1805298e50adSKalle Valo 			local->sparm.b5.a_promiscuous_mode = 1;
1806298e50adSKalle Valo 			promisc = 1;
1807298e50adSKalle Valo 			ray_update_parm(dev, OBJID_promiscuous_mode,
1808298e50adSKalle Valo 					&promisc, sizeof(promisc));
1809298e50adSKalle Valo 		}
1810298e50adSKalle Valo 	} else {
1811298e50adSKalle Valo 		if (local->sparm.b5.a_promiscuous_mode == 1) {
1812298e50adSKalle Valo 			pr_debug("ray_cs set_multicast_list promisc off\n");
1813298e50adSKalle Valo 			local->sparm.b5.a_promiscuous_mode = 0;
1814298e50adSKalle Valo 			promisc = 0;
1815298e50adSKalle Valo 			ray_update_parm(dev, OBJID_promiscuous_mode,
1816298e50adSKalle Valo 					&promisc, sizeof(promisc));
1817298e50adSKalle Valo 		}
1818298e50adSKalle Valo 	}
1819298e50adSKalle Valo 
1820298e50adSKalle Valo 	if (dev->flags & IFF_ALLMULTI)
1821298e50adSKalle Valo 		ray_update_multi_list(dev, 1);
1822298e50adSKalle Valo 	else {
1823298e50adSKalle Valo 		if (local->num_multi != netdev_mc_count(dev))
1824298e50adSKalle Valo 			ray_update_multi_list(dev, 0);
1825298e50adSKalle Valo 	}
1826298e50adSKalle Valo } /* end set_multicast_list */
1827298e50adSKalle Valo 
1828298e50adSKalle Valo /*=============================================================================
1829298e50adSKalle Valo  * All routines below here are run at interrupt time.
1830298e50adSKalle Valo =============================================================================*/
ray_interrupt(int irq,void * dev_id)1831298e50adSKalle Valo static irqreturn_t ray_interrupt(int irq, void *dev_id)
1832298e50adSKalle Valo {
1833298e50adSKalle Valo 	struct net_device *dev = (struct net_device *)dev_id;
1834298e50adSKalle Valo 	struct pcmcia_device *link;
1835298e50adSKalle Valo 	ray_dev_t *local;
1836298e50adSKalle Valo 	struct ccs __iomem *pccs;
1837298e50adSKalle Valo 	struct rcs __iomem *prcs;
1838298e50adSKalle Valo 	UCHAR rcsindex;
1839298e50adSKalle Valo 	UCHAR tmp;
1840298e50adSKalle Valo 	UCHAR cmd;
1841298e50adSKalle Valo 	UCHAR status;
1842298e50adSKalle Valo 	UCHAR memtmp[ESSID_SIZE + 1];
1843298e50adSKalle Valo 
1844298e50adSKalle Valo 
1845298e50adSKalle Valo 	if (dev == NULL)	/* Note that we want interrupts with dev->start == 0 */
1846298e50adSKalle Valo 		return IRQ_NONE;
1847298e50adSKalle Valo 
1848298e50adSKalle Valo 	pr_debug("ray_cs: interrupt for *dev=%p\n", dev);
1849298e50adSKalle Valo 
1850298e50adSKalle Valo 	local = netdev_priv(dev);
1851298e50adSKalle Valo 	link = local->finder;
1852298e50adSKalle Valo 	if (!pcmcia_dev_present(link)) {
1853298e50adSKalle Valo 		pr_debug(
1854298e50adSKalle Valo 			"ray_cs interrupt from device not present or suspended.\n");
1855298e50adSKalle Valo 		return IRQ_NONE;
1856298e50adSKalle Valo 	}
1857298e50adSKalle Valo 	rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index);
1858298e50adSKalle Valo 
1859298e50adSKalle Valo 	if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
1860298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs interrupt bad rcsindex = 0x%x\n", rcsindex);
1861298e50adSKalle Valo 		clear_interrupt(local);
1862298e50adSKalle Valo 		return IRQ_HANDLED;
1863298e50adSKalle Valo 	}
1864298e50adSKalle Valo 	if (rcsindex < NUMBER_OF_CCS) { /* If it's a returned CCS */
1865298e50adSKalle Valo 		pccs = ccs_base(local) + rcsindex;
1866298e50adSKalle Valo 		cmd = readb(&pccs->cmd);
1867298e50adSKalle Valo 		status = readb(&pccs->buffer_status);
1868298e50adSKalle Valo 		switch (cmd) {
1869298e50adSKalle Valo 		case CCS_DOWNLOAD_STARTUP_PARAMS:	/* Happens in firmware someday */
1870298e50adSKalle Valo 			del_timer(&local->timer);
1871298e50adSKalle Valo 			if (status == CCS_COMMAND_COMPLETE) {
1872298e50adSKalle Valo 				dev_dbg(&link->dev,
1873298e50adSKalle Valo 				      "ray_cs interrupt download_startup_parameters OK\n");
1874298e50adSKalle Valo 			} else {
1875298e50adSKalle Valo 				dev_dbg(&link->dev,
1876298e50adSKalle Valo 				      "ray_cs interrupt download_startup_parameters fail\n");
1877298e50adSKalle Valo 			}
1878298e50adSKalle Valo 			break;
1879298e50adSKalle Valo 		case CCS_UPDATE_PARAMS:
1880298e50adSKalle Valo 			dev_dbg(&link->dev, "ray_cs interrupt update params done\n");
1881298e50adSKalle Valo 			if (status != CCS_COMMAND_COMPLETE) {
1882298e50adSKalle Valo 				tmp =
1883298e50adSKalle Valo 				    readb(&pccs->var.update_param.
1884298e50adSKalle Valo 					  failure_cause);
1885298e50adSKalle Valo 				dev_dbg(&link->dev,
1886298e50adSKalle Valo 				      "ray_cs interrupt update params failed - reason %d\n",
1887298e50adSKalle Valo 				      tmp);
1888298e50adSKalle Valo 			}
1889298e50adSKalle Valo 			break;
1890298e50adSKalle Valo 		case CCS_REPORT_PARAMS:
1891298e50adSKalle Valo 			dev_dbg(&link->dev, "ray_cs interrupt report params done\n");
1892298e50adSKalle Valo 			break;
1893298e50adSKalle Valo 		case CCS_UPDATE_MULTICAST_LIST:	/* Note that this CCS isn't returned */
1894298e50adSKalle Valo 			dev_dbg(&link->dev,
1895298e50adSKalle Valo 			      "ray_cs interrupt CCS Update Multicast List done\n");
1896298e50adSKalle Valo 			break;
1897298e50adSKalle Valo 		case CCS_UPDATE_POWER_SAVINGS_MODE:
1898298e50adSKalle Valo 			dev_dbg(&link->dev,
1899298e50adSKalle Valo 			      "ray_cs interrupt update power save mode done\n");
1900298e50adSKalle Valo 			break;
1901298e50adSKalle Valo 		case CCS_START_NETWORK:
1902298e50adSKalle Valo 		case CCS_JOIN_NETWORK:
1903298e50adSKalle Valo 			memcpy(memtmp, local->sparm.b4.a_current_ess_id,
1904298e50adSKalle Valo 								ESSID_SIZE);
1905298e50adSKalle Valo 			memtmp[ESSID_SIZE] = '\0';
1906298e50adSKalle Valo 
1907298e50adSKalle Valo 			if (status == CCS_COMMAND_COMPLETE) {
1908298e50adSKalle Valo 				if (readb
1909298e50adSKalle Valo 				    (&pccs->var.start_network.net_initiated) ==
1910298e50adSKalle Valo 				    1) {
1911298e50adSKalle Valo 					dev_dbg(&link->dev,
1912298e50adSKalle Valo 					      "ray_cs interrupt network \"%s\" started\n",
1913298e50adSKalle Valo 					      memtmp);
1914298e50adSKalle Valo 				} else {
1915298e50adSKalle Valo 					dev_dbg(&link->dev,
1916298e50adSKalle Valo 					      "ray_cs interrupt network \"%s\" joined\n",
1917298e50adSKalle Valo 					      memtmp);
1918298e50adSKalle Valo 				}
1919298e50adSKalle Valo 				memcpy_fromio(&local->bss_id,
1920298e50adSKalle Valo 					      pccs->var.start_network.bssid,
1921298e50adSKalle Valo 					      ADDRLEN);
1922298e50adSKalle Valo 
1923298e50adSKalle Valo 				if (local->fw_ver == 0x55)
1924298e50adSKalle Valo 					local->net_default_tx_rate = 3;
1925298e50adSKalle Valo 				else
1926298e50adSKalle Valo 					local->net_default_tx_rate =
1927298e50adSKalle Valo 					    readb(&pccs->var.start_network.
1928298e50adSKalle Valo 						  net_default_tx_rate);
1929298e50adSKalle Valo 				local->encryption =
1930298e50adSKalle Valo 				    readb(&pccs->var.start_network.encryption);
1931298e50adSKalle Valo 				if (!sniffer && (local->net_type == INFRA)
1932298e50adSKalle Valo 				    && !(local->sparm.b4.a_acting_as_ap_status)) {
1933298e50adSKalle Valo 					authenticate(local);
1934298e50adSKalle Valo 				}
1935298e50adSKalle Valo 				local->card_status = CARD_ACQ_COMPLETE;
1936298e50adSKalle Valo 			} else {
1937298e50adSKalle Valo 				local->card_status = CARD_ACQ_FAILED;
1938298e50adSKalle Valo 
1939298e50adSKalle Valo 				del_timer(&local->timer);
1940298e50adSKalle Valo 				local->timer.expires = jiffies + HZ * 5;
1941298e50adSKalle Valo 				if (status == CCS_START_NETWORK) {
1942298e50adSKalle Valo 					dev_dbg(&link->dev,
1943298e50adSKalle Valo 					      "ray_cs interrupt network \"%s\" start failed\n",
1944298e50adSKalle Valo 					      memtmp);
1945298e50adSKalle Valo 					local->timer.function = start_net;
1946298e50adSKalle Valo 				} else {
1947298e50adSKalle Valo 					dev_dbg(&link->dev,
1948298e50adSKalle Valo 					      "ray_cs interrupt network \"%s\" join failed\n",
1949298e50adSKalle Valo 					      memtmp);
1950298e50adSKalle Valo 					local->timer.function = join_net;
1951298e50adSKalle Valo 				}
1952298e50adSKalle Valo 				add_timer(&local->timer);
1953298e50adSKalle Valo 			}
1954298e50adSKalle Valo 			break;
1955298e50adSKalle Valo 		case CCS_START_ASSOCIATION:
1956298e50adSKalle Valo 			if (status == CCS_COMMAND_COMPLETE) {
1957298e50adSKalle Valo 				local->card_status = CARD_ASSOC_COMPLETE;
1958298e50adSKalle Valo 				dev_dbg(&link->dev, "ray_cs association successful\n");
1959298e50adSKalle Valo 			} else {
1960298e50adSKalle Valo 				dev_dbg(&link->dev, "ray_cs association failed,\n");
1961298e50adSKalle Valo 				local->card_status = CARD_ASSOC_FAILED;
1962298e50adSKalle Valo 				join_net(&local->timer);
1963298e50adSKalle Valo 			}
1964298e50adSKalle Valo 			break;
1965298e50adSKalle Valo 		case CCS_TX_REQUEST:
1966298e50adSKalle Valo 			if (status == CCS_COMMAND_COMPLETE) {
1967298e50adSKalle Valo 				dev_dbg(&link->dev,
1968298e50adSKalle Valo 				      "ray_cs interrupt tx request complete\n");
1969298e50adSKalle Valo 			} else {
1970298e50adSKalle Valo 				dev_dbg(&link->dev,
1971298e50adSKalle Valo 				      "ray_cs interrupt tx request failed\n");
1972298e50adSKalle Valo 			}
1973298e50adSKalle Valo 			if (!sniffer)
1974298e50adSKalle Valo 				netif_start_queue(dev);
1975298e50adSKalle Valo 			netif_wake_queue(dev);
1976298e50adSKalle Valo 			break;
1977298e50adSKalle Valo 		case CCS_TEST_MEMORY:
1978298e50adSKalle Valo 			dev_dbg(&link->dev, "ray_cs interrupt mem test done\n");
1979298e50adSKalle Valo 			break;
1980298e50adSKalle Valo 		case CCS_SHUTDOWN:
1981298e50adSKalle Valo 			dev_dbg(&link->dev,
1982298e50adSKalle Valo 			      "ray_cs interrupt Unexpected CCS returned - Shutdown\n");
1983298e50adSKalle Valo 			break;
1984298e50adSKalle Valo 		case CCS_DUMP_MEMORY:
1985298e50adSKalle Valo 			dev_dbg(&link->dev, "ray_cs interrupt dump memory done\n");
1986298e50adSKalle Valo 			break;
1987298e50adSKalle Valo 		case CCS_START_TIMER:
1988298e50adSKalle Valo 			dev_dbg(&link->dev,
1989298e50adSKalle Valo 			      "ray_cs interrupt DING - raylink timer expired\n");
1990298e50adSKalle Valo 			break;
1991298e50adSKalle Valo 		default:
1992298e50adSKalle Valo 			dev_dbg(&link->dev,
1993298e50adSKalle Valo 			      "ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n",
1994298e50adSKalle Valo 			      rcsindex, cmd);
1995298e50adSKalle Valo 		}
1996298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
1997298e50adSKalle Valo 	} else { /* It's an RCS */
1998298e50adSKalle Valo 
1999298e50adSKalle Valo 		prcs = rcs_base(local) + rcsindex;
2000298e50adSKalle Valo 
2001298e50adSKalle Valo 		switch (readb(&prcs->interrupt_id)) {
2002298e50adSKalle Valo 		case PROCESS_RX_PACKET:
2003298e50adSKalle Valo 			ray_rx(dev, local, prcs);
2004298e50adSKalle Valo 			break;
2005298e50adSKalle Valo 		case REJOIN_NET_COMPLETE:
2006298e50adSKalle Valo 			dev_dbg(&link->dev, "ray_cs interrupt rejoin net complete\n");
2007298e50adSKalle Valo 			local->card_status = CARD_ACQ_COMPLETE;
2008298e50adSKalle Valo 			/* do we need to clear tx buffers CCS's? */
2009298e50adSKalle Valo 			if (local->sparm.b4.a_network_type == ADHOC) {
2010298e50adSKalle Valo 				if (!sniffer)
2011298e50adSKalle Valo 					netif_start_queue(dev);
2012298e50adSKalle Valo 			} else {
2013298e50adSKalle Valo 				memcpy_fromio(&local->bss_id,
2014298e50adSKalle Valo 					      prcs->var.rejoin_net_complete.
2015298e50adSKalle Valo 					      bssid, ADDRLEN);
2016298e50adSKalle Valo 				dev_dbg(&link->dev, "ray_cs new BSSID = %pm\n",
2017298e50adSKalle Valo 					local->bss_id);
2018298e50adSKalle Valo 				if (!sniffer)
2019298e50adSKalle Valo 					authenticate(local);
2020298e50adSKalle Valo 			}
2021298e50adSKalle Valo 			break;
2022298e50adSKalle Valo 		case ROAMING_INITIATED:
2023298e50adSKalle Valo 			dev_dbg(&link->dev, "ray_cs interrupt roaming initiated\n");
2024298e50adSKalle Valo 			netif_stop_queue(dev);
2025298e50adSKalle Valo 			local->card_status = CARD_DOING_ACQ;
2026298e50adSKalle Valo 			break;
2027298e50adSKalle Valo 		case JAPAN_CALL_SIGN_RXD:
2028298e50adSKalle Valo 			dev_dbg(&link->dev, "ray_cs interrupt japan call sign rx\n");
2029298e50adSKalle Valo 			break;
2030298e50adSKalle Valo 		default:
2031298e50adSKalle Valo 			dev_dbg(&link->dev,
2032298e50adSKalle Valo 			      "ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",
2033298e50adSKalle Valo 			      rcsindex,
2034298e50adSKalle Valo 			      (unsigned int)readb(&prcs->interrupt_id));
2035298e50adSKalle Valo 			break;
2036298e50adSKalle Valo 		}
2037298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &prcs->buffer_status);
2038298e50adSKalle Valo 	}
2039298e50adSKalle Valo 	clear_interrupt(local);
2040298e50adSKalle Valo 	return IRQ_HANDLED;
2041298e50adSKalle Valo } /* ray_interrupt */
2042298e50adSKalle Valo 
2043298e50adSKalle Valo /*===========================================================================*/
ray_rx(struct net_device * dev,ray_dev_t * local,struct rcs __iomem * prcs)2044298e50adSKalle Valo static void ray_rx(struct net_device *dev, ray_dev_t *local,
2045298e50adSKalle Valo 		   struct rcs __iomem *prcs)
2046298e50adSKalle Valo {
2047298e50adSKalle Valo 	int rx_len;
2048298e50adSKalle Valo 	unsigned int pkt_addr;
2049298e50adSKalle Valo 	void __iomem *pmsg;
2050298e50adSKalle Valo 	pr_debug("ray_rx process rx packet\n");
2051298e50adSKalle Valo 
2052298e50adSKalle Valo 	/* Calculate address of packet within Rx buffer */
2053298e50adSKalle Valo 	pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8)
2054298e50adSKalle Valo 		    + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END;
2055298e50adSKalle Valo 	/* Length of first packet fragment */
2056298e50adSKalle Valo 	rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8)
2057298e50adSKalle Valo 	    + readb(&prcs->var.rx_packet.rx_data_length[1]);
2058298e50adSKalle Valo 
2059298e50adSKalle Valo 	local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev);
2060298e50adSKalle Valo 	pmsg = local->rmem + pkt_addr;
2061298e50adSKalle Valo 	switch (readb(pmsg)) {
2062298e50adSKalle Valo 	case DATA_TYPE:
2063298e50adSKalle Valo 		pr_debug("ray_rx data type\n");
2064298e50adSKalle Valo 		rx_data(dev, prcs, pkt_addr, rx_len);
2065298e50adSKalle Valo 		break;
2066298e50adSKalle Valo 	case AUTHENTIC_TYPE:
2067298e50adSKalle Valo 		pr_debug("ray_rx authentic type\n");
2068298e50adSKalle Valo 		if (sniffer)
2069298e50adSKalle Valo 			rx_data(dev, prcs, pkt_addr, rx_len);
2070298e50adSKalle Valo 		else
2071298e50adSKalle Valo 			rx_authenticate(local, prcs, pkt_addr, rx_len);
2072298e50adSKalle Valo 		break;
2073298e50adSKalle Valo 	case DEAUTHENTIC_TYPE:
2074298e50adSKalle Valo 		pr_debug("ray_rx deauth type\n");
2075298e50adSKalle Valo 		if (sniffer)
2076298e50adSKalle Valo 			rx_data(dev, prcs, pkt_addr, rx_len);
2077298e50adSKalle Valo 		else
2078298e50adSKalle Valo 			rx_deauthenticate(local, prcs, pkt_addr, rx_len);
2079298e50adSKalle Valo 		break;
2080298e50adSKalle Valo 	case NULL_MSG_TYPE:
2081298e50adSKalle Valo 		pr_debug("ray_cs rx NULL msg\n");
2082298e50adSKalle Valo 		break;
2083298e50adSKalle Valo 	case BEACON_TYPE:
2084298e50adSKalle Valo 		pr_debug("ray_rx beacon type\n");
2085298e50adSKalle Valo 		if (sniffer)
2086298e50adSKalle Valo 			rx_data(dev, prcs, pkt_addr, rx_len);
2087298e50adSKalle Valo 
2088298e50adSKalle Valo 		copy_from_rx_buff(local, (UCHAR *) &local->last_bcn, pkt_addr,
2089298e50adSKalle Valo 				  rx_len < sizeof(struct beacon_rx) ?
2090298e50adSKalle Valo 				  rx_len : sizeof(struct beacon_rx));
2091298e50adSKalle Valo 
2092298e50adSKalle Valo 		local->beacon_rxed = 1;
2093298e50adSKalle Valo 		/* Get the statistics so the card counters never overflow */
2094298e50adSKalle Valo 		ray_get_stats(dev);
2095298e50adSKalle Valo 		break;
2096298e50adSKalle Valo 	default:
2097298e50adSKalle Valo 		pr_debug("ray_cs unknown pkt type %2x\n",
2098298e50adSKalle Valo 		      (unsigned int)readb(pmsg));
2099298e50adSKalle Valo 		break;
2100298e50adSKalle Valo 	}
2101298e50adSKalle Valo 
2102298e50adSKalle Valo } /* end ray_rx */
2103298e50adSKalle Valo 
2104298e50adSKalle Valo /*===========================================================================*/
rx_data(struct net_device * dev,struct rcs __iomem * prcs,unsigned int pkt_addr,int rx_len)2105298e50adSKalle Valo static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
2106298e50adSKalle Valo 		    unsigned int pkt_addr, int rx_len)
2107298e50adSKalle Valo {
2108298e50adSKalle Valo 	struct sk_buff *skb = NULL;
2109298e50adSKalle Valo 	struct rcs __iomem *prcslink = prcs;
2110298e50adSKalle Valo 	ray_dev_t *local = netdev_priv(dev);
2111298e50adSKalle Valo 	UCHAR *rx_ptr;
2112298e50adSKalle Valo 	int total_len;
2113298e50adSKalle Valo 	int tmp;
2114298e50adSKalle Valo #ifdef WIRELESS_SPY
2115298e50adSKalle Valo 	int siglev = local->last_rsl;
2116298e50adSKalle Valo 	u_char linksrcaddr[ETH_ALEN];	/* Other end of the wireless link */
2117298e50adSKalle Valo #endif
2118298e50adSKalle Valo 
2119298e50adSKalle Valo 	if (!sniffer) {
2120298e50adSKalle Valo 		if (translate) {
2121298e50adSKalle Valo /* TBD length needs fixing for translated header */
2122298e50adSKalle Valo 			if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
2123298e50adSKalle Valo 			    rx_len >
2124298e50adSKalle Valo 			    (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
2125298e50adSKalle Valo 			     FCS_LEN)) {
2126298e50adSKalle Valo 				pr_debug(
2127298e50adSKalle Valo 				      "ray_cs invalid packet length %d received\n",
2128298e50adSKalle Valo 				      rx_len);
2129298e50adSKalle Valo 				return;
2130298e50adSKalle Valo 			}
2131298e50adSKalle Valo 		} else { /* encapsulated ethernet */
2132298e50adSKalle Valo 
2133298e50adSKalle Valo 			if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
2134298e50adSKalle Valo 			    rx_len >
2135298e50adSKalle Valo 			    (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
2136298e50adSKalle Valo 			     FCS_LEN)) {
2137298e50adSKalle Valo 				pr_debug(
2138298e50adSKalle Valo 				      "ray_cs invalid packet length %d received\n",
2139298e50adSKalle Valo 				      rx_len);
2140298e50adSKalle Valo 				return;
2141298e50adSKalle Valo 			}
2142298e50adSKalle Valo 		}
2143298e50adSKalle Valo 	}
2144298e50adSKalle Valo 	pr_debug("ray_cs rx_data packet\n");
2145298e50adSKalle Valo 	/* If fragmented packet, verify sizes of fragments add up */
2146298e50adSKalle Valo 	if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
2147298e50adSKalle Valo 		pr_debug("ray_cs rx'ed fragment\n");
2148298e50adSKalle Valo 		tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8)
2149298e50adSKalle Valo 		    + readb(&prcs->var.rx_packet.totalpacketlength[1]);
2150298e50adSKalle Valo 		total_len = tmp;
2151298e50adSKalle Valo 		prcslink = prcs;
2152298e50adSKalle Valo 		do {
2153298e50adSKalle Valo 			tmp -=
2154298e50adSKalle Valo 			    (readb(&prcslink->var.rx_packet.rx_data_length[0])
2155298e50adSKalle Valo 			     << 8)
2156298e50adSKalle Valo 			    + readb(&prcslink->var.rx_packet.rx_data_length[1]);
2157298e50adSKalle Valo 			if (readb(&prcslink->var.rx_packet.next_frag_rcs_index)
2158298e50adSKalle Valo 			    == 0xFF || tmp < 0)
2159298e50adSKalle Valo 				break;
2160298e50adSKalle Valo 			prcslink = rcs_base(local)
2161298e50adSKalle Valo 			    + readb(&prcslink->link_field);
2162298e50adSKalle Valo 		} while (1);
2163298e50adSKalle Valo 
2164298e50adSKalle Valo 		if (tmp < 0) {
2165298e50adSKalle Valo 			pr_debug(
2166298e50adSKalle Valo 			      "ray_cs rx_data fragment lengths don't add up\n");
2167298e50adSKalle Valo 			local->stats.rx_dropped++;
2168298e50adSKalle Valo 			release_frag_chain(local, prcs);
2169298e50adSKalle Valo 			return;
2170298e50adSKalle Valo 		}
2171298e50adSKalle Valo 	} else { /* Single unfragmented packet */
2172298e50adSKalle Valo 		total_len = rx_len;
2173298e50adSKalle Valo 	}
2174298e50adSKalle Valo 
2175298e50adSKalle Valo 	skb = dev_alloc_skb(total_len + 5);
2176298e50adSKalle Valo 	if (skb == NULL) {
2177298e50adSKalle Valo 		pr_debug("ray_cs rx_data could not allocate skb\n");
2178298e50adSKalle Valo 		local->stats.rx_dropped++;
2179298e50adSKalle Valo 		if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF)
2180298e50adSKalle Valo 			release_frag_chain(local, prcs);
2181298e50adSKalle Valo 		return;
2182298e50adSKalle Valo 	}
2183298e50adSKalle Valo 	skb_reserve(skb, 2);	/* Align IP on 16 byte (TBD check this) */
2184298e50adSKalle Valo 
2185298e50adSKalle Valo 	pr_debug("ray_cs rx_data total_len = %x, rx_len = %x\n", total_len,
2186298e50adSKalle Valo 	      rx_len);
2187298e50adSKalle Valo 
2188298e50adSKalle Valo /************************/
2189298e50adSKalle Valo 	/* Reserve enough room for the whole damn packet. */
2190298e50adSKalle Valo 	rx_ptr = skb_put(skb, total_len);
2191298e50adSKalle Valo 	/* Copy the whole packet to sk_buff */
2192298e50adSKalle Valo 	rx_ptr +=
2193298e50adSKalle Valo 	    copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len);
2194298e50adSKalle Valo 	/* Get source address */
2195298e50adSKalle Valo #ifdef WIRELESS_SPY
2196298e50adSKalle Valo 	skb_copy_from_linear_data_offset(skb,
2197298e50adSKalle Valo 					 offsetof(struct mac_header, addr_2),
2198298e50adSKalle Valo 					 linksrcaddr, ETH_ALEN);
2199298e50adSKalle Valo #endif
2200298e50adSKalle Valo 	/* Now, deal with encapsulation/translation/sniffer */
2201298e50adSKalle Valo 	if (!sniffer) {
2202298e50adSKalle Valo 		if (!translate) {
2203298e50adSKalle Valo 			/* Encapsulated ethernet, so just lop off 802.11 MAC header */
2204298e50adSKalle Valo /* TBD reserve            skb_reserve( skb, RX_MAC_HEADER_LENGTH); */
2205298e50adSKalle Valo 			skb_pull(skb, RX_MAC_HEADER_LENGTH);
2206298e50adSKalle Valo 		} else {
2207298e50adSKalle Valo 			/* Do translation */
2208298e50adSKalle Valo 			untranslate(local, skb, total_len);
2209298e50adSKalle Valo 		}
2210298e50adSKalle Valo 	} else { /* sniffer mode, so just pass whole packet */
2211298e50adSKalle Valo 	}
2212298e50adSKalle Valo 
2213298e50adSKalle Valo /************************/
2214298e50adSKalle Valo 	/* Now pick up the rest of the fragments if any */
2215298e50adSKalle Valo 	tmp = 17;
2216298e50adSKalle Valo 	if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
2217298e50adSKalle Valo 		prcslink = prcs;
2218298e50adSKalle Valo 		pr_debug("ray_cs rx_data in fragment loop\n");
2219298e50adSKalle Valo 		do {
2220298e50adSKalle Valo 			prcslink = rcs_base(local)
2221298e50adSKalle Valo 			    +
2222298e50adSKalle Valo 			    readb(&prcslink->var.rx_packet.next_frag_rcs_index);
2223298e50adSKalle Valo 			rx_len =
2224298e50adSKalle Valo 			    ((readb(&prcslink->var.rx_packet.rx_data_length[0])
2225298e50adSKalle Valo 			      << 8)
2226298e50adSKalle Valo 			     +
2227298e50adSKalle Valo 			     readb(&prcslink->var.rx_packet.rx_data_length[1]))
2228298e50adSKalle Valo 			    & RX_BUFF_END;
2229298e50adSKalle Valo 			pkt_addr =
2230298e50adSKalle Valo 			    ((readb(&prcslink->var.rx_packet.rx_data_ptr[0]) <<
2231298e50adSKalle Valo 			      8)
2232298e50adSKalle Valo 			     + readb(&prcslink->var.rx_packet.rx_data_ptr[1]))
2233298e50adSKalle Valo 			    & RX_BUFF_END;
2234298e50adSKalle Valo 
2235298e50adSKalle Valo 			rx_ptr +=
2236298e50adSKalle Valo 			    copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len);
2237298e50adSKalle Valo 
2238298e50adSKalle Valo 		} while (tmp-- &&
2239298e50adSKalle Valo 			 readb(&prcslink->var.rx_packet.next_frag_rcs_index) !=
2240298e50adSKalle Valo 			 0xFF);
2241298e50adSKalle Valo 		release_frag_chain(local, prcs);
2242298e50adSKalle Valo 	}
2243298e50adSKalle Valo 
2244298e50adSKalle Valo 	skb->protocol = eth_type_trans(skb, dev);
2245298e50adSKalle Valo 	netif_rx(skb);
2246298e50adSKalle Valo 	local->stats.rx_packets++;
2247298e50adSKalle Valo 	local->stats.rx_bytes += total_len;
2248298e50adSKalle Valo 
2249298e50adSKalle Valo 	/* Gather signal strength per address */
2250298e50adSKalle Valo #ifdef WIRELESS_SPY
2251298e50adSKalle Valo 	/* For the Access Point or the node having started the ad-hoc net
2252298e50adSKalle Valo 	 * note : ad-hoc work only in some specific configurations, but we
2253298e50adSKalle Valo 	 * kludge in ray_get_wireless_stats... */
2254298e50adSKalle Valo 	if (!memcmp(linksrcaddr, local->bss_id, ETH_ALEN)) {
2255298e50adSKalle Valo 		/* Update statistics */
2256298e50adSKalle Valo 		/*local->wstats.qual.qual = none ? */
2257298e50adSKalle Valo 		local->wstats.qual.level = siglev;
2258298e50adSKalle Valo 		/*local->wstats.qual.noise = none ? */
2259298e50adSKalle Valo 		local->wstats.qual.updated = 0x2;
2260298e50adSKalle Valo 	}
2261298e50adSKalle Valo 	/* Now, update the spy stuff */
2262298e50adSKalle Valo 	{
2263298e50adSKalle Valo 		struct iw_quality wstats;
2264298e50adSKalle Valo 		wstats.level = siglev;
2265298e50adSKalle Valo 		/* wstats.noise = none ? */
2266298e50adSKalle Valo 		/* wstats.qual = none ? */
2267298e50adSKalle Valo 		wstats.updated = 0x2;
2268298e50adSKalle Valo 		/* Update spy records */
2269298e50adSKalle Valo 		wireless_spy_update(dev, linksrcaddr, &wstats);
2270298e50adSKalle Valo 	}
2271298e50adSKalle Valo #endif /* WIRELESS_SPY */
2272298e50adSKalle Valo } /* end rx_data */
2273298e50adSKalle Valo 
2274298e50adSKalle Valo /*===========================================================================*/
untranslate(ray_dev_t * local,struct sk_buff * skb,int len)2275298e50adSKalle Valo static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
2276298e50adSKalle Valo {
2277298e50adSKalle Valo 	snaphdr_t *psnap = (snaphdr_t *) (skb->data + RX_MAC_HEADER_LENGTH);
2278298e50adSKalle Valo 	struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data;
2279298e50adSKalle Valo 	__be16 type = *(__be16 *) psnap->ethertype;
2280298e50adSKalle Valo 	int delta;
2281298e50adSKalle Valo 	struct ethhdr *peth;
2282298e50adSKalle Valo 	UCHAR srcaddr[ADDRLEN];
2283298e50adSKalle Valo 	UCHAR destaddr[ADDRLEN];
2284298e50adSKalle Valo 	static const UCHAR org_bridge[3] = { 0, 0, 0xf8 };
2285298e50adSKalle Valo 	static const UCHAR org_1042[3] = { 0, 0, 0 };
2286298e50adSKalle Valo 
2287298e50adSKalle Valo 	memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN);
2288298e50adSKalle Valo 	memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN);
2289298e50adSKalle Valo 
2290298e50adSKalle Valo #if 0
2291298e50adSKalle Valo 	if {
2292298e50adSKalle Valo 		print_hex_dump(KERN_DEBUG, "skb->data before untranslate: ",
2293298e50adSKalle Valo 			       DUMP_PREFIX_NONE, 16, 1,
2294298e50adSKalle Valo 			       skb->data, 64, true);
2295298e50adSKalle Valo 		printk(KERN_DEBUG
2296298e50adSKalle Valo 		       "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n",
2297298e50adSKalle Valo 		       ntohs(type), psnap->dsap, psnap->ssap, psnap->ctrl,
2298298e50adSKalle Valo 		       psnap->org[0], psnap->org[1], psnap->org[2]);
2299298e50adSKalle Valo 		printk(KERN_DEBUG "untranslate skb->data = %p\n", skb->data);
2300298e50adSKalle Valo 	}
2301298e50adSKalle Valo #endif
2302298e50adSKalle Valo 
2303298e50adSKalle Valo 	if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) {
2304298e50adSKalle Valo 		/* not a snap type so leave it alone */
2305298e50adSKalle Valo 		pr_debug("ray_cs untranslate NOT SNAP %02x %02x %02x\n",
2306298e50adSKalle Valo 		      psnap->dsap, psnap->ssap, psnap->ctrl);
2307298e50adSKalle Valo 
2308298e50adSKalle Valo 		delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
2309298e50adSKalle Valo 		peth = (struct ethhdr *)(skb->data + delta);
2310298e50adSKalle Valo 		peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
2311298e50adSKalle Valo 	} else { /* Its a SNAP */
2312298e50adSKalle Valo 		if (memcmp(psnap->org, org_bridge, 3) == 0) {
2313298e50adSKalle Valo 		/* EtherII and nuke the LLC */
2314298e50adSKalle Valo 			pr_debug("ray_cs untranslate Bridge encap\n");
2315298e50adSKalle Valo 			delta = RX_MAC_HEADER_LENGTH
2316298e50adSKalle Valo 			    + sizeof(struct snaphdr_t) - ETH_HLEN;
2317298e50adSKalle Valo 			peth = (struct ethhdr *)(skb->data + delta);
2318298e50adSKalle Valo 			peth->h_proto = type;
2319298e50adSKalle Valo 		} else if (memcmp(psnap->org, org_1042, 3) == 0) {
2320298e50adSKalle Valo 			switch (ntohs(type)) {
2321298e50adSKalle Valo 			case ETH_P_IPX:
2322298e50adSKalle Valo 			case ETH_P_AARP:
2323298e50adSKalle Valo 				pr_debug("ray_cs untranslate RFC IPX/AARP\n");
2324298e50adSKalle Valo 				delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
2325298e50adSKalle Valo 				peth = (struct ethhdr *)(skb->data + delta);
2326298e50adSKalle Valo 				peth->h_proto =
2327298e50adSKalle Valo 				    htons(len - RX_MAC_HEADER_LENGTH);
2328298e50adSKalle Valo 				break;
2329298e50adSKalle Valo 			default:
2330298e50adSKalle Valo 				pr_debug("ray_cs untranslate RFC default\n");
2331298e50adSKalle Valo 				delta = RX_MAC_HEADER_LENGTH +
2332298e50adSKalle Valo 				    sizeof(struct snaphdr_t) - ETH_HLEN;
2333298e50adSKalle Valo 				peth = (struct ethhdr *)(skb->data + delta);
2334298e50adSKalle Valo 				peth->h_proto = type;
2335298e50adSKalle Valo 				break;
2336298e50adSKalle Valo 			}
2337298e50adSKalle Valo 		} else {
2338298e50adSKalle Valo 			printk("ray_cs untranslate very confused by packet\n");
2339298e50adSKalle Valo 			delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
2340298e50adSKalle Valo 			peth = (struct ethhdr *)(skb->data + delta);
2341298e50adSKalle Valo 			peth->h_proto = type;
2342298e50adSKalle Valo 		}
2343298e50adSKalle Valo 	}
2344298e50adSKalle Valo /* TBD reserve  skb_reserve(skb, delta); */
2345298e50adSKalle Valo 	skb_pull(skb, delta);
2346298e50adSKalle Valo 	pr_debug("untranslate after skb_pull(%d), skb->data = %p\n", delta,
2347298e50adSKalle Valo 	      skb->data);
2348298e50adSKalle Valo 	memcpy(peth->h_dest, destaddr, ADDRLEN);
2349298e50adSKalle Valo 	memcpy(peth->h_source, srcaddr, ADDRLEN);
2350298e50adSKalle Valo #if 0
2351298e50adSKalle Valo 	{
2352298e50adSKalle Valo 		int i;
2353298e50adSKalle Valo 		printk(KERN_DEBUG "skb->data after untranslate:");
2354298e50adSKalle Valo 		for (i = 0; i < 64; i++)
2355298e50adSKalle Valo 			printk("%02x ", skb->data[i]);
2356298e50adSKalle Valo 		printk("\n");
2357298e50adSKalle Valo 	}
2358298e50adSKalle Valo #endif
2359298e50adSKalle Valo } /* end untranslate */
2360298e50adSKalle Valo 
2361298e50adSKalle Valo /*===========================================================================*/
2362298e50adSKalle Valo /* Copy data from circular receive buffer to PC memory.
2363298e50adSKalle Valo  * dest     = destination address in PC memory
2364298e50adSKalle Valo  * pkt_addr = source address in receive buffer
2365298e50adSKalle Valo  * len      = length of packet to copy
2366298e50adSKalle Valo  */
copy_from_rx_buff(ray_dev_t * local,UCHAR * dest,int pkt_addr,int length)2367298e50adSKalle Valo static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr,
2368298e50adSKalle Valo 			     int length)
2369298e50adSKalle Valo {
2370298e50adSKalle Valo 	int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1);
2371298e50adSKalle Valo 	if (wrap_bytes <= 0) {
2372298e50adSKalle Valo 		memcpy_fromio(dest, local->rmem + pkt_addr, length);
2373298e50adSKalle Valo 	} else { /* Packet wrapped in circular buffer */
2374298e50adSKalle Valo 
2375298e50adSKalle Valo 		memcpy_fromio(dest, local->rmem + pkt_addr,
2376298e50adSKalle Valo 			      length - wrap_bytes);
2377298e50adSKalle Valo 		memcpy_fromio(dest + length - wrap_bytes, local->rmem,
2378298e50adSKalle Valo 			      wrap_bytes);
2379298e50adSKalle Valo 	}
2380298e50adSKalle Valo 	return length;
2381298e50adSKalle Valo }
2382298e50adSKalle Valo 
2383298e50adSKalle Valo /*===========================================================================*/
release_frag_chain(ray_dev_t * local,struct rcs __iomem * prcs)2384298e50adSKalle Valo static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs)
2385298e50adSKalle Valo {
2386298e50adSKalle Valo 	struct rcs __iomem *prcslink = prcs;
2387298e50adSKalle Valo 	int tmp = 17;
2388298e50adSKalle Valo 	unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index);
2389298e50adSKalle Valo 
2390298e50adSKalle Valo 	while (tmp--) {
2391298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
2392298e50adSKalle Valo 		if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
2393298e50adSKalle Valo 			pr_debug("ray_cs interrupt bad rcsindex = 0x%x\n",
2394298e50adSKalle Valo 			      rcsindex);
2395298e50adSKalle Valo 			break;
2396298e50adSKalle Valo 		}
2397298e50adSKalle Valo 		prcslink = rcs_base(local) + rcsindex;
2398298e50adSKalle Valo 		rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index);
2399298e50adSKalle Valo 	}
2400298e50adSKalle Valo 	writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
2401298e50adSKalle Valo }
2402298e50adSKalle Valo 
2403298e50adSKalle Valo /*===========================================================================*/
authenticate(ray_dev_t * local)2404298e50adSKalle Valo static void authenticate(ray_dev_t *local)
2405298e50adSKalle Valo {
2406298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
2407298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_cs Starting authentication.\n");
2408298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
2409298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs authenticate - device not present\n");
2410298e50adSKalle Valo 		return;
2411298e50adSKalle Valo 	}
2412298e50adSKalle Valo 
2413298e50adSKalle Valo 	del_timer(&local->timer);
2414298e50adSKalle Valo 	if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) {
2415298e50adSKalle Valo 		local->timer.function = join_net;
2416298e50adSKalle Valo 	} else {
2417298e50adSKalle Valo 		local->timer.function = authenticate_timeout;
2418298e50adSKalle Valo 	}
2419298e50adSKalle Valo 	local->timer.expires = jiffies + HZ * 2;
2420298e50adSKalle Valo 	add_timer(&local->timer);
2421298e50adSKalle Valo 	local->authentication_state = AWAITING_RESPONSE;
2422298e50adSKalle Valo } /* end authenticate */
2423298e50adSKalle Valo 
2424298e50adSKalle Valo /*===========================================================================*/
rx_authenticate(ray_dev_t * local,struct rcs __iomem * prcs,unsigned int pkt_addr,int rx_len)2425298e50adSKalle Valo static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs,
2426298e50adSKalle Valo 			    unsigned int pkt_addr, int rx_len)
2427298e50adSKalle Valo {
2428298e50adSKalle Valo 	UCHAR buff[256];
2429298e50adSKalle Valo 	struct ray_rx_msg *msg = (struct ray_rx_msg *) buff;
2430298e50adSKalle Valo 
2431298e50adSKalle Valo 	del_timer(&local->timer);
2432298e50adSKalle Valo 
2433298e50adSKalle Valo 	copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
2434298e50adSKalle Valo 	/* if we are trying to get authenticated */
2435298e50adSKalle Valo 	if (local->sparm.b4.a_network_type == ADHOC) {
2436298e50adSKalle Valo 		pr_debug("ray_cs rx_auth var= %6ph\n", msg->var);
2437298e50adSKalle Valo 		if (msg->var[2] == 1) {
2438298e50adSKalle Valo 			pr_debug("ray_cs Sending authentication response.\n");
2439298e50adSKalle Valo 			if (!build_auth_frame
2440298e50adSKalle Valo 			    (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) {
2441298e50adSKalle Valo 				local->authentication_state = NEED_TO_AUTH;
2442298e50adSKalle Valo 				memcpy(local->auth_id, msg->mac.addr_2,
2443298e50adSKalle Valo 				       ADDRLEN);
2444298e50adSKalle Valo 			}
2445298e50adSKalle Valo 		}
2446298e50adSKalle Valo 	} else { /* Infrastructure network */
2447298e50adSKalle Valo 
2448298e50adSKalle Valo 		if (local->authentication_state == AWAITING_RESPONSE) {
2449298e50adSKalle Valo 			/* Verify authentication sequence #2 and success */
2450298e50adSKalle Valo 			if (msg->var[2] == 2) {
2451298e50adSKalle Valo 				if ((msg->var[3] | msg->var[4]) == 0) {
2452298e50adSKalle Valo 					pr_debug("Authentication successful\n");
2453298e50adSKalle Valo 					local->card_status = CARD_AUTH_COMPLETE;
2454298e50adSKalle Valo 					associate(local);
2455298e50adSKalle Valo 					local->authentication_state =
2456298e50adSKalle Valo 					    AUTHENTICATED;
2457298e50adSKalle Valo 				} else {
2458298e50adSKalle Valo 					pr_debug("Authentication refused\n");
2459298e50adSKalle Valo 					local->card_status = CARD_AUTH_REFUSED;
2460298e50adSKalle Valo 					join_net(&local->timer);
2461298e50adSKalle Valo 					local->authentication_state =
2462298e50adSKalle Valo 					    UNAUTHENTICATED;
2463298e50adSKalle Valo 				}
2464298e50adSKalle Valo 			}
2465298e50adSKalle Valo 		}
2466298e50adSKalle Valo 	}
2467298e50adSKalle Valo 
2468298e50adSKalle Valo } /* end rx_authenticate */
2469298e50adSKalle Valo 
2470298e50adSKalle Valo /*===========================================================================*/
associate(ray_dev_t * local)2471298e50adSKalle Valo static void associate(ray_dev_t *local)
2472298e50adSKalle Valo {
2473298e50adSKalle Valo 	struct ccs __iomem *pccs;
2474298e50adSKalle Valo 	struct pcmcia_device *link = local->finder;
2475298e50adSKalle Valo 	struct net_device *dev = link->priv;
2476298e50adSKalle Valo 	int ccsindex;
2477298e50adSKalle Valo 	if (!(pcmcia_dev_present(link))) {
2478298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs associate - device not present\n");
2479298e50adSKalle Valo 		return;
2480298e50adSKalle Valo 	}
2481298e50adSKalle Valo 	/* If no tx buffers available, return */
2482298e50adSKalle Valo 	if ((ccsindex = get_free_ccs(local)) < 0) {
2483298e50adSKalle Valo /* TBD should never be here but... what if we are? */
2484298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs associate - No free ccs\n");
2485298e50adSKalle Valo 		return;
2486298e50adSKalle Valo 	}
2487298e50adSKalle Valo 	dev_dbg(&link->dev, "ray_cs Starting association with access point\n");
2488298e50adSKalle Valo 	pccs = ccs_base(local) + ccsindex;
2489298e50adSKalle Valo 	/* fill in the CCS */
2490298e50adSKalle Valo 	writeb(CCS_START_ASSOCIATION, &pccs->cmd);
2491298e50adSKalle Valo 	/* Interrupt the firmware to process the command */
2492298e50adSKalle Valo 	if (interrupt_ecf(local, ccsindex)) {
2493298e50adSKalle Valo 		dev_dbg(&link->dev, "ray_cs associate failed - ECF not ready for intr\n");
2494298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
2495298e50adSKalle Valo 
2496298e50adSKalle Valo 		del_timer(&local->timer);
2497298e50adSKalle Valo 		local->timer.expires = jiffies + HZ * 2;
2498298e50adSKalle Valo 		local->timer.function = join_net;
2499298e50adSKalle Valo 		add_timer(&local->timer);
2500298e50adSKalle Valo 		local->card_status = CARD_ASSOC_FAILED;
2501298e50adSKalle Valo 		return;
2502298e50adSKalle Valo 	}
2503298e50adSKalle Valo 	if (!sniffer)
2504298e50adSKalle Valo 		netif_start_queue(dev);
2505298e50adSKalle Valo 
2506298e50adSKalle Valo } /* end associate */
2507298e50adSKalle Valo 
2508298e50adSKalle Valo /*===========================================================================*/
rx_deauthenticate(ray_dev_t * local,struct rcs __iomem * prcs,unsigned int pkt_addr,int rx_len)2509298e50adSKalle Valo static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
2510298e50adSKalle Valo 			      unsigned int pkt_addr, int rx_len)
2511298e50adSKalle Valo {
2512298e50adSKalle Valo /*  UCHAR buff[256];
2513298e50adSKalle Valo     struct ray_rx_msg *msg = (struct ray_rx_msg *) buff;
2514298e50adSKalle Valo */
2515298e50adSKalle Valo 	pr_debug("Deauthentication frame received\n");
2516298e50adSKalle Valo 	local->authentication_state = UNAUTHENTICATED;
2517298e50adSKalle Valo 	/* Need to reauthenticate or rejoin depending on reason code */
2518298e50adSKalle Valo /*  copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
2519298e50adSKalle Valo  */
2520298e50adSKalle Valo }
2521298e50adSKalle Valo 
2522298e50adSKalle Valo /*===========================================================================*/
clear_interrupt(ray_dev_t * local)2523298e50adSKalle Valo static void clear_interrupt(ray_dev_t *local)
2524298e50adSKalle Valo {
2525298e50adSKalle Valo 	writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET);
2526298e50adSKalle Valo }
2527298e50adSKalle Valo 
2528298e50adSKalle Valo /*===========================================================================*/
2529298e50adSKalle Valo #ifdef CONFIG_PROC_FS
2530298e50adSKalle Valo #define MAXDATA (PAGE_SIZE - 80)
2531298e50adSKalle Valo 
2532298e50adSKalle Valo static const char *card_status[] = {
2533298e50adSKalle Valo 	"Card inserted - uninitialized",	/* 0 */
2534298e50adSKalle Valo 	"Card not downloaded",			/* 1 */
2535298e50adSKalle Valo 	"Waiting for download parameters",	/* 2 */
2536298e50adSKalle Valo 	"Card doing acquisition",		/* 3 */
2537298e50adSKalle Valo 	"Acquisition complete",			/* 4 */
2538298e50adSKalle Valo 	"Authentication complete",		/* 5 */
2539298e50adSKalle Valo 	"Association complete",			/* 6 */
2540298e50adSKalle Valo 	"???", "???", "???", "???",		/* 7 8 9 10 undefined */
2541298e50adSKalle Valo 	"Card init error",			/* 11 */
2542298e50adSKalle Valo 	"Download parameters error",		/* 12 */
2543298e50adSKalle Valo 	"???",					/* 13 */
2544298e50adSKalle Valo 	"Acquisition failed",			/* 14 */
2545298e50adSKalle Valo 	"Authentication refused",		/* 15 */
2546298e50adSKalle Valo 	"Association failed"			/* 16 */
2547298e50adSKalle Valo };
2548298e50adSKalle Valo 
2549298e50adSKalle Valo static const char *nettype[] = { "Adhoc", "Infra " };
2550298e50adSKalle Valo static const char *framing[] = { "Encapsulation", "Translation" }
2551298e50adSKalle Valo 
2552298e50adSKalle Valo ;
2553298e50adSKalle Valo /*===========================================================================*/
ray_cs_proc_show(struct seq_file * m,void * v)2554298e50adSKalle Valo static int ray_cs_proc_show(struct seq_file *m, void *v)
2555298e50adSKalle Valo {
2556298e50adSKalle Valo /* Print current values which are not available via other means
2557298e50adSKalle Valo  * eg ifconfig
2558298e50adSKalle Valo  */
2559298e50adSKalle Valo 	int i;
2560298e50adSKalle Valo 	struct pcmcia_device *link;
2561298e50adSKalle Valo 	struct net_device *dev;
2562298e50adSKalle Valo 	ray_dev_t *local;
2563298e50adSKalle Valo 	UCHAR *p;
2564298e50adSKalle Valo 	struct freq_hop_element *pfh;
2565298e50adSKalle Valo 	UCHAR c[33];
2566298e50adSKalle Valo 
2567298e50adSKalle Valo 	link = this_device;
2568298e50adSKalle Valo 	if (!link)
2569298e50adSKalle Valo 		return 0;
2570298e50adSKalle Valo 	dev = (struct net_device *)link->priv;
2571298e50adSKalle Valo 	if (!dev)
2572298e50adSKalle Valo 		return 0;
2573298e50adSKalle Valo 	local = netdev_priv(dev);
2574298e50adSKalle Valo 	if (!local)
2575298e50adSKalle Valo 		return 0;
2576298e50adSKalle Valo 
2577298e50adSKalle Valo 	seq_puts(m, "Raylink Wireless LAN driver status\n");
2578298e50adSKalle Valo 	seq_printf(m, "%s\n", rcsid);
2579298e50adSKalle Valo 	/* build 4 does not report version, and field is 0x55 after memtest */
2580298e50adSKalle Valo 	seq_puts(m, "Firmware version     = ");
2581298e50adSKalle Valo 	if (local->fw_ver == 0x55)
2582298e50adSKalle Valo 		seq_puts(m, "4 - Use dump_cis for more details\n");
2583298e50adSKalle Valo 	else
2584298e50adSKalle Valo 		seq_printf(m, "%2d.%02d.%02d\n",
2585298e50adSKalle Valo 			   local->fw_ver, local->fw_bld, local->fw_var);
2586298e50adSKalle Valo 
2587298e50adSKalle Valo 	for (i = 0; i < 32; i++)
2588298e50adSKalle Valo 		c[i] = local->sparm.b5.a_current_ess_id[i];
2589298e50adSKalle Valo 	c[32] = 0;
2590298e50adSKalle Valo 	seq_printf(m, "%s network ESSID = \"%s\"\n",
2591298e50adSKalle Valo 		   nettype[local->sparm.b5.a_network_type], c);
2592298e50adSKalle Valo 
2593298e50adSKalle Valo 	p = local->bss_id;
2594298e50adSKalle Valo 	seq_printf(m, "BSSID                = %pM\n", p);
2595298e50adSKalle Valo 
2596298e50adSKalle Valo 	seq_printf(m, "Country code         = %d\n",
2597298e50adSKalle Valo 		   local->sparm.b5.a_curr_country_code);
2598298e50adSKalle Valo 
2599298e50adSKalle Valo 	i = local->card_status;
2600298e50adSKalle Valo 	if (i < 0)
2601298e50adSKalle Valo 		i = 10;
2602298e50adSKalle Valo 	if (i > 16)
2603298e50adSKalle Valo 		i = 10;
2604298e50adSKalle Valo 	seq_printf(m, "Card status          = %s\n", card_status[i]);
2605298e50adSKalle Valo 
2606298e50adSKalle Valo 	seq_printf(m, "Framing mode         = %s\n", framing[translate]);
2607298e50adSKalle Valo 
2608298e50adSKalle Valo 	seq_printf(m, "Last pkt signal lvl  = %d\n", local->last_rsl);
2609298e50adSKalle Valo 
2610298e50adSKalle Valo 	if (local->beacon_rxed) {
2611298e50adSKalle Valo 		/* Pull some fields out of last beacon received */
2612298e50adSKalle Valo 		seq_printf(m, "Beacon Interval      = %d Kus\n",
2613298e50adSKalle Valo 			   local->last_bcn.beacon_intvl[0]
2614298e50adSKalle Valo 			   + 256 * local->last_bcn.beacon_intvl[1]);
2615298e50adSKalle Valo 
2616298e50adSKalle Valo 		p = local->last_bcn.elements;
2617298e50adSKalle Valo 		if (p[0] == C_ESSID_ELEMENT_ID)
2618298e50adSKalle Valo 			p += p[1] + 2;
2619298e50adSKalle Valo 		else {
2620298e50adSKalle Valo 			seq_printf(m,
2621298e50adSKalle Valo 				   "Parse beacon failed at essid element id = %d\n",
2622298e50adSKalle Valo 				   p[0]);
2623298e50adSKalle Valo 			return 0;
2624298e50adSKalle Valo 		}
2625298e50adSKalle Valo 
2626298e50adSKalle Valo 		if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) {
2627298e50adSKalle Valo 			seq_puts(m, "Supported rate codes = ");
2628298e50adSKalle Valo 			for (i = 2; i < p[1] + 2; i++)
2629298e50adSKalle Valo 				seq_printf(m, "0x%02x ", p[i]);
2630298e50adSKalle Valo 			seq_putc(m, '\n');
2631298e50adSKalle Valo 			p += p[1] + 2;
2632298e50adSKalle Valo 		} else {
2633298e50adSKalle Valo 			seq_puts(m, "Parse beacon failed at rates element\n");
2634298e50adSKalle Valo 			return 0;
2635298e50adSKalle Valo 		}
2636298e50adSKalle Valo 
2637298e50adSKalle Valo 		if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) {
2638298e50adSKalle Valo 			pfh = (struct freq_hop_element *)p;
2639298e50adSKalle Valo 			seq_printf(m, "Hop dwell            = %d Kus\n",
2640298e50adSKalle Valo 				   pfh->dwell_time[0] +
2641298e50adSKalle Valo 				   256 * pfh->dwell_time[1]);
2642298e50adSKalle Valo 			seq_printf(m, "Hop set              = %d\n",
2643298e50adSKalle Valo 				   pfh->hop_set);
2644298e50adSKalle Valo 			seq_printf(m, "Hop pattern          = %d\n",
2645298e50adSKalle Valo 				   pfh->hop_pattern);
2646298e50adSKalle Valo 			seq_printf(m, "Hop index            = %d\n",
2647298e50adSKalle Valo 				   pfh->hop_index);
2648298e50adSKalle Valo 			p += p[1] + 2;
2649298e50adSKalle Valo 		} else {
2650298e50adSKalle Valo 			seq_puts(m,
2651298e50adSKalle Valo 				 "Parse beacon failed at FH param element\n");
2652298e50adSKalle Valo 			return 0;
2653298e50adSKalle Valo 		}
2654298e50adSKalle Valo 	} else {
2655298e50adSKalle Valo 		seq_puts(m, "No beacons received\n");
2656298e50adSKalle Valo 	}
2657298e50adSKalle Valo 	return 0;
2658298e50adSKalle Valo }
2659298e50adSKalle Valo #endif
2660298e50adSKalle Valo /*===========================================================================*/
build_auth_frame(ray_dev_t * local,UCHAR * dest,int auth_type)2661298e50adSKalle Valo static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
2662298e50adSKalle Valo {
2663298e50adSKalle Valo 	int addr;
2664298e50adSKalle Valo 	struct ccs __iomem *pccs;
2665298e50adSKalle Valo 	struct tx_msg __iomem *ptx;
2666298e50adSKalle Valo 	int ccsindex;
2667298e50adSKalle Valo 
2668298e50adSKalle Valo 	/* If no tx buffers available, return */
2669298e50adSKalle Valo 	if ((ccsindex = get_free_tx_ccs(local)) < 0) {
2670298e50adSKalle Valo 		pr_debug("ray_cs send authenticate - No free tx ccs\n");
2671298e50adSKalle Valo 		return -1;
2672298e50adSKalle Valo 	}
2673298e50adSKalle Valo 
2674298e50adSKalle Valo 	pccs = ccs_base(local) + ccsindex;
2675298e50adSKalle Valo 
2676298e50adSKalle Valo 	/* Address in card space */
2677298e50adSKalle Valo 	addr = TX_BUF_BASE + (ccsindex << 11);
2678298e50adSKalle Valo 	/* fill in the CCS */
2679298e50adSKalle Valo 	writeb(CCS_TX_REQUEST, &pccs->cmd);
2680298e50adSKalle Valo 	writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr);
2681298e50adSKalle Valo 	writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1);
2682298e50adSKalle Valo 	writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length);
2683298e50adSKalle Valo 	writeb(TX_AUTHENTICATE_LENGTH_LSB,
2684298e50adSKalle Valo 	       pccs->var.tx_request.tx_data_length + 1);
2685298e50adSKalle Valo 	writeb(0, &pccs->var.tx_request.pow_sav_mode);
2686298e50adSKalle Valo 
2687298e50adSKalle Valo 	ptx = local->sram + addr;
2688298e50adSKalle Valo 	/* fill in the mac header */
2689298e50adSKalle Valo 	writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1);
2690298e50adSKalle Valo 	writeb(0, &ptx->mac.frame_ctl_2);
2691298e50adSKalle Valo 
2692298e50adSKalle Valo 	memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN);
2693298e50adSKalle Valo 	memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN);
2694298e50adSKalle Valo 	memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
2695298e50adSKalle Valo 
2696298e50adSKalle Valo 	/* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */
2697298e50adSKalle Valo 	memset_io(ptx->var, 0, 6);
2698298e50adSKalle Valo 	writeb(auth_type & 0xff, ptx->var + 2);
2699298e50adSKalle Valo 
2700298e50adSKalle Valo 	/* Interrupt the firmware to process the command */
2701298e50adSKalle Valo 	if (interrupt_ecf(local, ccsindex)) {
2702298e50adSKalle Valo 		pr_debug(
2703298e50adSKalle Valo 		      "ray_cs send authentication request failed - ECF not ready for intr\n");
2704298e50adSKalle Valo 		writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
2705298e50adSKalle Valo 		return -1;
2706298e50adSKalle Valo 	}
2707298e50adSKalle Valo 	return 0;
2708298e50adSKalle Valo } /* End build_auth_frame */
2709298e50adSKalle Valo 
2710298e50adSKalle Valo /*===========================================================================*/
2711298e50adSKalle Valo #ifdef CONFIG_PROC_FS
ray_cs_essid_proc_write(struct file * file,const char __user * buffer,size_t count,loff_t * pos)2712298e50adSKalle Valo static ssize_t ray_cs_essid_proc_write(struct file *file,
2713298e50adSKalle Valo 		const char __user *buffer, size_t count, loff_t *pos)
2714298e50adSKalle Valo {
2715298e50adSKalle Valo 	static char proc_essid[33];
2716298e50adSKalle Valo 	unsigned int len = count;
2717298e50adSKalle Valo 
2718298e50adSKalle Valo 	if (len > 32)
2719298e50adSKalle Valo 		len = 32;
2720298e50adSKalle Valo 	memset(proc_essid, 0, 33);
2721298e50adSKalle Valo 	if (copy_from_user(proc_essid, buffer, len))
2722298e50adSKalle Valo 		return -EFAULT;
2723298e50adSKalle Valo 	essid = proc_essid;
2724298e50adSKalle Valo 	return count;
2725298e50adSKalle Valo }
2726298e50adSKalle Valo 
2727298e50adSKalle Valo static const struct proc_ops ray_cs_essid_proc_ops = {
2728298e50adSKalle Valo 	.proc_write	= ray_cs_essid_proc_write,
2729298e50adSKalle Valo 	.proc_lseek	= noop_llseek,
2730298e50adSKalle Valo };
2731298e50adSKalle Valo 
int_proc_write(struct file * file,const char __user * buffer,size_t count,loff_t * pos)2732298e50adSKalle Valo static ssize_t int_proc_write(struct file *file, const char __user *buffer,
2733298e50adSKalle Valo 			      size_t count, loff_t *pos)
2734298e50adSKalle Valo {
2735298e50adSKalle Valo 	static char proc_number[10];
2736298e50adSKalle Valo 	char *p;
2737298e50adSKalle Valo 	int nr, len;
2738298e50adSKalle Valo 
2739298e50adSKalle Valo 	if (!count)
2740298e50adSKalle Valo 		return 0;
2741298e50adSKalle Valo 
2742298e50adSKalle Valo 	if (count > 9)
2743298e50adSKalle Valo 		return -EINVAL;
2744298e50adSKalle Valo 	if (copy_from_user(proc_number, buffer, count))
2745298e50adSKalle Valo 		return -EFAULT;
2746298e50adSKalle Valo 	p = proc_number;
2747298e50adSKalle Valo 	nr = 0;
2748298e50adSKalle Valo 	len = count;
2749298e50adSKalle Valo 	do {
2750298e50adSKalle Valo 		unsigned int c = *p - '0';
2751298e50adSKalle Valo 		if (c > 9)
2752298e50adSKalle Valo 			return -EINVAL;
2753298e50adSKalle Valo 		nr = nr * 10 + c;
2754298e50adSKalle Valo 		p++;
2755298e50adSKalle Valo 	} while (--len);
2756298e50adSKalle Valo 	*(int *)pde_data(file_inode(file)) = nr;
2757298e50adSKalle Valo 	return count;
2758298e50adSKalle Valo }
2759298e50adSKalle Valo 
2760298e50adSKalle Valo static const struct proc_ops int_proc_ops = {
2761298e50adSKalle Valo 	.proc_write	= int_proc_write,
2762298e50adSKalle Valo 	.proc_lseek	= noop_llseek,
2763298e50adSKalle Valo };
2764298e50adSKalle Valo #endif
2765298e50adSKalle Valo 
2766298e50adSKalle Valo static const struct pcmcia_device_id ray_ids[] = {
2767298e50adSKalle Valo 	PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000),
2768298e50adSKalle Valo 	PCMCIA_DEVICE_NULL,
2769298e50adSKalle Valo };
2770298e50adSKalle Valo 
2771298e50adSKalle Valo MODULE_DEVICE_TABLE(pcmcia, ray_ids);
2772298e50adSKalle Valo 
2773298e50adSKalle Valo static struct pcmcia_driver ray_driver = {
2774298e50adSKalle Valo 	.owner = THIS_MODULE,
2775298e50adSKalle Valo 	.name = "ray_cs",
2776298e50adSKalle Valo 	.probe = ray_probe,
2777298e50adSKalle Valo 	.remove = ray_detach,
2778298e50adSKalle Valo 	.id_table = ray_ids,
2779298e50adSKalle Valo 	.suspend = ray_suspend,
2780298e50adSKalle Valo 	.resume = ray_resume,
2781298e50adSKalle Valo };
2782298e50adSKalle Valo 
init_ray_cs(void)2783298e50adSKalle Valo static int __init init_ray_cs(void)
2784298e50adSKalle Valo {
2785298e50adSKalle Valo 	int rc;
2786298e50adSKalle Valo 
2787298e50adSKalle Valo 	pr_debug("%s\n", rcsid);
2788298e50adSKalle Valo 	rc = pcmcia_register_driver(&ray_driver);
2789298e50adSKalle Valo 	pr_debug("raylink init_module register_pcmcia_driver returns 0x%x\n",
2790298e50adSKalle Valo 	      rc);
2791298e50adSKalle Valo 	if (rc)
2792298e50adSKalle Valo 		return rc;
2793298e50adSKalle Valo 
2794298e50adSKalle Valo #ifdef CONFIG_PROC_FS
2795298e50adSKalle Valo 	proc_mkdir("driver/ray_cs", NULL);
2796298e50adSKalle Valo 
2797298e50adSKalle Valo 	proc_create_single("driver/ray_cs/ray_cs", 0, NULL, ray_cs_proc_show);
2798298e50adSKalle Valo 	proc_create("driver/ray_cs/essid", 0200, NULL, &ray_cs_essid_proc_ops);
2799298e50adSKalle Valo 	proc_create_data("driver/ray_cs/net_type", 0200, NULL, &int_proc_ops,
2800298e50adSKalle Valo 			 &net_type);
2801298e50adSKalle Valo 	proc_create_data("driver/ray_cs/translate", 0200, NULL, &int_proc_ops,
2802298e50adSKalle Valo 			 &translate);
2803298e50adSKalle Valo #endif
2804298e50adSKalle Valo 	translate = !!translate;
2805298e50adSKalle Valo 	return 0;
2806298e50adSKalle Valo } /* init_ray_cs */
2807298e50adSKalle Valo 
2808298e50adSKalle Valo /*===========================================================================*/
2809298e50adSKalle Valo 
exit_ray_cs(void)2810298e50adSKalle Valo static void __exit exit_ray_cs(void)
2811298e50adSKalle Valo {
2812298e50adSKalle Valo 	pr_debug("ray_cs: cleanup_module\n");
2813298e50adSKalle Valo 
2814298e50adSKalle Valo #ifdef CONFIG_PROC_FS
2815298e50adSKalle Valo 	remove_proc_subtree("driver/ray_cs", NULL);
2816298e50adSKalle Valo #endif
2817298e50adSKalle Valo 
2818298e50adSKalle Valo 	pcmcia_unregister_driver(&ray_driver);
2819298e50adSKalle Valo } /* exit_ray_cs */
2820298e50adSKalle Valo 
2821298e50adSKalle Valo module_init(init_ray_cs);
2822298e50adSKalle Valo module_exit(exit_ray_cs);
2823298e50adSKalle Valo 
2824298e50adSKalle Valo /*===========================================================================*/
2825