xref: /OK3568_Linux_fs/kernel/drivers/tty/ipwireless/hardware.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * IPWireless 3G PCMCIA Network Driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Original code
6*4882a593Smuzhiyun  *   by Stephen Blackheath <stephen@blacksapphire.com>,
7*4882a593Smuzhiyun  *      Ben Martel <benm@symmetric.co.nz>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Copyrighted as follows:
10*4882a593Smuzhiyun  *   Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * Various driver changes and rewrites, port to new kernels
13*4882a593Smuzhiyun  *   Copyright (C) 2006-2007 Jiri Kosina
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * Misc code cleanups and updates
16*4882a593Smuzhiyun  *   Copyright (C) 2007 David Sterba
17*4882a593Smuzhiyun  */
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <linux/interrupt.h>
20*4882a593Smuzhiyun #include <linux/io.h>
21*4882a593Smuzhiyun #include <linux/irq.h>
22*4882a593Smuzhiyun #include <linux/kernel.h>
23*4882a593Smuzhiyun #include <linux/list.h>
24*4882a593Smuzhiyun #include <linux/slab.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #include "hardware.h"
27*4882a593Smuzhiyun #include "setup_protocol.h"
28*4882a593Smuzhiyun #include "network.h"
29*4882a593Smuzhiyun #include "main.h"
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static void ipw_send_setup_packet(struct ipw_hardware *hw);
32*4882a593Smuzhiyun static void handle_received_SETUP_packet(struct ipw_hardware *ipw,
33*4882a593Smuzhiyun 					 unsigned int address,
34*4882a593Smuzhiyun 					 const unsigned char *data, int len,
35*4882a593Smuzhiyun 					 int is_last);
36*4882a593Smuzhiyun static void ipwireless_setup_timer(struct timer_list *t);
37*4882a593Smuzhiyun static void handle_received_CTRL_packet(struct ipw_hardware *hw,
38*4882a593Smuzhiyun 		unsigned int channel_idx, const unsigned char *data, int len);
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /*#define TIMING_DIAGNOSTICS*/
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #ifdef TIMING_DIAGNOSTICS
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun static struct timing_stats {
45*4882a593Smuzhiyun 	unsigned long last_report_time;
46*4882a593Smuzhiyun 	unsigned long read_time;
47*4882a593Smuzhiyun 	unsigned long write_time;
48*4882a593Smuzhiyun 	unsigned long read_bytes;
49*4882a593Smuzhiyun 	unsigned long write_bytes;
50*4882a593Smuzhiyun 	unsigned long start_time;
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
start_timing(void)53*4882a593Smuzhiyun static void start_timing(void)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	timing_stats.start_time = jiffies;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
end_read_timing(unsigned length)58*4882a593Smuzhiyun static void end_read_timing(unsigned length)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	timing_stats.read_time += (jiffies - start_time);
61*4882a593Smuzhiyun 	timing_stats.read_bytes += length + 2;
62*4882a593Smuzhiyun 	report_timing();
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun 
end_write_timing(unsigned length)65*4882a593Smuzhiyun static void end_write_timing(unsigned length)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	timing_stats.write_time += (jiffies - start_time);
68*4882a593Smuzhiyun 	timing_stats.write_bytes += length + 2;
69*4882a593Smuzhiyun 	report_timing();
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
report_timing(void)72*4882a593Smuzhiyun static void report_timing(void)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun 	unsigned long since = jiffies - timing_stats.last_report_time;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	/* If it's been more than one second... */
77*4882a593Smuzhiyun 	if (since >= HZ) {
78*4882a593Smuzhiyun 		int first = (timing_stats.last_report_time == 0);
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 		timing_stats.last_report_time = jiffies;
81*4882a593Smuzhiyun 		if (!first)
82*4882a593Smuzhiyun 			printk(KERN_INFO IPWIRELESS_PCCARD_NAME
83*4882a593Smuzhiyun 			       ": %u us elapsed - read %lu bytes in %u us, wrote %lu bytes in %u us\n",
84*4882a593Smuzhiyun 			       jiffies_to_usecs(since),
85*4882a593Smuzhiyun 			       timing_stats.read_bytes,
86*4882a593Smuzhiyun 			       jiffies_to_usecs(timing_stats.read_time),
87*4882a593Smuzhiyun 			       timing_stats.write_bytes,
88*4882a593Smuzhiyun 			       jiffies_to_usecs(timing_stats.write_time));
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 		timing_stats.read_time = 0;
91*4882a593Smuzhiyun 		timing_stats.write_time = 0;
92*4882a593Smuzhiyun 		timing_stats.read_bytes = 0;
93*4882a593Smuzhiyun 		timing_stats.write_bytes = 0;
94*4882a593Smuzhiyun 	}
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun #else
start_timing(void)97*4882a593Smuzhiyun static void start_timing(void) { }
end_read_timing(unsigned length)98*4882a593Smuzhiyun static void end_read_timing(unsigned length) { }
end_write_timing(unsigned length)99*4882a593Smuzhiyun static void end_write_timing(unsigned length) { }
100*4882a593Smuzhiyun #endif
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /* Imported IPW definitions */
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun #define LL_MTU_V1 318
105*4882a593Smuzhiyun #define LL_MTU_V2 250
106*4882a593Smuzhiyun #define LL_MTU_MAX (LL_MTU_V1 > LL_MTU_V2 ? LL_MTU_V1 : LL_MTU_V2)
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun #define PRIO_DATA  2
109*4882a593Smuzhiyun #define PRIO_CTRL  1
110*4882a593Smuzhiyun #define PRIO_SETUP 0
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun /* Addresses */
113*4882a593Smuzhiyun #define ADDR_SETUP_PROT 0
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun /* Protocol ids */
116*4882a593Smuzhiyun enum {
117*4882a593Smuzhiyun 	/* Identifier for the Com Data protocol */
118*4882a593Smuzhiyun 	TL_PROTOCOLID_COM_DATA = 0,
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	/* Identifier for the Com Control protocol */
121*4882a593Smuzhiyun 	TL_PROTOCOLID_COM_CTRL = 1,
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	/* Identifier for the Setup protocol */
124*4882a593Smuzhiyun 	TL_PROTOCOLID_SETUP = 2
125*4882a593Smuzhiyun };
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun /* Number of bytes in NL packet header (cannot do
128*4882a593Smuzhiyun  * sizeof(nl_packet_header) since it's a bitfield) */
129*4882a593Smuzhiyun #define NL_FIRST_PACKET_HEADER_SIZE        3
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun /* Number of bytes in NL packet header (cannot do
132*4882a593Smuzhiyun  * sizeof(nl_packet_header) since it's a bitfield) */
133*4882a593Smuzhiyun #define NL_FOLLOWING_PACKET_HEADER_SIZE    1
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun struct nl_first_packet_header {
136*4882a593Smuzhiyun 	unsigned char protocol:3;
137*4882a593Smuzhiyun 	unsigned char address:3;
138*4882a593Smuzhiyun 	unsigned char packet_rank:2;
139*4882a593Smuzhiyun 	unsigned char length_lsb;
140*4882a593Smuzhiyun 	unsigned char length_msb;
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun struct nl_packet_header {
144*4882a593Smuzhiyun 	unsigned char protocol:3;
145*4882a593Smuzhiyun 	unsigned char address:3;
146*4882a593Smuzhiyun 	unsigned char packet_rank:2;
147*4882a593Smuzhiyun };
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun /* Value of 'packet_rank' above */
150*4882a593Smuzhiyun #define NL_INTERMEDIATE_PACKET    0x0
151*4882a593Smuzhiyun #define NL_LAST_PACKET            0x1
152*4882a593Smuzhiyun #define NL_FIRST_PACKET           0x2
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun union nl_packet {
155*4882a593Smuzhiyun 	/* Network packet header of the first packet (a special case) */
156*4882a593Smuzhiyun 	struct nl_first_packet_header hdr_first;
157*4882a593Smuzhiyun 	/* Network packet header of the following packets (if any) */
158*4882a593Smuzhiyun 	struct nl_packet_header hdr;
159*4882a593Smuzhiyun 	/* Complete network packet (header + data) */
160*4882a593Smuzhiyun 	unsigned char rawpkt[LL_MTU_MAX];
161*4882a593Smuzhiyun } __attribute__ ((__packed__));
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun #define HW_VERSION_UNKNOWN -1
164*4882a593Smuzhiyun #define HW_VERSION_1 1
165*4882a593Smuzhiyun #define HW_VERSION_2 2
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun /* IPW I/O ports */
168*4882a593Smuzhiyun #define IOIER 0x00		/* Interrupt Enable Register */
169*4882a593Smuzhiyun #define IOIR  0x02		/* Interrupt Source/ACK register */
170*4882a593Smuzhiyun #define IODCR 0x04		/* Data Control Register */
171*4882a593Smuzhiyun #define IODRR 0x06		/* Data Read Register */
172*4882a593Smuzhiyun #define IODWR 0x08		/* Data Write Register */
173*4882a593Smuzhiyun #define IOESR 0x0A		/* Embedded Driver Status Register */
174*4882a593Smuzhiyun #define IORXR 0x0C		/* Rx Fifo Register (Host to Embedded) */
175*4882a593Smuzhiyun #define IOTXR 0x0E		/* Tx Fifo Register (Embedded to Host) */
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun /* I/O ports and bit definitions for version 1 of the hardware */
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun /* IER bits*/
180*4882a593Smuzhiyun #define IER_RXENABLED   0x1
181*4882a593Smuzhiyun #define IER_TXENABLED   0x2
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun /* ISR bits */
184*4882a593Smuzhiyun #define IR_RXINTR       0x1
185*4882a593Smuzhiyun #define IR_TXINTR       0x2
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun /* DCR bits */
188*4882a593Smuzhiyun #define DCR_RXDONE      0x1
189*4882a593Smuzhiyun #define DCR_TXDONE      0x2
190*4882a593Smuzhiyun #define DCR_RXRESET     0x4
191*4882a593Smuzhiyun #define DCR_TXRESET     0x8
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun /* I/O ports and bit definitions for version 2 of the hardware */
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun struct MEMCCR {
196*4882a593Smuzhiyun 	unsigned short reg_config_option;	/* PCCOR: Configuration Option Register */
197*4882a593Smuzhiyun 	unsigned short reg_config_and_status;	/* PCCSR: Configuration and Status Register */
198*4882a593Smuzhiyun 	unsigned short reg_pin_replacement;	/* PCPRR: Pin Replacemant Register */
199*4882a593Smuzhiyun 	unsigned short reg_socket_and_copy;	/* PCSCR: Socket and Copy Register */
200*4882a593Smuzhiyun 	unsigned short reg_ext_status;		/* PCESR: Extendend Status Register */
201*4882a593Smuzhiyun 	unsigned short reg_io_base;		/* PCIOB: I/O Base Register */
202*4882a593Smuzhiyun };
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun struct MEMINFREG {
205*4882a593Smuzhiyun 	unsigned short memreg_tx_old;	/* TX Register (R/W) */
206*4882a593Smuzhiyun 	unsigned short pad1;
207*4882a593Smuzhiyun 	unsigned short memreg_rx_done;	/* RXDone Register (R/W) */
208*4882a593Smuzhiyun 	unsigned short pad2;
209*4882a593Smuzhiyun 	unsigned short memreg_rx;	/* RX Register (R/W) */
210*4882a593Smuzhiyun 	unsigned short pad3;
211*4882a593Smuzhiyun 	unsigned short memreg_pc_interrupt_ack;	/* PC intr Ack Register (W) */
212*4882a593Smuzhiyun 	unsigned short pad4;
213*4882a593Smuzhiyun 	unsigned long memreg_card_present;/* Mask for Host to check (R) for
214*4882a593Smuzhiyun 					   * CARD_PRESENT_VALUE */
215*4882a593Smuzhiyun 	unsigned short memreg_tx_new;	/* TX2 (new) Register (R/W) */
216*4882a593Smuzhiyun };
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun #define CARD_PRESENT_VALUE (0xBEEFCAFEUL)
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun #define MEMTX_TX                       0x0001
221*4882a593Smuzhiyun #define MEMRX_RX                       0x0001
222*4882a593Smuzhiyun #define MEMRX_RX_DONE                  0x0001
223*4882a593Smuzhiyun #define MEMRX_PCINTACKK                0x0001
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun #define NL_NUM_OF_PRIORITIES       3
226*4882a593Smuzhiyun #define NL_NUM_OF_PROTOCOLS        3
227*4882a593Smuzhiyun #define NL_NUM_OF_ADDRESSES        NO_OF_IPW_CHANNELS
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun struct ipw_hardware {
230*4882a593Smuzhiyun 	unsigned int base_port;
231*4882a593Smuzhiyun 	short hw_version;
232*4882a593Smuzhiyun 	unsigned short ll_mtu;
233*4882a593Smuzhiyun 	spinlock_t lock;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	int initializing;
236*4882a593Smuzhiyun 	int init_loops;
237*4882a593Smuzhiyun 	struct timer_list setup_timer;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	/* Flag if hw is ready to send next packet */
240*4882a593Smuzhiyun 	int tx_ready;
241*4882a593Smuzhiyun 	/* Count of pending packets to be sent */
242*4882a593Smuzhiyun 	int tx_queued;
243*4882a593Smuzhiyun 	struct list_head tx_queue[NL_NUM_OF_PRIORITIES];
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	int rx_bytes_queued;
246*4882a593Smuzhiyun 	struct list_head rx_queue;
247*4882a593Smuzhiyun 	/* Pool of rx_packet structures that are not currently used. */
248*4882a593Smuzhiyun 	struct list_head rx_pool;
249*4882a593Smuzhiyun 	int rx_pool_size;
250*4882a593Smuzhiyun 	/* True if reception of data is blocked while userspace processes it. */
251*4882a593Smuzhiyun 	int blocking_rx;
252*4882a593Smuzhiyun 	/* True if there is RX data ready on the hardware. */
253*4882a593Smuzhiyun 	int rx_ready;
254*4882a593Smuzhiyun 	unsigned short last_memtx_serial;
255*4882a593Smuzhiyun 	/*
256*4882a593Smuzhiyun 	 * Newer versions of the V2 card firmware send serial numbers in the
257*4882a593Smuzhiyun 	 * MemTX register. 'serial_number_detected' is set true when we detect
258*4882a593Smuzhiyun 	 * a non-zero serial number (indicating the new firmware).  Thereafter,
259*4882a593Smuzhiyun 	 * the driver can safely ignore the Timer Recovery re-sends to avoid
260*4882a593Smuzhiyun 	 * out-of-sync problems.
261*4882a593Smuzhiyun 	 */
262*4882a593Smuzhiyun 	int serial_number_detected;
263*4882a593Smuzhiyun 	struct work_struct work_rx;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	/* True if we are to send the set-up data to the hardware. */
266*4882a593Smuzhiyun 	int to_setup;
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	/* Card has been removed */
269*4882a593Smuzhiyun 	int removed;
270*4882a593Smuzhiyun 	/* Saved irq value when we disable the interrupt. */
271*4882a593Smuzhiyun 	int irq;
272*4882a593Smuzhiyun 	/* True if this driver is shutting down. */
273*4882a593Smuzhiyun 	int shutting_down;
274*4882a593Smuzhiyun 	/* Modem control lines */
275*4882a593Smuzhiyun 	unsigned int control_lines[NL_NUM_OF_ADDRESSES];
276*4882a593Smuzhiyun 	struct ipw_rx_packet *packet_assembler[NL_NUM_OF_ADDRESSES];
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	struct tasklet_struct tasklet;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	/* The handle for the network layer, for the sending of events to it. */
281*4882a593Smuzhiyun 	struct ipw_network *network;
282*4882a593Smuzhiyun 	struct MEMINFREG __iomem *memory_info_regs;
283*4882a593Smuzhiyun 	struct MEMCCR __iomem *memregs_CCR;
284*4882a593Smuzhiyun 	void (*reboot_callback) (void *data);
285*4882a593Smuzhiyun 	void *reboot_callback_data;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	unsigned short __iomem *memreg_tx;
288*4882a593Smuzhiyun };
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun /*
291*4882a593Smuzhiyun  * Packet info structure for tx packets.
292*4882a593Smuzhiyun  * Note: not all the fields defined here are required for all protocols
293*4882a593Smuzhiyun  */
294*4882a593Smuzhiyun struct ipw_tx_packet {
295*4882a593Smuzhiyun 	struct list_head queue;
296*4882a593Smuzhiyun 	/* channel idx + 1 */
297*4882a593Smuzhiyun 	unsigned char dest_addr;
298*4882a593Smuzhiyun 	/* SETUP, CTRL or DATA */
299*4882a593Smuzhiyun 	unsigned char protocol;
300*4882a593Smuzhiyun 	/* Length of data block, which starts at the end of this structure */
301*4882a593Smuzhiyun 	unsigned short length;
302*4882a593Smuzhiyun 	/* Sending state */
303*4882a593Smuzhiyun 	/* Offset of where we've sent up to so far */
304*4882a593Smuzhiyun 	unsigned long offset;
305*4882a593Smuzhiyun 	/* Count of packet fragments, starting at 0 */
306*4882a593Smuzhiyun 	int fragment_count;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	/* Called after packet is sent and before is freed */
309*4882a593Smuzhiyun 	void (*packet_callback) (void *cb_data, unsigned int packet_length);
310*4882a593Smuzhiyun 	void *callback_data;
311*4882a593Smuzhiyun };
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun /* Signals from DTE */
314*4882a593Smuzhiyun #define COMCTRL_RTS	0
315*4882a593Smuzhiyun #define COMCTRL_DTR	1
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun /* Signals from DCE */
318*4882a593Smuzhiyun #define COMCTRL_CTS	2
319*4882a593Smuzhiyun #define COMCTRL_DCD	3
320*4882a593Smuzhiyun #define COMCTRL_DSR	4
321*4882a593Smuzhiyun #define COMCTRL_RI	5
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun struct ipw_control_packet_body {
324*4882a593Smuzhiyun 	/* DTE signal or DCE signal */
325*4882a593Smuzhiyun 	unsigned char sig_no;
326*4882a593Smuzhiyun 	/* 0: set signal, 1: clear signal */
327*4882a593Smuzhiyun 	unsigned char value;
328*4882a593Smuzhiyun } __attribute__ ((__packed__));
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun struct ipw_control_packet {
331*4882a593Smuzhiyun 	struct ipw_tx_packet header;
332*4882a593Smuzhiyun 	struct ipw_control_packet_body body;
333*4882a593Smuzhiyun };
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun struct ipw_rx_packet {
336*4882a593Smuzhiyun 	struct list_head queue;
337*4882a593Smuzhiyun 	unsigned int capacity;
338*4882a593Smuzhiyun 	unsigned int length;
339*4882a593Smuzhiyun 	unsigned int protocol;
340*4882a593Smuzhiyun 	unsigned int channel_idx;
341*4882a593Smuzhiyun };
342*4882a593Smuzhiyun 
data_type(const unsigned char * buf,unsigned length)343*4882a593Smuzhiyun static char *data_type(const unsigned char *buf, unsigned length)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	struct nl_packet_header *hdr = (struct nl_packet_header *) buf;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	if (length == 0)
348*4882a593Smuzhiyun 		return "     ";
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	if (hdr->packet_rank & NL_FIRST_PACKET) {
351*4882a593Smuzhiyun 		switch (hdr->protocol) {
352*4882a593Smuzhiyun 		case TL_PROTOCOLID_COM_DATA:	return "DATA ";
353*4882a593Smuzhiyun 		case TL_PROTOCOLID_COM_CTRL:	return "CTRL ";
354*4882a593Smuzhiyun 		case TL_PROTOCOLID_SETUP:	return "SETUP";
355*4882a593Smuzhiyun 		default: return "???? ";
356*4882a593Smuzhiyun 		}
357*4882a593Smuzhiyun 	} else
358*4882a593Smuzhiyun 		return "     ";
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun #define DUMP_MAX_BYTES 64
362*4882a593Smuzhiyun 
dump_data_bytes(const char * type,const unsigned char * data,unsigned length)363*4882a593Smuzhiyun static void dump_data_bytes(const char *type, const unsigned char *data,
364*4882a593Smuzhiyun 			    unsigned length)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	char prefix[56];
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	sprintf(prefix, IPWIRELESS_PCCARD_NAME ": %s %s ",
369*4882a593Smuzhiyun 			type, data_type(data, length));
370*4882a593Smuzhiyun 	print_hex_dump_bytes(prefix, 0, (void *)data,
371*4882a593Smuzhiyun 			length < DUMP_MAX_BYTES ? length : DUMP_MAX_BYTES);
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun 
swap_packet_bitfield_to_le(unsigned char * data)374*4882a593Smuzhiyun static void swap_packet_bitfield_to_le(unsigned char *data)
375*4882a593Smuzhiyun {
376*4882a593Smuzhiyun #ifdef __BIG_ENDIAN_BITFIELD
377*4882a593Smuzhiyun 	unsigned char tmp = *data, ret = 0;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	/*
380*4882a593Smuzhiyun 	 * transform bits from aa.bbb.ccc to ccc.bbb.aa
381*4882a593Smuzhiyun 	 */
382*4882a593Smuzhiyun 	ret |= (tmp & 0xc0) >> 6;
383*4882a593Smuzhiyun 	ret |= (tmp & 0x38) >> 1;
384*4882a593Smuzhiyun 	ret |= (tmp & 0x07) << 5;
385*4882a593Smuzhiyun 	*data = ret & 0xff;
386*4882a593Smuzhiyun #endif
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun 
swap_packet_bitfield_from_le(unsigned char * data)389*4882a593Smuzhiyun static void swap_packet_bitfield_from_le(unsigned char *data)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun #ifdef __BIG_ENDIAN_BITFIELD
392*4882a593Smuzhiyun 	unsigned char tmp = *data, ret = 0;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	/*
395*4882a593Smuzhiyun 	 * transform bits from ccc.bbb.aa to aa.bbb.ccc
396*4882a593Smuzhiyun 	 */
397*4882a593Smuzhiyun 	ret |= (tmp & 0xe0) >> 5;
398*4882a593Smuzhiyun 	ret |= (tmp & 0x1c) << 1;
399*4882a593Smuzhiyun 	ret |= (tmp & 0x03) << 6;
400*4882a593Smuzhiyun 	*data = ret & 0xff;
401*4882a593Smuzhiyun #endif
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
do_send_fragment(struct ipw_hardware * hw,unsigned char * data,unsigned length)404*4882a593Smuzhiyun static void do_send_fragment(struct ipw_hardware *hw, unsigned char *data,
405*4882a593Smuzhiyun 			    unsigned length)
406*4882a593Smuzhiyun {
407*4882a593Smuzhiyun 	unsigned i;
408*4882a593Smuzhiyun 	unsigned long flags;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	start_timing();
411*4882a593Smuzhiyun 	BUG_ON(length > hw->ll_mtu);
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	if (ipwireless_debug)
414*4882a593Smuzhiyun 		dump_data_bytes("send", data, length);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	spin_lock_irqsave(&hw->lock, flags);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	hw->tx_ready = 0;
419*4882a593Smuzhiyun 	swap_packet_bitfield_to_le(data);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	if (hw->hw_version == HW_VERSION_1) {
422*4882a593Smuzhiyun 		outw((unsigned short) length, hw->base_port + IODWR);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 		for (i = 0; i < length; i += 2) {
425*4882a593Smuzhiyun 			unsigned short d = data[i];
426*4882a593Smuzhiyun 			__le16 raw_data;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 			if (i + 1 < length)
429*4882a593Smuzhiyun 				d |= data[i + 1] << 8;
430*4882a593Smuzhiyun 			raw_data = cpu_to_le16(d);
431*4882a593Smuzhiyun 			outw(raw_data, hw->base_port + IODWR);
432*4882a593Smuzhiyun 		}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 		outw(DCR_TXDONE, hw->base_port + IODCR);
435*4882a593Smuzhiyun 	} else if (hw->hw_version == HW_VERSION_2) {
436*4882a593Smuzhiyun 		outw((unsigned short) length, hw->base_port);
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 		for (i = 0; i < length; i += 2) {
439*4882a593Smuzhiyun 			unsigned short d = data[i];
440*4882a593Smuzhiyun 			__le16 raw_data;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 			if (i + 1 < length)
443*4882a593Smuzhiyun 				d |= data[i + 1] << 8;
444*4882a593Smuzhiyun 			raw_data = cpu_to_le16(d);
445*4882a593Smuzhiyun 			outw(raw_data, hw->base_port);
446*4882a593Smuzhiyun 		}
447*4882a593Smuzhiyun 		while ((i & 3) != 2) {
448*4882a593Smuzhiyun 			outw((unsigned short) 0xDEAD, hw->base_port);
449*4882a593Smuzhiyun 			i += 2;
450*4882a593Smuzhiyun 		}
451*4882a593Smuzhiyun 		writew(MEMRX_RX, &hw->memory_info_regs->memreg_rx);
452*4882a593Smuzhiyun 	}
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	spin_unlock_irqrestore(&hw->lock, flags);
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	end_write_timing(length);
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun 
do_send_packet(struct ipw_hardware * hw,struct ipw_tx_packet * packet)459*4882a593Smuzhiyun static void do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet)
460*4882a593Smuzhiyun {
461*4882a593Smuzhiyun 	unsigned short fragment_data_len;
462*4882a593Smuzhiyun 	unsigned short data_left = packet->length - packet->offset;
463*4882a593Smuzhiyun 	unsigned short header_size;
464*4882a593Smuzhiyun 	union nl_packet pkt;
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	header_size =
467*4882a593Smuzhiyun 	    (packet->fragment_count == 0)
468*4882a593Smuzhiyun 	    ? NL_FIRST_PACKET_HEADER_SIZE
469*4882a593Smuzhiyun 	    : NL_FOLLOWING_PACKET_HEADER_SIZE;
470*4882a593Smuzhiyun 	fragment_data_len = hw->ll_mtu - header_size;
471*4882a593Smuzhiyun 	if (data_left < fragment_data_len)
472*4882a593Smuzhiyun 		fragment_data_len = data_left;
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun 	/*
475*4882a593Smuzhiyun 	 * hdr_first is now in machine bitfield order, which will be swapped
476*4882a593Smuzhiyun 	 * to le just before it goes to hw
477*4882a593Smuzhiyun 	 */
478*4882a593Smuzhiyun 	pkt.hdr_first.protocol = packet->protocol;
479*4882a593Smuzhiyun 	pkt.hdr_first.address = packet->dest_addr;
480*4882a593Smuzhiyun 	pkt.hdr_first.packet_rank = 0;
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	/* First packet? */
483*4882a593Smuzhiyun 	if (packet->fragment_count == 0) {
484*4882a593Smuzhiyun 		pkt.hdr_first.packet_rank |= NL_FIRST_PACKET;
485*4882a593Smuzhiyun 		pkt.hdr_first.length_lsb = (unsigned char) packet->length;
486*4882a593Smuzhiyun 		pkt.hdr_first.length_msb =
487*4882a593Smuzhiyun 			(unsigned char) (packet->length >> 8);
488*4882a593Smuzhiyun 	}
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	memcpy(pkt.rawpkt + header_size,
491*4882a593Smuzhiyun 	       ((unsigned char *) packet) + sizeof(struct ipw_tx_packet) +
492*4882a593Smuzhiyun 	       packet->offset, fragment_data_len);
493*4882a593Smuzhiyun 	packet->offset += fragment_data_len;
494*4882a593Smuzhiyun 	packet->fragment_count++;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	/* Last packet? (May also be first packet.) */
497*4882a593Smuzhiyun 	if (packet->offset == packet->length)
498*4882a593Smuzhiyun 		pkt.hdr_first.packet_rank |= NL_LAST_PACKET;
499*4882a593Smuzhiyun 	do_send_fragment(hw, pkt.rawpkt, header_size + fragment_data_len);
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	/* If this packet has unsent data, then re-queue it. */
502*4882a593Smuzhiyun 	if (packet->offset < packet->length) {
503*4882a593Smuzhiyun 		/*
504*4882a593Smuzhiyun 		 * Re-queue it at the head of the highest priority queue so
505*4882a593Smuzhiyun 		 * it goes before all other packets
506*4882a593Smuzhiyun 		 */
507*4882a593Smuzhiyun 		unsigned long flags;
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 		spin_lock_irqsave(&hw->lock, flags);
510*4882a593Smuzhiyun 		list_add(&packet->queue, &hw->tx_queue[0]);
511*4882a593Smuzhiyun 		hw->tx_queued++;
512*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hw->lock, flags);
513*4882a593Smuzhiyun 	} else {
514*4882a593Smuzhiyun 		if (packet->packet_callback)
515*4882a593Smuzhiyun 			packet->packet_callback(packet->callback_data,
516*4882a593Smuzhiyun 					packet->length);
517*4882a593Smuzhiyun 		kfree(packet);
518*4882a593Smuzhiyun 	}
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun 
ipw_setup_hardware(struct ipw_hardware * hw)521*4882a593Smuzhiyun static void ipw_setup_hardware(struct ipw_hardware *hw)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun 	unsigned long flags;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	spin_lock_irqsave(&hw->lock, flags);
526*4882a593Smuzhiyun 	if (hw->hw_version == HW_VERSION_1) {
527*4882a593Smuzhiyun 		/* Reset RX FIFO */
528*4882a593Smuzhiyun 		outw(DCR_RXRESET, hw->base_port + IODCR);
529*4882a593Smuzhiyun 		/* SB: Reset TX FIFO */
530*4882a593Smuzhiyun 		outw(DCR_TXRESET, hw->base_port + IODCR);
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 		/* Enable TX and RX interrupts. */
533*4882a593Smuzhiyun 		outw(IER_TXENABLED | IER_RXENABLED, hw->base_port + IOIER);
534*4882a593Smuzhiyun 	} else {
535*4882a593Smuzhiyun 		/*
536*4882a593Smuzhiyun 		 * Set INTRACK bit (bit 0), which means we must explicitly
537*4882a593Smuzhiyun 		 * acknowledge interrupts by clearing bit 2 of reg_config_and_status.
538*4882a593Smuzhiyun 		 */
539*4882a593Smuzhiyun 		unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 		csr |= 1;
542*4882a593Smuzhiyun 		writew(csr, &hw->memregs_CCR->reg_config_and_status);
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun 	spin_unlock_irqrestore(&hw->lock, flags);
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun /*
548*4882a593Smuzhiyun  * If 'packet' is NULL, then this function allocates a new packet, setting its
549*4882a593Smuzhiyun  * length to 0 and ensuring it has the specified minimum amount of free space.
550*4882a593Smuzhiyun  *
551*4882a593Smuzhiyun  * If 'packet' is not NULL, then this function enlarges it if it doesn't
552*4882a593Smuzhiyun  * have the specified minimum amount of free space.
553*4882a593Smuzhiyun  *
554*4882a593Smuzhiyun  */
pool_allocate(struct ipw_hardware * hw,struct ipw_rx_packet * packet,int minimum_free_space)555*4882a593Smuzhiyun static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw,
556*4882a593Smuzhiyun 					   struct ipw_rx_packet *packet,
557*4882a593Smuzhiyun 					   int minimum_free_space)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	if (!packet) {
561*4882a593Smuzhiyun 		unsigned long flags;
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 		spin_lock_irqsave(&hw->lock, flags);
564*4882a593Smuzhiyun 		if (!list_empty(&hw->rx_pool)) {
565*4882a593Smuzhiyun 			packet = list_first_entry(&hw->rx_pool,
566*4882a593Smuzhiyun 					struct ipw_rx_packet, queue);
567*4882a593Smuzhiyun 			hw->rx_pool_size--;
568*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hw->lock, flags);
569*4882a593Smuzhiyun 			list_del(&packet->queue);
570*4882a593Smuzhiyun 		} else {
571*4882a593Smuzhiyun 			const int min_capacity =
572*4882a593Smuzhiyun 				ipwireless_ppp_mru(hw->network) + 2;
573*4882a593Smuzhiyun 			int new_capacity;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hw->lock, flags);
576*4882a593Smuzhiyun 			new_capacity =
577*4882a593Smuzhiyun 				(minimum_free_space > min_capacity
578*4882a593Smuzhiyun 				 ? minimum_free_space
579*4882a593Smuzhiyun 				 : min_capacity);
580*4882a593Smuzhiyun 			packet = kmalloc(sizeof(struct ipw_rx_packet)
581*4882a593Smuzhiyun 					+ new_capacity, GFP_ATOMIC);
582*4882a593Smuzhiyun 			if (!packet)
583*4882a593Smuzhiyun 				return NULL;
584*4882a593Smuzhiyun 			packet->capacity = new_capacity;
585*4882a593Smuzhiyun 		}
586*4882a593Smuzhiyun 		packet->length = 0;
587*4882a593Smuzhiyun 	}
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	if (packet->length + minimum_free_space > packet->capacity) {
590*4882a593Smuzhiyun 		struct ipw_rx_packet *old_packet = packet;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 		packet = kmalloc(sizeof(struct ipw_rx_packet) +
593*4882a593Smuzhiyun 				old_packet->length + minimum_free_space,
594*4882a593Smuzhiyun 				GFP_ATOMIC);
595*4882a593Smuzhiyun 		if (!packet) {
596*4882a593Smuzhiyun 			kfree(old_packet);
597*4882a593Smuzhiyun 			return NULL;
598*4882a593Smuzhiyun 		}
599*4882a593Smuzhiyun 		memcpy(packet, old_packet,
600*4882a593Smuzhiyun 				sizeof(struct ipw_rx_packet)
601*4882a593Smuzhiyun 					+ old_packet->length);
602*4882a593Smuzhiyun 		packet->capacity = old_packet->length + minimum_free_space;
603*4882a593Smuzhiyun 		kfree(old_packet);
604*4882a593Smuzhiyun 	}
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	return packet;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun 
pool_free(struct ipw_hardware * hw,struct ipw_rx_packet * packet)609*4882a593Smuzhiyun static void pool_free(struct ipw_hardware *hw, struct ipw_rx_packet *packet)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun 	if (hw->rx_pool_size > 6)
612*4882a593Smuzhiyun 		kfree(packet);
613*4882a593Smuzhiyun 	else {
614*4882a593Smuzhiyun 		hw->rx_pool_size++;
615*4882a593Smuzhiyun 		list_add(&packet->queue, &hw->rx_pool);
616*4882a593Smuzhiyun 	}
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun 
queue_received_packet(struct ipw_hardware * hw,unsigned int protocol,unsigned int address,const unsigned char * data,int length,int is_last)619*4882a593Smuzhiyun static void queue_received_packet(struct ipw_hardware *hw,
620*4882a593Smuzhiyun 				  unsigned int protocol,
621*4882a593Smuzhiyun 				  unsigned int address,
622*4882a593Smuzhiyun 				  const unsigned char *data, int length,
623*4882a593Smuzhiyun 				  int is_last)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun 	unsigned int channel_idx = address - 1;
626*4882a593Smuzhiyun 	struct ipw_rx_packet *packet = NULL;
627*4882a593Smuzhiyun 	unsigned long flags;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	/* Discard packet if channel index is out of range. */
630*4882a593Smuzhiyun 	if (channel_idx >= NL_NUM_OF_ADDRESSES) {
631*4882a593Smuzhiyun 		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
632*4882a593Smuzhiyun 		       ": data packet has bad address %u\n", address);
633*4882a593Smuzhiyun 		return;
634*4882a593Smuzhiyun 	}
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	/*
637*4882a593Smuzhiyun 	 * ->packet_assembler is safe to touch unlocked, this is the only place
638*4882a593Smuzhiyun 	 */
639*4882a593Smuzhiyun 	if (protocol == TL_PROTOCOLID_COM_DATA) {
640*4882a593Smuzhiyun 		struct ipw_rx_packet **assem =
641*4882a593Smuzhiyun 			&hw->packet_assembler[channel_idx];
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 		/*
644*4882a593Smuzhiyun 		 * Create a new packet, or assembler already contains one
645*4882a593Smuzhiyun 		 * enlarge it by 'length' bytes.
646*4882a593Smuzhiyun 		 */
647*4882a593Smuzhiyun 		(*assem) = pool_allocate(hw, *assem, length);
648*4882a593Smuzhiyun 		if (!(*assem)) {
649*4882a593Smuzhiyun 			printk(KERN_ERR IPWIRELESS_PCCARD_NAME
650*4882a593Smuzhiyun 				": no memory for incoming data packet, dropped!\n");
651*4882a593Smuzhiyun 			return;
652*4882a593Smuzhiyun 		}
653*4882a593Smuzhiyun 		(*assem)->protocol = protocol;
654*4882a593Smuzhiyun 		(*assem)->channel_idx = channel_idx;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 		/* Append this packet data onto existing data. */
657*4882a593Smuzhiyun 		memcpy((unsigned char *)(*assem) +
658*4882a593Smuzhiyun 			       sizeof(struct ipw_rx_packet)
659*4882a593Smuzhiyun 				+ (*assem)->length, data, length);
660*4882a593Smuzhiyun 		(*assem)->length += length;
661*4882a593Smuzhiyun 		if (is_last) {
662*4882a593Smuzhiyun 			packet = *assem;
663*4882a593Smuzhiyun 			*assem = NULL;
664*4882a593Smuzhiyun 			/* Count queued DATA bytes only */
665*4882a593Smuzhiyun 			spin_lock_irqsave(&hw->lock, flags);
666*4882a593Smuzhiyun 			hw->rx_bytes_queued += packet->length;
667*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hw->lock, flags);
668*4882a593Smuzhiyun 		}
669*4882a593Smuzhiyun 	} else {
670*4882a593Smuzhiyun 		/* If it's a CTRL packet, don't assemble, just queue it. */
671*4882a593Smuzhiyun 		packet = pool_allocate(hw, NULL, length);
672*4882a593Smuzhiyun 		if (!packet) {
673*4882a593Smuzhiyun 			printk(KERN_ERR IPWIRELESS_PCCARD_NAME
674*4882a593Smuzhiyun 				": no memory for incoming ctrl packet, dropped!\n");
675*4882a593Smuzhiyun 			return;
676*4882a593Smuzhiyun 		}
677*4882a593Smuzhiyun 		packet->protocol = protocol;
678*4882a593Smuzhiyun 		packet->channel_idx = channel_idx;
679*4882a593Smuzhiyun 		memcpy((unsigned char *)packet + sizeof(struct ipw_rx_packet),
680*4882a593Smuzhiyun 				data, length);
681*4882a593Smuzhiyun 		packet->length = length;
682*4882a593Smuzhiyun 	}
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	/*
685*4882a593Smuzhiyun 	 * If this is the last packet, then send the assembled packet on to the
686*4882a593Smuzhiyun 	 * network layer.
687*4882a593Smuzhiyun 	 */
688*4882a593Smuzhiyun 	if (packet) {
689*4882a593Smuzhiyun 		spin_lock_irqsave(&hw->lock, flags);
690*4882a593Smuzhiyun 		list_add_tail(&packet->queue, &hw->rx_queue);
691*4882a593Smuzhiyun 		/* Block reception of incoming packets if queue is full. */
692*4882a593Smuzhiyun 		hw->blocking_rx =
693*4882a593Smuzhiyun 			(hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE);
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hw->lock, flags);
696*4882a593Smuzhiyun 		schedule_work(&hw->work_rx);
697*4882a593Smuzhiyun 	}
698*4882a593Smuzhiyun }
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun /*
701*4882a593Smuzhiyun  * Workqueue callback
702*4882a593Smuzhiyun  */
ipw_receive_data_work(struct work_struct * work_rx)703*4882a593Smuzhiyun static void ipw_receive_data_work(struct work_struct *work_rx)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun 	struct ipw_hardware *hw =
706*4882a593Smuzhiyun 	    container_of(work_rx, struct ipw_hardware, work_rx);
707*4882a593Smuzhiyun 	unsigned long flags;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	spin_lock_irqsave(&hw->lock, flags);
710*4882a593Smuzhiyun 	while (!list_empty(&hw->rx_queue)) {
711*4882a593Smuzhiyun 		struct ipw_rx_packet *packet =
712*4882a593Smuzhiyun 			list_first_entry(&hw->rx_queue,
713*4882a593Smuzhiyun 					struct ipw_rx_packet, queue);
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 		if (hw->shutting_down)
716*4882a593Smuzhiyun 			break;
717*4882a593Smuzhiyun 		list_del(&packet->queue);
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 		/*
720*4882a593Smuzhiyun 		 * Note: ipwireless_network_packet_received must be called in a
721*4882a593Smuzhiyun 		 * process context (i.e. via schedule_work) because the tty
722*4882a593Smuzhiyun 		 * output code can sleep in the tty_flip_buffer_push call.
723*4882a593Smuzhiyun 		 */
724*4882a593Smuzhiyun 		if (packet->protocol == TL_PROTOCOLID_COM_DATA) {
725*4882a593Smuzhiyun 			if (hw->network != NULL) {
726*4882a593Smuzhiyun 				/* If the network hasn't been disconnected. */
727*4882a593Smuzhiyun 				spin_unlock_irqrestore(&hw->lock, flags);
728*4882a593Smuzhiyun 				/*
729*4882a593Smuzhiyun 				 * This must run unlocked due to tty processing
730*4882a593Smuzhiyun 				 * and mutex locking
731*4882a593Smuzhiyun 				 */
732*4882a593Smuzhiyun 				ipwireless_network_packet_received(
733*4882a593Smuzhiyun 						hw->network,
734*4882a593Smuzhiyun 						packet->channel_idx,
735*4882a593Smuzhiyun 						(unsigned char *)packet
736*4882a593Smuzhiyun 						+ sizeof(struct ipw_rx_packet),
737*4882a593Smuzhiyun 						packet->length);
738*4882a593Smuzhiyun 				spin_lock_irqsave(&hw->lock, flags);
739*4882a593Smuzhiyun 			}
740*4882a593Smuzhiyun 			/* Count queued DATA bytes only */
741*4882a593Smuzhiyun 			hw->rx_bytes_queued -= packet->length;
742*4882a593Smuzhiyun 		} else {
743*4882a593Smuzhiyun 			/*
744*4882a593Smuzhiyun 			 * This is safe to be called locked, callchain does
745*4882a593Smuzhiyun 			 * not block
746*4882a593Smuzhiyun 			 */
747*4882a593Smuzhiyun 			handle_received_CTRL_packet(hw, packet->channel_idx,
748*4882a593Smuzhiyun 					(unsigned char *)packet
749*4882a593Smuzhiyun 					+ sizeof(struct ipw_rx_packet),
750*4882a593Smuzhiyun 					packet->length);
751*4882a593Smuzhiyun 		}
752*4882a593Smuzhiyun 		pool_free(hw, packet);
753*4882a593Smuzhiyun 		/*
754*4882a593Smuzhiyun 		 * Unblock reception of incoming packets if queue is no longer
755*4882a593Smuzhiyun 		 * full.
756*4882a593Smuzhiyun 		 */
757*4882a593Smuzhiyun 		hw->blocking_rx =
758*4882a593Smuzhiyun 			hw->rx_bytes_queued >= IPWIRELESS_RX_QUEUE_SIZE;
759*4882a593Smuzhiyun 		if (hw->shutting_down)
760*4882a593Smuzhiyun 			break;
761*4882a593Smuzhiyun 	}
762*4882a593Smuzhiyun 	spin_unlock_irqrestore(&hw->lock, flags);
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun 
handle_received_CTRL_packet(struct ipw_hardware * hw,unsigned int channel_idx,const unsigned char * data,int len)765*4882a593Smuzhiyun static void handle_received_CTRL_packet(struct ipw_hardware *hw,
766*4882a593Smuzhiyun 					unsigned int channel_idx,
767*4882a593Smuzhiyun 					const unsigned char *data, int len)
768*4882a593Smuzhiyun {
769*4882a593Smuzhiyun 	const struct ipw_control_packet_body *body =
770*4882a593Smuzhiyun 		(const struct ipw_control_packet_body *) data;
771*4882a593Smuzhiyun 	unsigned int changed_mask;
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	if (len != sizeof(struct ipw_control_packet_body)) {
774*4882a593Smuzhiyun 		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
775*4882a593Smuzhiyun 		       ": control packet was %d bytes - wrong size!\n",
776*4882a593Smuzhiyun 		       len);
777*4882a593Smuzhiyun 		return;
778*4882a593Smuzhiyun 	}
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	switch (body->sig_no) {
781*4882a593Smuzhiyun 	case COMCTRL_CTS:
782*4882a593Smuzhiyun 		changed_mask = IPW_CONTROL_LINE_CTS;
783*4882a593Smuzhiyun 		break;
784*4882a593Smuzhiyun 	case COMCTRL_DCD:
785*4882a593Smuzhiyun 		changed_mask = IPW_CONTROL_LINE_DCD;
786*4882a593Smuzhiyun 		break;
787*4882a593Smuzhiyun 	case COMCTRL_DSR:
788*4882a593Smuzhiyun 		changed_mask = IPW_CONTROL_LINE_DSR;
789*4882a593Smuzhiyun 		break;
790*4882a593Smuzhiyun 	case COMCTRL_RI:
791*4882a593Smuzhiyun 		changed_mask = IPW_CONTROL_LINE_RI;
792*4882a593Smuzhiyun 		break;
793*4882a593Smuzhiyun 	default:
794*4882a593Smuzhiyun 		changed_mask = 0;
795*4882a593Smuzhiyun 	}
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	if (changed_mask != 0) {
798*4882a593Smuzhiyun 		if (body->value)
799*4882a593Smuzhiyun 			hw->control_lines[channel_idx] |= changed_mask;
800*4882a593Smuzhiyun 		else
801*4882a593Smuzhiyun 			hw->control_lines[channel_idx] &= ~changed_mask;
802*4882a593Smuzhiyun 		if (hw->network)
803*4882a593Smuzhiyun 			ipwireless_network_notify_control_line_change(
804*4882a593Smuzhiyun 					hw->network,
805*4882a593Smuzhiyun 					channel_idx,
806*4882a593Smuzhiyun 					hw->control_lines[channel_idx],
807*4882a593Smuzhiyun 					changed_mask);
808*4882a593Smuzhiyun 	}
809*4882a593Smuzhiyun }
810*4882a593Smuzhiyun 
handle_received_packet(struct ipw_hardware * hw,const union nl_packet * packet,unsigned short len)811*4882a593Smuzhiyun static void handle_received_packet(struct ipw_hardware *hw,
812*4882a593Smuzhiyun 				   const union nl_packet *packet,
813*4882a593Smuzhiyun 				   unsigned short len)
814*4882a593Smuzhiyun {
815*4882a593Smuzhiyun 	unsigned int protocol = packet->hdr.protocol;
816*4882a593Smuzhiyun 	unsigned int address = packet->hdr.address;
817*4882a593Smuzhiyun 	unsigned int header_length;
818*4882a593Smuzhiyun 	const unsigned char *data;
819*4882a593Smuzhiyun 	unsigned int data_len;
820*4882a593Smuzhiyun 	int is_last = packet->hdr.packet_rank & NL_LAST_PACKET;
821*4882a593Smuzhiyun 
822*4882a593Smuzhiyun 	if (packet->hdr.packet_rank & NL_FIRST_PACKET)
823*4882a593Smuzhiyun 		header_length = NL_FIRST_PACKET_HEADER_SIZE;
824*4882a593Smuzhiyun 	else
825*4882a593Smuzhiyun 		header_length = NL_FOLLOWING_PACKET_HEADER_SIZE;
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	data = packet->rawpkt + header_length;
828*4882a593Smuzhiyun 	data_len = len - header_length;
829*4882a593Smuzhiyun 	switch (protocol) {
830*4882a593Smuzhiyun 	case TL_PROTOCOLID_COM_DATA:
831*4882a593Smuzhiyun 	case TL_PROTOCOLID_COM_CTRL:
832*4882a593Smuzhiyun 		queue_received_packet(hw, protocol, address, data, data_len,
833*4882a593Smuzhiyun 				is_last);
834*4882a593Smuzhiyun 		break;
835*4882a593Smuzhiyun 	case TL_PROTOCOLID_SETUP:
836*4882a593Smuzhiyun 		handle_received_SETUP_packet(hw, address, data, data_len,
837*4882a593Smuzhiyun 				is_last);
838*4882a593Smuzhiyun 		break;
839*4882a593Smuzhiyun 	}
840*4882a593Smuzhiyun }
841*4882a593Smuzhiyun 
acknowledge_data_read(struct ipw_hardware * hw)842*4882a593Smuzhiyun static void acknowledge_data_read(struct ipw_hardware *hw)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun 	if (hw->hw_version == HW_VERSION_1)
845*4882a593Smuzhiyun 		outw(DCR_RXDONE, hw->base_port + IODCR);
846*4882a593Smuzhiyun 	else
847*4882a593Smuzhiyun 		writew(MEMRX_PCINTACKK,
848*4882a593Smuzhiyun 				&hw->memory_info_regs->memreg_pc_interrupt_ack);
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun /*
852*4882a593Smuzhiyun  * Retrieve a packet from the IPW hardware.
853*4882a593Smuzhiyun  */
do_receive_packet(struct ipw_hardware * hw)854*4882a593Smuzhiyun static void do_receive_packet(struct ipw_hardware *hw)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun 	unsigned len;
857*4882a593Smuzhiyun 	unsigned i;
858*4882a593Smuzhiyun 	unsigned char pkt[LL_MTU_MAX];
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	start_timing();
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 	if (hw->hw_version == HW_VERSION_1) {
863*4882a593Smuzhiyun 		len = inw(hw->base_port + IODRR);
864*4882a593Smuzhiyun 		if (len > hw->ll_mtu) {
865*4882a593Smuzhiyun 			printk(KERN_INFO IPWIRELESS_PCCARD_NAME
866*4882a593Smuzhiyun 			       ": received a packet of %u bytes - longer than the MTU!\n", len);
867*4882a593Smuzhiyun 			outw(DCR_RXDONE | DCR_RXRESET, hw->base_port + IODCR);
868*4882a593Smuzhiyun 			return;
869*4882a593Smuzhiyun 		}
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun 		for (i = 0; i < len; i += 2) {
872*4882a593Smuzhiyun 			__le16 raw_data = inw(hw->base_port + IODRR);
873*4882a593Smuzhiyun 			unsigned short data = le16_to_cpu(raw_data);
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 			pkt[i] = (unsigned char) data;
876*4882a593Smuzhiyun 			pkt[i + 1] = (unsigned char) (data >> 8);
877*4882a593Smuzhiyun 		}
878*4882a593Smuzhiyun 	} else {
879*4882a593Smuzhiyun 		len = inw(hw->base_port);
880*4882a593Smuzhiyun 		if (len > hw->ll_mtu) {
881*4882a593Smuzhiyun 			printk(KERN_INFO IPWIRELESS_PCCARD_NAME
882*4882a593Smuzhiyun 			       ": received a packet of %u bytes - longer than the MTU!\n", len);
883*4882a593Smuzhiyun 			writew(MEMRX_PCINTACKK,
884*4882a593Smuzhiyun 				&hw->memory_info_regs->memreg_pc_interrupt_ack);
885*4882a593Smuzhiyun 			return;
886*4882a593Smuzhiyun 		}
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 		for (i = 0; i < len; i += 2) {
889*4882a593Smuzhiyun 			__le16 raw_data = inw(hw->base_port);
890*4882a593Smuzhiyun 			unsigned short data = le16_to_cpu(raw_data);
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 			pkt[i] = (unsigned char) data;
893*4882a593Smuzhiyun 			pkt[i + 1] = (unsigned char) (data >> 8);
894*4882a593Smuzhiyun 		}
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 		while ((i & 3) != 2) {
897*4882a593Smuzhiyun 			inw(hw->base_port);
898*4882a593Smuzhiyun 			i += 2;
899*4882a593Smuzhiyun 		}
900*4882a593Smuzhiyun 	}
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 	acknowledge_data_read(hw);
903*4882a593Smuzhiyun 
904*4882a593Smuzhiyun 	swap_packet_bitfield_from_le(pkt);
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun 	if (ipwireless_debug)
907*4882a593Smuzhiyun 		dump_data_bytes("recv", pkt, len);
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	handle_received_packet(hw, (union nl_packet *) pkt, len);
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	end_read_timing(len);
912*4882a593Smuzhiyun }
913*4882a593Smuzhiyun 
get_current_packet_priority(struct ipw_hardware * hw)914*4882a593Smuzhiyun static int get_current_packet_priority(struct ipw_hardware *hw)
915*4882a593Smuzhiyun {
916*4882a593Smuzhiyun 	/*
917*4882a593Smuzhiyun 	 * If we're initializing, don't send anything of higher priority than
918*4882a593Smuzhiyun 	 * PRIO_SETUP.  The network layer therefore need not care about
919*4882a593Smuzhiyun 	 * hardware initialization - any of its stuff will simply be queued
920*4882a593Smuzhiyun 	 * until setup is complete.
921*4882a593Smuzhiyun 	 */
922*4882a593Smuzhiyun 	return (hw->to_setup || hw->initializing
923*4882a593Smuzhiyun 			? PRIO_SETUP + 1 : NL_NUM_OF_PRIORITIES);
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun /*
927*4882a593Smuzhiyun  * return 1 if something has been received from hw
928*4882a593Smuzhiyun  */
get_packets_from_hw(struct ipw_hardware * hw)929*4882a593Smuzhiyun static int get_packets_from_hw(struct ipw_hardware *hw)
930*4882a593Smuzhiyun {
931*4882a593Smuzhiyun 	int received = 0;
932*4882a593Smuzhiyun 	unsigned long flags;
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	spin_lock_irqsave(&hw->lock, flags);
935*4882a593Smuzhiyun 	while (hw->rx_ready && !hw->blocking_rx) {
936*4882a593Smuzhiyun 		received = 1;
937*4882a593Smuzhiyun 		hw->rx_ready--;
938*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hw->lock, flags);
939*4882a593Smuzhiyun 
940*4882a593Smuzhiyun 		do_receive_packet(hw);
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 		spin_lock_irqsave(&hw->lock, flags);
943*4882a593Smuzhiyun 	}
944*4882a593Smuzhiyun 	spin_unlock_irqrestore(&hw->lock, flags);
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	return received;
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun /*
950*4882a593Smuzhiyun  * Send pending packet up to given priority, prioritize SETUP data until
951*4882a593Smuzhiyun  * hardware is fully setup.
952*4882a593Smuzhiyun  *
953*4882a593Smuzhiyun  * return 1 if more packets can be sent
954*4882a593Smuzhiyun  */
send_pending_packet(struct ipw_hardware * hw,int priority_limit)955*4882a593Smuzhiyun static int send_pending_packet(struct ipw_hardware *hw, int priority_limit)
956*4882a593Smuzhiyun {
957*4882a593Smuzhiyun 	int more_to_send = 0;
958*4882a593Smuzhiyun 	unsigned long flags;
959*4882a593Smuzhiyun 
960*4882a593Smuzhiyun 	spin_lock_irqsave(&hw->lock, flags);
961*4882a593Smuzhiyun 	if (hw->tx_queued && hw->tx_ready) {
962*4882a593Smuzhiyun 		int priority;
963*4882a593Smuzhiyun 		struct ipw_tx_packet *packet = NULL;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 		/* Pick a packet */
966*4882a593Smuzhiyun 		for (priority = 0; priority < priority_limit; priority++) {
967*4882a593Smuzhiyun 			if (!list_empty(&hw->tx_queue[priority])) {
968*4882a593Smuzhiyun 				packet = list_first_entry(
969*4882a593Smuzhiyun 						&hw->tx_queue[priority],
970*4882a593Smuzhiyun 						struct ipw_tx_packet,
971*4882a593Smuzhiyun 						queue);
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun 				hw->tx_queued--;
974*4882a593Smuzhiyun 				list_del(&packet->queue);
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 				break;
977*4882a593Smuzhiyun 			}
978*4882a593Smuzhiyun 		}
979*4882a593Smuzhiyun 		if (!packet) {
980*4882a593Smuzhiyun 			hw->tx_queued = 0;
981*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hw->lock, flags);
982*4882a593Smuzhiyun 			return 0;
983*4882a593Smuzhiyun 		}
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hw->lock, flags);
986*4882a593Smuzhiyun 
987*4882a593Smuzhiyun 		/* Send */
988*4882a593Smuzhiyun 		do_send_packet(hw, packet);
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 		/* Check if more to send */
991*4882a593Smuzhiyun 		spin_lock_irqsave(&hw->lock, flags);
992*4882a593Smuzhiyun 		for (priority = 0; priority < priority_limit; priority++)
993*4882a593Smuzhiyun 			if (!list_empty(&hw->tx_queue[priority])) {
994*4882a593Smuzhiyun 				more_to_send = 1;
995*4882a593Smuzhiyun 				break;
996*4882a593Smuzhiyun 			}
997*4882a593Smuzhiyun 
998*4882a593Smuzhiyun 		if (!more_to_send)
999*4882a593Smuzhiyun 			hw->tx_queued = 0;
1000*4882a593Smuzhiyun 	}
1001*4882a593Smuzhiyun 	spin_unlock_irqrestore(&hw->lock, flags);
1002*4882a593Smuzhiyun 
1003*4882a593Smuzhiyun 	return more_to_send;
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun /*
1007*4882a593Smuzhiyun  * Send and receive all queued packets.
1008*4882a593Smuzhiyun  */
ipwireless_do_tasklet(struct tasklet_struct * t)1009*4882a593Smuzhiyun static void ipwireless_do_tasklet(struct tasklet_struct *t)
1010*4882a593Smuzhiyun {
1011*4882a593Smuzhiyun 	struct ipw_hardware *hw = from_tasklet(hw, t, tasklet);
1012*4882a593Smuzhiyun 	unsigned long flags;
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	spin_lock_irqsave(&hw->lock, flags);
1015*4882a593Smuzhiyun 	if (hw->shutting_down) {
1016*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hw->lock, flags);
1017*4882a593Smuzhiyun 		return;
1018*4882a593Smuzhiyun 	}
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 	if (hw->to_setup == 1) {
1021*4882a593Smuzhiyun 		/*
1022*4882a593Smuzhiyun 		 * Initial setup data sent to hardware
1023*4882a593Smuzhiyun 		 */
1024*4882a593Smuzhiyun 		hw->to_setup = 2;
1025*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hw->lock, flags);
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun 		ipw_setup_hardware(hw);
1028*4882a593Smuzhiyun 		ipw_send_setup_packet(hw);
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 		send_pending_packet(hw, PRIO_SETUP + 1);
1031*4882a593Smuzhiyun 		get_packets_from_hw(hw);
1032*4882a593Smuzhiyun 	} else {
1033*4882a593Smuzhiyun 		int priority_limit = get_current_packet_priority(hw);
1034*4882a593Smuzhiyun 		int again;
1035*4882a593Smuzhiyun 
1036*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hw->lock, flags);
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 		do {
1039*4882a593Smuzhiyun 			again = send_pending_packet(hw, priority_limit);
1040*4882a593Smuzhiyun 			again |= get_packets_from_hw(hw);
1041*4882a593Smuzhiyun 		} while (again);
1042*4882a593Smuzhiyun 	}
1043*4882a593Smuzhiyun }
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun /*
1046*4882a593Smuzhiyun  * return true if the card is physically present.
1047*4882a593Smuzhiyun  */
is_card_present(struct ipw_hardware * hw)1048*4882a593Smuzhiyun static int is_card_present(struct ipw_hardware *hw)
1049*4882a593Smuzhiyun {
1050*4882a593Smuzhiyun 	if (hw->hw_version == HW_VERSION_1)
1051*4882a593Smuzhiyun 		return inw(hw->base_port + IOIR) != 0xFFFF;
1052*4882a593Smuzhiyun 	else
1053*4882a593Smuzhiyun 		return readl(&hw->memory_info_regs->memreg_card_present) ==
1054*4882a593Smuzhiyun 		    CARD_PRESENT_VALUE;
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun 
ipwireless_handle_v1_interrupt(int irq,struct ipw_hardware * hw)1057*4882a593Smuzhiyun static irqreturn_t ipwireless_handle_v1_interrupt(int irq,
1058*4882a593Smuzhiyun 						  struct ipw_hardware *hw)
1059*4882a593Smuzhiyun {
1060*4882a593Smuzhiyun 	unsigned short irqn;
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun 	irqn = inw(hw->base_port + IOIR);
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 	/* Check if card is present */
1065*4882a593Smuzhiyun 	if (irqn == 0xFFFF)
1066*4882a593Smuzhiyun 		return IRQ_NONE;
1067*4882a593Smuzhiyun 	else if (irqn != 0) {
1068*4882a593Smuzhiyun 		unsigned short ack = 0;
1069*4882a593Smuzhiyun 		unsigned long flags;
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 		/* Transmit complete. */
1072*4882a593Smuzhiyun 		if (irqn & IR_TXINTR) {
1073*4882a593Smuzhiyun 			ack |= IR_TXINTR;
1074*4882a593Smuzhiyun 			spin_lock_irqsave(&hw->lock, flags);
1075*4882a593Smuzhiyun 			hw->tx_ready = 1;
1076*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hw->lock, flags);
1077*4882a593Smuzhiyun 		}
1078*4882a593Smuzhiyun 		/* Received data */
1079*4882a593Smuzhiyun 		if (irqn & IR_RXINTR) {
1080*4882a593Smuzhiyun 			ack |= IR_RXINTR;
1081*4882a593Smuzhiyun 			spin_lock_irqsave(&hw->lock, flags);
1082*4882a593Smuzhiyun 			hw->rx_ready++;
1083*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hw->lock, flags);
1084*4882a593Smuzhiyun 		}
1085*4882a593Smuzhiyun 		if (ack != 0) {
1086*4882a593Smuzhiyun 			outw(ack, hw->base_port + IOIR);
1087*4882a593Smuzhiyun 			tasklet_schedule(&hw->tasklet);
1088*4882a593Smuzhiyun 		}
1089*4882a593Smuzhiyun 		return IRQ_HANDLED;
1090*4882a593Smuzhiyun 	}
1091*4882a593Smuzhiyun 	return IRQ_NONE;
1092*4882a593Smuzhiyun }
1093*4882a593Smuzhiyun 
acknowledge_pcmcia_interrupt(struct ipw_hardware * hw)1094*4882a593Smuzhiyun static void acknowledge_pcmcia_interrupt(struct ipw_hardware *hw)
1095*4882a593Smuzhiyun {
1096*4882a593Smuzhiyun 	unsigned short csr = readw(&hw->memregs_CCR->reg_config_and_status);
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	csr &= 0xfffd;
1099*4882a593Smuzhiyun 	writew(csr, &hw->memregs_CCR->reg_config_and_status);
1100*4882a593Smuzhiyun }
1101*4882a593Smuzhiyun 
ipwireless_handle_v2_v3_interrupt(int irq,struct ipw_hardware * hw)1102*4882a593Smuzhiyun static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq,
1103*4882a593Smuzhiyun 						     struct ipw_hardware *hw)
1104*4882a593Smuzhiyun {
1105*4882a593Smuzhiyun 	int tx = 0;
1106*4882a593Smuzhiyun 	int rx = 0;
1107*4882a593Smuzhiyun 	int rx_repeat = 0;
1108*4882a593Smuzhiyun 	int try_mem_tx_old;
1109*4882a593Smuzhiyun 	unsigned long flags;
1110*4882a593Smuzhiyun 
1111*4882a593Smuzhiyun 	do {
1112*4882a593Smuzhiyun 
1113*4882a593Smuzhiyun 	unsigned short memtx = readw(hw->memreg_tx);
1114*4882a593Smuzhiyun 	unsigned short memtx_serial;
1115*4882a593Smuzhiyun 	unsigned short memrxdone =
1116*4882a593Smuzhiyun 		readw(&hw->memory_info_regs->memreg_rx_done);
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	try_mem_tx_old = 0;
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun 	/* check whether the interrupt was generated by ipwireless card */
1121*4882a593Smuzhiyun 	if (!(memtx & MEMTX_TX) && !(memrxdone & MEMRX_RX_DONE)) {
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 		/* check if the card uses memreg_tx_old register */
1124*4882a593Smuzhiyun 		if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) {
1125*4882a593Smuzhiyun 			memtx = readw(&hw->memory_info_regs->memreg_tx_old);
1126*4882a593Smuzhiyun 			if (memtx & MEMTX_TX) {
1127*4882a593Smuzhiyun 				printk(KERN_INFO IPWIRELESS_PCCARD_NAME
1128*4882a593Smuzhiyun 					": Using memreg_tx_old\n");
1129*4882a593Smuzhiyun 				hw->memreg_tx =
1130*4882a593Smuzhiyun 					&hw->memory_info_regs->memreg_tx_old;
1131*4882a593Smuzhiyun 			} else {
1132*4882a593Smuzhiyun 				return IRQ_NONE;
1133*4882a593Smuzhiyun 			}
1134*4882a593Smuzhiyun 		} else
1135*4882a593Smuzhiyun 			return IRQ_NONE;
1136*4882a593Smuzhiyun 	}
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 	/*
1139*4882a593Smuzhiyun 	 * See if the card is physically present. Note that while it is
1140*4882a593Smuzhiyun 	 * powering up, it appears not to be present.
1141*4882a593Smuzhiyun 	 */
1142*4882a593Smuzhiyun 	if (!is_card_present(hw)) {
1143*4882a593Smuzhiyun 		acknowledge_pcmcia_interrupt(hw);
1144*4882a593Smuzhiyun 		return IRQ_HANDLED;
1145*4882a593Smuzhiyun 	}
1146*4882a593Smuzhiyun 
1147*4882a593Smuzhiyun 	memtx_serial = memtx & (unsigned short) 0xff00;
1148*4882a593Smuzhiyun 	if (memtx & MEMTX_TX) {
1149*4882a593Smuzhiyun 		writew(memtx_serial, hw->memreg_tx);
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun 		if (hw->serial_number_detected) {
1152*4882a593Smuzhiyun 			if (memtx_serial != hw->last_memtx_serial) {
1153*4882a593Smuzhiyun 				hw->last_memtx_serial = memtx_serial;
1154*4882a593Smuzhiyun 				spin_lock_irqsave(&hw->lock, flags);
1155*4882a593Smuzhiyun 				hw->rx_ready++;
1156*4882a593Smuzhiyun 				spin_unlock_irqrestore(&hw->lock, flags);
1157*4882a593Smuzhiyun 				rx = 1;
1158*4882a593Smuzhiyun 			} else
1159*4882a593Smuzhiyun 				/* Ignore 'Timer Recovery' duplicates. */
1160*4882a593Smuzhiyun 				rx_repeat = 1;
1161*4882a593Smuzhiyun 		} else {
1162*4882a593Smuzhiyun 			/*
1163*4882a593Smuzhiyun 			 * If a non-zero serial number is seen, then enable
1164*4882a593Smuzhiyun 			 * serial number checking.
1165*4882a593Smuzhiyun 			 */
1166*4882a593Smuzhiyun 			if (memtx_serial != 0) {
1167*4882a593Smuzhiyun 				hw->serial_number_detected = 1;
1168*4882a593Smuzhiyun 				printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
1169*4882a593Smuzhiyun 					": memreg_tx serial num detected\n");
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 				spin_lock_irqsave(&hw->lock, flags);
1172*4882a593Smuzhiyun 				hw->rx_ready++;
1173*4882a593Smuzhiyun 				spin_unlock_irqrestore(&hw->lock, flags);
1174*4882a593Smuzhiyun 			}
1175*4882a593Smuzhiyun 			rx = 1;
1176*4882a593Smuzhiyun 		}
1177*4882a593Smuzhiyun 	}
1178*4882a593Smuzhiyun 	if (memrxdone & MEMRX_RX_DONE) {
1179*4882a593Smuzhiyun 		writew(0, &hw->memory_info_regs->memreg_rx_done);
1180*4882a593Smuzhiyun 		spin_lock_irqsave(&hw->lock, flags);
1181*4882a593Smuzhiyun 		hw->tx_ready = 1;
1182*4882a593Smuzhiyun 		spin_unlock_irqrestore(&hw->lock, flags);
1183*4882a593Smuzhiyun 		tx = 1;
1184*4882a593Smuzhiyun 	}
1185*4882a593Smuzhiyun 	if (tx)
1186*4882a593Smuzhiyun 		writew(MEMRX_PCINTACKK,
1187*4882a593Smuzhiyun 				&hw->memory_info_regs->memreg_pc_interrupt_ack);
1188*4882a593Smuzhiyun 
1189*4882a593Smuzhiyun 	acknowledge_pcmcia_interrupt(hw);
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	if (tx || rx)
1192*4882a593Smuzhiyun 		tasklet_schedule(&hw->tasklet);
1193*4882a593Smuzhiyun 	else if (!rx_repeat) {
1194*4882a593Smuzhiyun 		if (hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) {
1195*4882a593Smuzhiyun 			if (hw->serial_number_detected)
1196*4882a593Smuzhiyun 				printk(KERN_WARNING IPWIRELESS_PCCARD_NAME
1197*4882a593Smuzhiyun 					": spurious interrupt - new_tx mode\n");
1198*4882a593Smuzhiyun 			else {
1199*4882a593Smuzhiyun 				printk(KERN_WARNING IPWIRELESS_PCCARD_NAME
1200*4882a593Smuzhiyun 					": no valid memreg_tx value - switching to the old memreg_tx\n");
1201*4882a593Smuzhiyun 				hw->memreg_tx =
1202*4882a593Smuzhiyun 					&hw->memory_info_regs->memreg_tx_old;
1203*4882a593Smuzhiyun 				try_mem_tx_old = 1;
1204*4882a593Smuzhiyun 			}
1205*4882a593Smuzhiyun 		} else
1206*4882a593Smuzhiyun 			printk(KERN_WARNING IPWIRELESS_PCCARD_NAME
1207*4882a593Smuzhiyun 					": spurious interrupt - old_tx mode\n");
1208*4882a593Smuzhiyun 	}
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	} while (try_mem_tx_old == 1);
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	return IRQ_HANDLED;
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun 
ipwireless_interrupt(int irq,void * dev_id)1215*4882a593Smuzhiyun irqreturn_t ipwireless_interrupt(int irq, void *dev_id)
1216*4882a593Smuzhiyun {
1217*4882a593Smuzhiyun 	struct ipw_dev *ipw = dev_id;
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 	if (ipw->hardware->hw_version == HW_VERSION_1)
1220*4882a593Smuzhiyun 		return ipwireless_handle_v1_interrupt(irq, ipw->hardware);
1221*4882a593Smuzhiyun 	else
1222*4882a593Smuzhiyun 		return ipwireless_handle_v2_v3_interrupt(irq, ipw->hardware);
1223*4882a593Smuzhiyun }
1224*4882a593Smuzhiyun 
flush_packets_to_hw(struct ipw_hardware * hw)1225*4882a593Smuzhiyun static void flush_packets_to_hw(struct ipw_hardware *hw)
1226*4882a593Smuzhiyun {
1227*4882a593Smuzhiyun 	int priority_limit;
1228*4882a593Smuzhiyun 	unsigned long flags;
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 	spin_lock_irqsave(&hw->lock, flags);
1231*4882a593Smuzhiyun 	priority_limit = get_current_packet_priority(hw);
1232*4882a593Smuzhiyun 	spin_unlock_irqrestore(&hw->lock, flags);
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	while (send_pending_packet(hw, priority_limit));
1235*4882a593Smuzhiyun }
1236*4882a593Smuzhiyun 
send_packet(struct ipw_hardware * hw,int priority,struct ipw_tx_packet * packet)1237*4882a593Smuzhiyun static void send_packet(struct ipw_hardware *hw, int priority,
1238*4882a593Smuzhiyun 			struct ipw_tx_packet *packet)
1239*4882a593Smuzhiyun {
1240*4882a593Smuzhiyun 	unsigned long flags;
1241*4882a593Smuzhiyun 
1242*4882a593Smuzhiyun 	spin_lock_irqsave(&hw->lock, flags);
1243*4882a593Smuzhiyun 	list_add_tail(&packet->queue, &hw->tx_queue[priority]);
1244*4882a593Smuzhiyun 	hw->tx_queued++;
1245*4882a593Smuzhiyun 	spin_unlock_irqrestore(&hw->lock, flags);
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun 	flush_packets_to_hw(hw);
1248*4882a593Smuzhiyun }
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun /* Create data packet, non-atomic allocation */
alloc_data_packet(int data_size,unsigned char dest_addr,unsigned char protocol)1251*4882a593Smuzhiyun static void *alloc_data_packet(int data_size,
1252*4882a593Smuzhiyun 				unsigned char dest_addr,
1253*4882a593Smuzhiyun 				unsigned char protocol)
1254*4882a593Smuzhiyun {
1255*4882a593Smuzhiyun 	struct ipw_tx_packet *packet = kzalloc(
1256*4882a593Smuzhiyun 			sizeof(struct ipw_tx_packet) + data_size,
1257*4882a593Smuzhiyun 			GFP_ATOMIC);
1258*4882a593Smuzhiyun 
1259*4882a593Smuzhiyun 	if (!packet)
1260*4882a593Smuzhiyun 		return NULL;
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun 	INIT_LIST_HEAD(&packet->queue);
1263*4882a593Smuzhiyun 	packet->dest_addr = dest_addr;
1264*4882a593Smuzhiyun 	packet->protocol = protocol;
1265*4882a593Smuzhiyun 	packet->length = data_size;
1266*4882a593Smuzhiyun 
1267*4882a593Smuzhiyun 	return packet;
1268*4882a593Smuzhiyun }
1269*4882a593Smuzhiyun 
alloc_ctrl_packet(int header_size,unsigned char dest_addr,unsigned char protocol,unsigned char sig_no)1270*4882a593Smuzhiyun static void *alloc_ctrl_packet(int header_size,
1271*4882a593Smuzhiyun 			       unsigned char dest_addr,
1272*4882a593Smuzhiyun 			       unsigned char protocol,
1273*4882a593Smuzhiyun 			       unsigned char sig_no)
1274*4882a593Smuzhiyun {
1275*4882a593Smuzhiyun 	/*
1276*4882a593Smuzhiyun 	 * sig_no is located right after ipw_tx_packet struct in every
1277*4882a593Smuzhiyun 	 * CTRL or SETUP packets, we can use ipw_control_packet as a
1278*4882a593Smuzhiyun 	 * common struct
1279*4882a593Smuzhiyun 	 */
1280*4882a593Smuzhiyun 	struct ipw_control_packet *packet = kzalloc(header_size, GFP_ATOMIC);
1281*4882a593Smuzhiyun 
1282*4882a593Smuzhiyun 	if (!packet)
1283*4882a593Smuzhiyun 		return NULL;
1284*4882a593Smuzhiyun 
1285*4882a593Smuzhiyun 	INIT_LIST_HEAD(&packet->header.queue);
1286*4882a593Smuzhiyun 	packet->header.dest_addr = dest_addr;
1287*4882a593Smuzhiyun 	packet->header.protocol = protocol;
1288*4882a593Smuzhiyun 	packet->header.length = header_size - sizeof(struct ipw_tx_packet);
1289*4882a593Smuzhiyun 	packet->body.sig_no = sig_no;
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun 	return packet;
1292*4882a593Smuzhiyun }
1293*4882a593Smuzhiyun 
ipwireless_send_packet(struct ipw_hardware * hw,unsigned int channel_idx,const unsigned char * data,unsigned int length,void (* callback)(void * cb,unsigned int length),void * callback_data)1294*4882a593Smuzhiyun int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx,
1295*4882a593Smuzhiyun 			    const unsigned char *data, unsigned int length,
1296*4882a593Smuzhiyun 			    void (*callback) (void *cb, unsigned int length),
1297*4882a593Smuzhiyun 			    void *callback_data)
1298*4882a593Smuzhiyun {
1299*4882a593Smuzhiyun 	struct ipw_tx_packet *packet;
1300*4882a593Smuzhiyun 
1301*4882a593Smuzhiyun 	packet = alloc_data_packet(length, (channel_idx + 1),
1302*4882a593Smuzhiyun 			TL_PROTOCOLID_COM_DATA);
1303*4882a593Smuzhiyun 	if (!packet)
1304*4882a593Smuzhiyun 		return -ENOMEM;
1305*4882a593Smuzhiyun 	packet->packet_callback = callback;
1306*4882a593Smuzhiyun 	packet->callback_data = callback_data;
1307*4882a593Smuzhiyun 	memcpy((unsigned char *) packet + sizeof(struct ipw_tx_packet), data,
1308*4882a593Smuzhiyun 			length);
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 	send_packet(hw, PRIO_DATA, packet);
1311*4882a593Smuzhiyun 	return 0;
1312*4882a593Smuzhiyun }
1313*4882a593Smuzhiyun 
set_control_line(struct ipw_hardware * hw,int prio,unsigned int channel_idx,int line,int state)1314*4882a593Smuzhiyun static int set_control_line(struct ipw_hardware *hw, int prio,
1315*4882a593Smuzhiyun 			   unsigned int channel_idx, int line, int state)
1316*4882a593Smuzhiyun {
1317*4882a593Smuzhiyun 	struct ipw_control_packet *packet;
1318*4882a593Smuzhiyun 	int protocolid = TL_PROTOCOLID_COM_CTRL;
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun 	if (prio == PRIO_SETUP)
1321*4882a593Smuzhiyun 		protocolid = TL_PROTOCOLID_SETUP;
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun 	packet = alloc_ctrl_packet(sizeof(struct ipw_control_packet),
1324*4882a593Smuzhiyun 			(channel_idx + 1), protocolid, line);
1325*4882a593Smuzhiyun 	if (!packet)
1326*4882a593Smuzhiyun 		return -ENOMEM;
1327*4882a593Smuzhiyun 	packet->header.length = sizeof(struct ipw_control_packet_body);
1328*4882a593Smuzhiyun 	packet->body.value = (state == 0 ? 0 : 1);
1329*4882a593Smuzhiyun 	send_packet(hw, prio, &packet->header);
1330*4882a593Smuzhiyun 	return 0;
1331*4882a593Smuzhiyun }
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 
set_DTR(struct ipw_hardware * hw,int priority,unsigned int channel_idx,int state)1334*4882a593Smuzhiyun static int set_DTR(struct ipw_hardware *hw, int priority,
1335*4882a593Smuzhiyun 		   unsigned int channel_idx, int state)
1336*4882a593Smuzhiyun {
1337*4882a593Smuzhiyun 	if (state != 0)
1338*4882a593Smuzhiyun 		hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_DTR;
1339*4882a593Smuzhiyun 	else
1340*4882a593Smuzhiyun 		hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_DTR;
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun 	return set_control_line(hw, priority, channel_idx, COMCTRL_DTR, state);
1343*4882a593Smuzhiyun }
1344*4882a593Smuzhiyun 
set_RTS(struct ipw_hardware * hw,int priority,unsigned int channel_idx,int state)1345*4882a593Smuzhiyun static int set_RTS(struct ipw_hardware *hw, int priority,
1346*4882a593Smuzhiyun 		   unsigned int channel_idx, int state)
1347*4882a593Smuzhiyun {
1348*4882a593Smuzhiyun 	if (state != 0)
1349*4882a593Smuzhiyun 		hw->control_lines[channel_idx] |= IPW_CONTROL_LINE_RTS;
1350*4882a593Smuzhiyun 	else
1351*4882a593Smuzhiyun 		hw->control_lines[channel_idx] &= ~IPW_CONTROL_LINE_RTS;
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun 	return set_control_line(hw, priority, channel_idx, COMCTRL_RTS, state);
1354*4882a593Smuzhiyun }
1355*4882a593Smuzhiyun 
ipwireless_set_DTR(struct ipw_hardware * hw,unsigned int channel_idx,int state)1356*4882a593Smuzhiyun int ipwireless_set_DTR(struct ipw_hardware *hw, unsigned int channel_idx,
1357*4882a593Smuzhiyun 		       int state)
1358*4882a593Smuzhiyun {
1359*4882a593Smuzhiyun 	return set_DTR(hw, PRIO_CTRL, channel_idx, state);
1360*4882a593Smuzhiyun }
1361*4882a593Smuzhiyun 
ipwireless_set_RTS(struct ipw_hardware * hw,unsigned int channel_idx,int state)1362*4882a593Smuzhiyun int ipwireless_set_RTS(struct ipw_hardware *hw, unsigned int channel_idx,
1363*4882a593Smuzhiyun 		       int state)
1364*4882a593Smuzhiyun {
1365*4882a593Smuzhiyun 	return set_RTS(hw, PRIO_CTRL, channel_idx, state);
1366*4882a593Smuzhiyun }
1367*4882a593Smuzhiyun 
1368*4882a593Smuzhiyun struct ipw_setup_get_version_query_packet {
1369*4882a593Smuzhiyun 	struct ipw_tx_packet header;
1370*4882a593Smuzhiyun 	struct tl_setup_get_version_qry body;
1371*4882a593Smuzhiyun };
1372*4882a593Smuzhiyun 
1373*4882a593Smuzhiyun struct ipw_setup_config_packet {
1374*4882a593Smuzhiyun 	struct ipw_tx_packet header;
1375*4882a593Smuzhiyun 	struct tl_setup_config_msg body;
1376*4882a593Smuzhiyun };
1377*4882a593Smuzhiyun 
1378*4882a593Smuzhiyun struct ipw_setup_config_done_packet {
1379*4882a593Smuzhiyun 	struct ipw_tx_packet header;
1380*4882a593Smuzhiyun 	struct tl_setup_config_done_msg body;
1381*4882a593Smuzhiyun };
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun struct ipw_setup_open_packet {
1384*4882a593Smuzhiyun 	struct ipw_tx_packet header;
1385*4882a593Smuzhiyun 	struct tl_setup_open_msg body;
1386*4882a593Smuzhiyun };
1387*4882a593Smuzhiyun 
1388*4882a593Smuzhiyun struct ipw_setup_info_packet {
1389*4882a593Smuzhiyun 	struct ipw_tx_packet header;
1390*4882a593Smuzhiyun 	struct tl_setup_info_msg body;
1391*4882a593Smuzhiyun };
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun struct ipw_setup_reboot_msg_ack {
1394*4882a593Smuzhiyun 	struct ipw_tx_packet header;
1395*4882a593Smuzhiyun 	struct TlSetupRebootMsgAck body;
1396*4882a593Smuzhiyun };
1397*4882a593Smuzhiyun 
1398*4882a593Smuzhiyun /* This handles the actual initialization of the card */
__handle_setup_get_version_rsp(struct ipw_hardware * hw)1399*4882a593Smuzhiyun static void __handle_setup_get_version_rsp(struct ipw_hardware *hw)
1400*4882a593Smuzhiyun {
1401*4882a593Smuzhiyun 	struct ipw_setup_config_packet *config_packet;
1402*4882a593Smuzhiyun 	struct ipw_setup_config_done_packet *config_done_packet;
1403*4882a593Smuzhiyun 	struct ipw_setup_open_packet *open_packet;
1404*4882a593Smuzhiyun 	struct ipw_setup_info_packet *info_packet;
1405*4882a593Smuzhiyun 	int port;
1406*4882a593Smuzhiyun 	unsigned int channel_idx;
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun 	/* generate config packet */
1409*4882a593Smuzhiyun 	for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) {
1410*4882a593Smuzhiyun 		config_packet = alloc_ctrl_packet(
1411*4882a593Smuzhiyun 				sizeof(struct ipw_setup_config_packet),
1412*4882a593Smuzhiyun 				ADDR_SETUP_PROT,
1413*4882a593Smuzhiyun 				TL_PROTOCOLID_SETUP,
1414*4882a593Smuzhiyun 				TL_SETUP_SIGNO_CONFIG_MSG);
1415*4882a593Smuzhiyun 		if (!config_packet)
1416*4882a593Smuzhiyun 			goto exit_nomem;
1417*4882a593Smuzhiyun 		config_packet->header.length = sizeof(struct tl_setup_config_msg);
1418*4882a593Smuzhiyun 		config_packet->body.port_no = port;
1419*4882a593Smuzhiyun 		config_packet->body.prio_data = PRIO_DATA;
1420*4882a593Smuzhiyun 		config_packet->body.prio_ctrl = PRIO_CTRL;
1421*4882a593Smuzhiyun 		send_packet(hw, PRIO_SETUP, &config_packet->header);
1422*4882a593Smuzhiyun 	}
1423*4882a593Smuzhiyun 	config_done_packet = alloc_ctrl_packet(
1424*4882a593Smuzhiyun 			sizeof(struct ipw_setup_config_done_packet),
1425*4882a593Smuzhiyun 			ADDR_SETUP_PROT,
1426*4882a593Smuzhiyun 			TL_PROTOCOLID_SETUP,
1427*4882a593Smuzhiyun 			TL_SETUP_SIGNO_CONFIG_DONE_MSG);
1428*4882a593Smuzhiyun 	if (!config_done_packet)
1429*4882a593Smuzhiyun 		goto exit_nomem;
1430*4882a593Smuzhiyun 	config_done_packet->header.length = sizeof(struct tl_setup_config_done_msg);
1431*4882a593Smuzhiyun 	send_packet(hw, PRIO_SETUP, &config_done_packet->header);
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun 	/* generate open packet */
1434*4882a593Smuzhiyun 	for (port = 1; port <= NL_NUM_OF_ADDRESSES; port++) {
1435*4882a593Smuzhiyun 		open_packet = alloc_ctrl_packet(
1436*4882a593Smuzhiyun 				sizeof(struct ipw_setup_open_packet),
1437*4882a593Smuzhiyun 				ADDR_SETUP_PROT,
1438*4882a593Smuzhiyun 				TL_PROTOCOLID_SETUP,
1439*4882a593Smuzhiyun 				TL_SETUP_SIGNO_OPEN_MSG);
1440*4882a593Smuzhiyun 		if (!open_packet)
1441*4882a593Smuzhiyun 			goto exit_nomem;
1442*4882a593Smuzhiyun 		open_packet->header.length = sizeof(struct tl_setup_open_msg);
1443*4882a593Smuzhiyun 		open_packet->body.port_no = port;
1444*4882a593Smuzhiyun 		send_packet(hw, PRIO_SETUP, &open_packet->header);
1445*4882a593Smuzhiyun 	}
1446*4882a593Smuzhiyun 	for (channel_idx = 0;
1447*4882a593Smuzhiyun 			channel_idx < NL_NUM_OF_ADDRESSES; channel_idx++) {
1448*4882a593Smuzhiyun 		int ret;
1449*4882a593Smuzhiyun 
1450*4882a593Smuzhiyun 		ret = set_DTR(hw, PRIO_SETUP, channel_idx,
1451*4882a593Smuzhiyun 			(hw->control_lines[channel_idx] &
1452*4882a593Smuzhiyun 			 IPW_CONTROL_LINE_DTR) != 0);
1453*4882a593Smuzhiyun 		if (ret) {
1454*4882a593Smuzhiyun 			printk(KERN_ERR IPWIRELESS_PCCARD_NAME
1455*4882a593Smuzhiyun 					": error setting DTR (%d)\n", ret);
1456*4882a593Smuzhiyun 			return;
1457*4882a593Smuzhiyun 		}
1458*4882a593Smuzhiyun 
1459*4882a593Smuzhiyun 		ret = set_RTS(hw, PRIO_SETUP, channel_idx,
1460*4882a593Smuzhiyun 			(hw->control_lines [channel_idx] &
1461*4882a593Smuzhiyun 			 IPW_CONTROL_LINE_RTS) != 0);
1462*4882a593Smuzhiyun 		if (ret) {
1463*4882a593Smuzhiyun 			printk(KERN_ERR IPWIRELESS_PCCARD_NAME
1464*4882a593Smuzhiyun 					": error setting RTS (%d)\n", ret);
1465*4882a593Smuzhiyun 			return;
1466*4882a593Smuzhiyun 		}
1467*4882a593Smuzhiyun 	}
1468*4882a593Smuzhiyun 	/*
1469*4882a593Smuzhiyun 	 * For NDIS we assume that we are using sync PPP frames, for COM async.
1470*4882a593Smuzhiyun 	 * This driver uses NDIS mode too. We don't bother with translation
1471*4882a593Smuzhiyun 	 * from async -> sync PPP.
1472*4882a593Smuzhiyun 	 */
1473*4882a593Smuzhiyun 	info_packet = alloc_ctrl_packet(sizeof(struct ipw_setup_info_packet),
1474*4882a593Smuzhiyun 			ADDR_SETUP_PROT,
1475*4882a593Smuzhiyun 			TL_PROTOCOLID_SETUP,
1476*4882a593Smuzhiyun 			TL_SETUP_SIGNO_INFO_MSG);
1477*4882a593Smuzhiyun 	if (!info_packet)
1478*4882a593Smuzhiyun 		goto exit_nomem;
1479*4882a593Smuzhiyun 	info_packet->header.length = sizeof(struct tl_setup_info_msg);
1480*4882a593Smuzhiyun 	info_packet->body.driver_type = NDISWAN_DRIVER;
1481*4882a593Smuzhiyun 	info_packet->body.major_version = NDISWAN_DRIVER_MAJOR_VERSION;
1482*4882a593Smuzhiyun 	info_packet->body.minor_version = NDISWAN_DRIVER_MINOR_VERSION;
1483*4882a593Smuzhiyun 	send_packet(hw, PRIO_SETUP, &info_packet->header);
1484*4882a593Smuzhiyun 
1485*4882a593Smuzhiyun 	/* Initialization is now complete, so we clear the 'to_setup' flag */
1486*4882a593Smuzhiyun 	hw->to_setup = 0;
1487*4882a593Smuzhiyun 
1488*4882a593Smuzhiyun 	return;
1489*4882a593Smuzhiyun 
1490*4882a593Smuzhiyun exit_nomem:
1491*4882a593Smuzhiyun 	printk(KERN_ERR IPWIRELESS_PCCARD_NAME
1492*4882a593Smuzhiyun 			": not enough memory to alloc control packet\n");
1493*4882a593Smuzhiyun 	hw->to_setup = -1;
1494*4882a593Smuzhiyun }
1495*4882a593Smuzhiyun 
handle_setup_get_version_rsp(struct ipw_hardware * hw,unsigned char vers_no)1496*4882a593Smuzhiyun static void handle_setup_get_version_rsp(struct ipw_hardware *hw,
1497*4882a593Smuzhiyun 		unsigned char vers_no)
1498*4882a593Smuzhiyun {
1499*4882a593Smuzhiyun 	del_timer(&hw->setup_timer);
1500*4882a593Smuzhiyun 	hw->initializing = 0;
1501*4882a593Smuzhiyun 	printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": card is ready.\n");
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	if (vers_no == TL_SETUP_VERSION)
1504*4882a593Smuzhiyun 		__handle_setup_get_version_rsp(hw);
1505*4882a593Smuzhiyun 	else
1506*4882a593Smuzhiyun 		printk(KERN_ERR IPWIRELESS_PCCARD_NAME
1507*4882a593Smuzhiyun 				": invalid hardware version no %u\n",
1508*4882a593Smuzhiyun 				(unsigned int) vers_no);
1509*4882a593Smuzhiyun }
1510*4882a593Smuzhiyun 
ipw_send_setup_packet(struct ipw_hardware * hw)1511*4882a593Smuzhiyun static void ipw_send_setup_packet(struct ipw_hardware *hw)
1512*4882a593Smuzhiyun {
1513*4882a593Smuzhiyun 	struct ipw_setup_get_version_query_packet *ver_packet;
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun 	ver_packet = alloc_ctrl_packet(
1516*4882a593Smuzhiyun 			sizeof(struct ipw_setup_get_version_query_packet),
1517*4882a593Smuzhiyun 			ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP,
1518*4882a593Smuzhiyun 			TL_SETUP_SIGNO_GET_VERSION_QRY);
1519*4882a593Smuzhiyun 	if (!ver_packet)
1520*4882a593Smuzhiyun 		return;
1521*4882a593Smuzhiyun 	ver_packet->header.length = sizeof(struct tl_setup_get_version_qry);
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun 	/*
1524*4882a593Smuzhiyun 	 * Response is handled in handle_received_SETUP_packet
1525*4882a593Smuzhiyun 	 */
1526*4882a593Smuzhiyun 	send_packet(hw, PRIO_SETUP, &ver_packet->header);
1527*4882a593Smuzhiyun }
1528*4882a593Smuzhiyun 
handle_received_SETUP_packet(struct ipw_hardware * hw,unsigned int address,const unsigned char * data,int len,int is_last)1529*4882a593Smuzhiyun static void handle_received_SETUP_packet(struct ipw_hardware *hw,
1530*4882a593Smuzhiyun 					 unsigned int address,
1531*4882a593Smuzhiyun 					 const unsigned char *data, int len,
1532*4882a593Smuzhiyun 					 int is_last)
1533*4882a593Smuzhiyun {
1534*4882a593Smuzhiyun 	const union ipw_setup_rx_msg *rx_msg = (const union ipw_setup_rx_msg *) data;
1535*4882a593Smuzhiyun 
1536*4882a593Smuzhiyun 	if (address != ADDR_SETUP_PROT) {
1537*4882a593Smuzhiyun 		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
1538*4882a593Smuzhiyun 		       ": setup packet has bad address %d\n", address);
1539*4882a593Smuzhiyun 		return;
1540*4882a593Smuzhiyun 	}
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun 	switch (rx_msg->sig_no) {
1543*4882a593Smuzhiyun 	case TL_SETUP_SIGNO_GET_VERSION_RSP:
1544*4882a593Smuzhiyun 		if (hw->to_setup)
1545*4882a593Smuzhiyun 			handle_setup_get_version_rsp(hw,
1546*4882a593Smuzhiyun 					rx_msg->version_rsp_msg.version);
1547*4882a593Smuzhiyun 		break;
1548*4882a593Smuzhiyun 
1549*4882a593Smuzhiyun 	case TL_SETUP_SIGNO_OPEN_MSG:
1550*4882a593Smuzhiyun 		if (ipwireless_debug) {
1551*4882a593Smuzhiyun 			unsigned int channel_idx = rx_msg->open_msg.port_no - 1;
1552*4882a593Smuzhiyun 
1553*4882a593Smuzhiyun 			printk(KERN_INFO IPWIRELESS_PCCARD_NAME
1554*4882a593Smuzhiyun 			       ": OPEN_MSG [channel %u] reply received\n",
1555*4882a593Smuzhiyun 			       channel_idx);
1556*4882a593Smuzhiyun 		}
1557*4882a593Smuzhiyun 		break;
1558*4882a593Smuzhiyun 
1559*4882a593Smuzhiyun 	case TL_SETUP_SIGNO_INFO_MSG_ACK:
1560*4882a593Smuzhiyun 		if (ipwireless_debug)
1561*4882a593Smuzhiyun 			printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
1562*4882a593Smuzhiyun 			       ": card successfully configured as NDISWAN\n");
1563*4882a593Smuzhiyun 		break;
1564*4882a593Smuzhiyun 
1565*4882a593Smuzhiyun 	case TL_SETUP_SIGNO_REBOOT_MSG:
1566*4882a593Smuzhiyun 		if (hw->to_setup)
1567*4882a593Smuzhiyun 			printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
1568*4882a593Smuzhiyun 			       ": Setup not completed - ignoring reboot msg\n");
1569*4882a593Smuzhiyun 		else {
1570*4882a593Smuzhiyun 			struct ipw_setup_reboot_msg_ack *packet;
1571*4882a593Smuzhiyun 
1572*4882a593Smuzhiyun 			printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
1573*4882a593Smuzhiyun 			       ": Acknowledging REBOOT message\n");
1574*4882a593Smuzhiyun 			packet = alloc_ctrl_packet(
1575*4882a593Smuzhiyun 					sizeof(struct ipw_setup_reboot_msg_ack),
1576*4882a593Smuzhiyun 					ADDR_SETUP_PROT, TL_PROTOCOLID_SETUP,
1577*4882a593Smuzhiyun 					TL_SETUP_SIGNO_REBOOT_MSG_ACK);
1578*4882a593Smuzhiyun 			if (!packet) {
1579*4882a593Smuzhiyun 				pr_err(IPWIRELESS_PCCARD_NAME
1580*4882a593Smuzhiyun 				       ": Not enough memory to send reboot packet");
1581*4882a593Smuzhiyun 				break;
1582*4882a593Smuzhiyun 			}
1583*4882a593Smuzhiyun 			packet->header.length =
1584*4882a593Smuzhiyun 				sizeof(struct TlSetupRebootMsgAck);
1585*4882a593Smuzhiyun 			send_packet(hw, PRIO_SETUP, &packet->header);
1586*4882a593Smuzhiyun 			if (hw->reboot_callback)
1587*4882a593Smuzhiyun 				hw->reboot_callback(hw->reboot_callback_data);
1588*4882a593Smuzhiyun 		}
1589*4882a593Smuzhiyun 		break;
1590*4882a593Smuzhiyun 
1591*4882a593Smuzhiyun 	default:
1592*4882a593Smuzhiyun 		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
1593*4882a593Smuzhiyun 		       ": unknown setup message %u received\n",
1594*4882a593Smuzhiyun 		       (unsigned int) rx_msg->sig_no);
1595*4882a593Smuzhiyun 	}
1596*4882a593Smuzhiyun }
1597*4882a593Smuzhiyun 
do_close_hardware(struct ipw_hardware * hw)1598*4882a593Smuzhiyun static void do_close_hardware(struct ipw_hardware *hw)
1599*4882a593Smuzhiyun {
1600*4882a593Smuzhiyun 	unsigned int irqn;
1601*4882a593Smuzhiyun 
1602*4882a593Smuzhiyun 	if (hw->hw_version == HW_VERSION_1) {
1603*4882a593Smuzhiyun 		/* Disable TX and RX interrupts. */
1604*4882a593Smuzhiyun 		outw(0, hw->base_port + IOIER);
1605*4882a593Smuzhiyun 
1606*4882a593Smuzhiyun 		/* Acknowledge any outstanding interrupt requests */
1607*4882a593Smuzhiyun 		irqn = inw(hw->base_port + IOIR);
1608*4882a593Smuzhiyun 		if (irqn & IR_TXINTR)
1609*4882a593Smuzhiyun 			outw(IR_TXINTR, hw->base_port + IOIR);
1610*4882a593Smuzhiyun 		if (irqn & IR_RXINTR)
1611*4882a593Smuzhiyun 			outw(IR_RXINTR, hw->base_port + IOIR);
1612*4882a593Smuzhiyun 
1613*4882a593Smuzhiyun 		synchronize_irq(hw->irq);
1614*4882a593Smuzhiyun 	}
1615*4882a593Smuzhiyun }
1616*4882a593Smuzhiyun 
ipwireless_hardware_create(void)1617*4882a593Smuzhiyun struct ipw_hardware *ipwireless_hardware_create(void)
1618*4882a593Smuzhiyun {
1619*4882a593Smuzhiyun 	int i;
1620*4882a593Smuzhiyun 	struct ipw_hardware *hw =
1621*4882a593Smuzhiyun 		kzalloc(sizeof(struct ipw_hardware), GFP_KERNEL);
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun 	if (!hw)
1624*4882a593Smuzhiyun 		return NULL;
1625*4882a593Smuzhiyun 
1626*4882a593Smuzhiyun 	hw->irq = -1;
1627*4882a593Smuzhiyun 	hw->initializing = 1;
1628*4882a593Smuzhiyun 	hw->tx_ready = 1;
1629*4882a593Smuzhiyun 	hw->rx_bytes_queued = 0;
1630*4882a593Smuzhiyun 	hw->rx_pool_size = 0;
1631*4882a593Smuzhiyun 	hw->last_memtx_serial = (unsigned short) 0xffff;
1632*4882a593Smuzhiyun 	for (i = 0; i < NL_NUM_OF_PRIORITIES; i++)
1633*4882a593Smuzhiyun 		INIT_LIST_HEAD(&hw->tx_queue[i]);
1634*4882a593Smuzhiyun 
1635*4882a593Smuzhiyun 	INIT_LIST_HEAD(&hw->rx_queue);
1636*4882a593Smuzhiyun 	INIT_LIST_HEAD(&hw->rx_pool);
1637*4882a593Smuzhiyun 	spin_lock_init(&hw->lock);
1638*4882a593Smuzhiyun 	tasklet_setup(&hw->tasklet, ipwireless_do_tasklet);
1639*4882a593Smuzhiyun 	INIT_WORK(&hw->work_rx, ipw_receive_data_work);
1640*4882a593Smuzhiyun 	timer_setup(&hw->setup_timer, ipwireless_setup_timer, 0);
1641*4882a593Smuzhiyun 
1642*4882a593Smuzhiyun 	return hw;
1643*4882a593Smuzhiyun }
1644*4882a593Smuzhiyun 
ipwireless_init_hardware_v1(struct ipw_hardware * hw,unsigned int base_port,void __iomem * attr_memory,void __iomem * common_memory,int is_v2_card,void (* reboot_callback)(void * data),void * reboot_callback_data)1645*4882a593Smuzhiyun void ipwireless_init_hardware_v1(struct ipw_hardware *hw,
1646*4882a593Smuzhiyun 		unsigned int base_port,
1647*4882a593Smuzhiyun 		void __iomem *attr_memory,
1648*4882a593Smuzhiyun 		void __iomem *common_memory,
1649*4882a593Smuzhiyun 		int is_v2_card,
1650*4882a593Smuzhiyun 		void (*reboot_callback) (void *data),
1651*4882a593Smuzhiyun 		void *reboot_callback_data)
1652*4882a593Smuzhiyun {
1653*4882a593Smuzhiyun 	if (hw->removed) {
1654*4882a593Smuzhiyun 		hw->removed = 0;
1655*4882a593Smuzhiyun 		enable_irq(hw->irq);
1656*4882a593Smuzhiyun 	}
1657*4882a593Smuzhiyun 	hw->base_port = base_port;
1658*4882a593Smuzhiyun 	hw->hw_version = (is_v2_card ? HW_VERSION_2 : HW_VERSION_1);
1659*4882a593Smuzhiyun 	hw->ll_mtu = (hw->hw_version == HW_VERSION_1 ? LL_MTU_V1 : LL_MTU_V2);
1660*4882a593Smuzhiyun 	hw->memregs_CCR = (struct MEMCCR __iomem *)
1661*4882a593Smuzhiyun 			((unsigned short __iomem *) attr_memory + 0x200);
1662*4882a593Smuzhiyun 	hw->memory_info_regs = (struct MEMINFREG __iomem *) common_memory;
1663*4882a593Smuzhiyun 	hw->memreg_tx = &hw->memory_info_regs->memreg_tx_new;
1664*4882a593Smuzhiyun 	hw->reboot_callback = reboot_callback;
1665*4882a593Smuzhiyun 	hw->reboot_callback_data = reboot_callback_data;
1666*4882a593Smuzhiyun }
1667*4882a593Smuzhiyun 
ipwireless_init_hardware_v2_v3(struct ipw_hardware * hw)1668*4882a593Smuzhiyun void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw)
1669*4882a593Smuzhiyun {
1670*4882a593Smuzhiyun 	hw->initializing = 1;
1671*4882a593Smuzhiyun 	hw->init_loops = 0;
1672*4882a593Smuzhiyun 	printk(KERN_INFO IPWIRELESS_PCCARD_NAME
1673*4882a593Smuzhiyun 	       ": waiting for card to start up...\n");
1674*4882a593Smuzhiyun 	ipwireless_setup_timer(&hw->setup_timer);
1675*4882a593Smuzhiyun }
1676*4882a593Smuzhiyun 
ipwireless_setup_timer(struct timer_list * t)1677*4882a593Smuzhiyun static void ipwireless_setup_timer(struct timer_list *t)
1678*4882a593Smuzhiyun {
1679*4882a593Smuzhiyun 	struct ipw_hardware *hw = from_timer(hw, t, setup_timer);
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 	hw->init_loops++;
1682*4882a593Smuzhiyun 
1683*4882a593Smuzhiyun 	if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY &&
1684*4882a593Smuzhiyun 			hw->hw_version == HW_VERSION_2 &&
1685*4882a593Smuzhiyun 			hw->memreg_tx == &hw->memory_info_regs->memreg_tx_new) {
1686*4882a593Smuzhiyun 		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
1687*4882a593Smuzhiyun 				": failed to startup using TX2, trying TX\n");
1688*4882a593Smuzhiyun 
1689*4882a593Smuzhiyun 		hw->memreg_tx = &hw->memory_info_regs->memreg_tx_old;
1690*4882a593Smuzhiyun 		hw->init_loops = 0;
1691*4882a593Smuzhiyun 	}
1692*4882a593Smuzhiyun 	/* Give up after a certain number of retries */
1693*4882a593Smuzhiyun 	if (hw->init_loops == TL_SETUP_MAX_VERSION_QRY) {
1694*4882a593Smuzhiyun 		printk(KERN_INFO IPWIRELESS_PCCARD_NAME
1695*4882a593Smuzhiyun 		       ": card failed to start up!\n");
1696*4882a593Smuzhiyun 		hw->initializing = 0;
1697*4882a593Smuzhiyun 	} else {
1698*4882a593Smuzhiyun 		/* Do not attempt to write to the board if it is not present. */
1699*4882a593Smuzhiyun 		if (is_card_present(hw)) {
1700*4882a593Smuzhiyun 			unsigned long flags;
1701*4882a593Smuzhiyun 
1702*4882a593Smuzhiyun 			spin_lock_irqsave(&hw->lock, flags);
1703*4882a593Smuzhiyun 			hw->to_setup = 1;
1704*4882a593Smuzhiyun 			hw->tx_ready = 1;
1705*4882a593Smuzhiyun 			spin_unlock_irqrestore(&hw->lock, flags);
1706*4882a593Smuzhiyun 			tasklet_schedule(&hw->tasklet);
1707*4882a593Smuzhiyun 		}
1708*4882a593Smuzhiyun 
1709*4882a593Smuzhiyun 		mod_timer(&hw->setup_timer,
1710*4882a593Smuzhiyun 			jiffies + msecs_to_jiffies(TL_SETUP_VERSION_QRY_TMO));
1711*4882a593Smuzhiyun 	}
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun 
1714*4882a593Smuzhiyun /*
1715*4882a593Smuzhiyun  * Stop any interrupts from executing so that, once this function returns,
1716*4882a593Smuzhiyun  * other layers of the driver can be sure they won't get any more callbacks.
1717*4882a593Smuzhiyun  * Thus must be called on a proper process context.
1718*4882a593Smuzhiyun  */
ipwireless_stop_interrupts(struct ipw_hardware * hw)1719*4882a593Smuzhiyun void ipwireless_stop_interrupts(struct ipw_hardware *hw)
1720*4882a593Smuzhiyun {
1721*4882a593Smuzhiyun 	if (!hw->shutting_down) {
1722*4882a593Smuzhiyun 		/* Tell everyone we are going down. */
1723*4882a593Smuzhiyun 		hw->shutting_down = 1;
1724*4882a593Smuzhiyun 		del_timer(&hw->setup_timer);
1725*4882a593Smuzhiyun 
1726*4882a593Smuzhiyun 		/* Prevent the hardware from sending any more interrupts */
1727*4882a593Smuzhiyun 		do_close_hardware(hw);
1728*4882a593Smuzhiyun 	}
1729*4882a593Smuzhiyun }
1730*4882a593Smuzhiyun 
ipwireless_hardware_free(struct ipw_hardware * hw)1731*4882a593Smuzhiyun void ipwireless_hardware_free(struct ipw_hardware *hw)
1732*4882a593Smuzhiyun {
1733*4882a593Smuzhiyun 	int i;
1734*4882a593Smuzhiyun 	struct ipw_rx_packet *rp, *rq;
1735*4882a593Smuzhiyun 	struct ipw_tx_packet *tp, *tq;
1736*4882a593Smuzhiyun 
1737*4882a593Smuzhiyun 	ipwireless_stop_interrupts(hw);
1738*4882a593Smuzhiyun 
1739*4882a593Smuzhiyun 	flush_work(&hw->work_rx);
1740*4882a593Smuzhiyun 
1741*4882a593Smuzhiyun 	for (i = 0; i < NL_NUM_OF_ADDRESSES; i++)
1742*4882a593Smuzhiyun 		kfree(hw->packet_assembler[i]);
1743*4882a593Smuzhiyun 
1744*4882a593Smuzhiyun 	for (i = 0; i < NL_NUM_OF_PRIORITIES; i++)
1745*4882a593Smuzhiyun 		list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) {
1746*4882a593Smuzhiyun 			list_del(&tp->queue);
1747*4882a593Smuzhiyun 			kfree(tp);
1748*4882a593Smuzhiyun 		}
1749*4882a593Smuzhiyun 
1750*4882a593Smuzhiyun 	list_for_each_entry_safe(rp, rq, &hw->rx_queue, queue) {
1751*4882a593Smuzhiyun 		list_del(&rp->queue);
1752*4882a593Smuzhiyun 		kfree(rp);
1753*4882a593Smuzhiyun 	}
1754*4882a593Smuzhiyun 
1755*4882a593Smuzhiyun 	list_for_each_entry_safe(rp, rq, &hw->rx_pool, queue) {
1756*4882a593Smuzhiyun 		list_del(&rp->queue);
1757*4882a593Smuzhiyun 		kfree(rp);
1758*4882a593Smuzhiyun 	}
1759*4882a593Smuzhiyun 	kfree(hw);
1760*4882a593Smuzhiyun }
1761*4882a593Smuzhiyun 
1762*4882a593Smuzhiyun /*
1763*4882a593Smuzhiyun  * Associate the specified network with this hardware, so it will receive events
1764*4882a593Smuzhiyun  * from it.
1765*4882a593Smuzhiyun  */
ipwireless_associate_network(struct ipw_hardware * hw,struct ipw_network * network)1766*4882a593Smuzhiyun void ipwireless_associate_network(struct ipw_hardware *hw,
1767*4882a593Smuzhiyun 				  struct ipw_network *network)
1768*4882a593Smuzhiyun {
1769*4882a593Smuzhiyun 	hw->network = network;
1770*4882a593Smuzhiyun }
1771