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