1145247Sdamien/*      $FreeBSD$	*/
2145247Sdamien
3145247Sdamien/*-
4156599Sdamien * Copyright (c) 2004-2006
5145247Sdamien *      Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
6145247Sdamien *
7145247Sdamien * Redistribution and use in source and binary forms, with or without
8145247Sdamien * modification, are permitted provided that the following conditions
9145247Sdamien * are met:
10145247Sdamien * 1. Redistributions of source code must retain the above copyright
11145247Sdamien *    notice unmodified, this list of conditions, and the following
12145247Sdamien *    disclaimer.
13145247Sdamien * 2. Redistributions in binary form must reproduce the above copyright
14145247Sdamien *    notice, this list of conditions and the following disclaimer in the
15145247Sdamien *    documentation and/or other materials provided with the distribution.
16145247Sdamien *
17145247Sdamien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18145247Sdamien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19145247Sdamien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20145247Sdamien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21145247Sdamien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22145247Sdamien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23145247Sdamien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24145247Sdamien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25145247Sdamien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26145247Sdamien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27145247Sdamien * SUCH DAMAGE.
28145247Sdamien */
29145247Sdamien
30145247Sdamien#define IPW_NTBD	128
31145247Sdamien#define IPW_TBD_SZ	(IPW_NTBD * sizeof (struct ipw_bd))
32145247Sdamien#define IPW_NDATA	(IPW_NTBD / 2)
33145247Sdamien#define IPW_NRBD	128
34145247Sdamien#define IPW_RBD_SZ	(IPW_NRBD * sizeof (struct ipw_bd))
35145247Sdamien#define IPW_STATUS_SZ	(IPW_NRBD * sizeof (struct ipw_status))
36145247Sdamien
37145247Sdamien#define IPW_CSR_INTR		0x0008
38145247Sdamien#define IPW_CSR_INTR_MASK	0x000c
39145247Sdamien#define IPW_CSR_INDIRECT_ADDR	0x0010
40145247Sdamien#define IPW_CSR_INDIRECT_DATA	0x0014
41145247Sdamien#define IPW_CSR_AUTOINC_ADDR	0x0018
42145247Sdamien#define IPW_CSR_AUTOINC_DATA	0x001c
43145247Sdamien#define IPW_CSR_RST		0x0020
44145247Sdamien#define IPW_CSR_CTL		0x0024
45145247Sdamien#define IPW_CSR_IO		0x0030
46145247Sdamien#define IPW_CSR_TX_BASE		0x0200
47145247Sdamien#define IPW_CSR_TX_SIZE		0x0204
48145247Sdamien#define IPW_CSR_RX_BASE		0x0240
49145247Sdamien#define IPW_CSR_STATUS_BASE	0x0244
50145247Sdamien#define IPW_CSR_RX_SIZE		0x0248
51145247Sdamien#define IPW_CSR_TX_READ		0x0280
52145247Sdamien#define IPW_CSR_RX_READ		0x02a0
53145247Sdamien#define IPW_CSR_TABLE1_BASE	0x0380
54145247Sdamien#define IPW_CSR_TABLE2_BASE	0x0384
55145247Sdamien#define IPW_CSR_TX_WRITE	0x0f80
56145247Sdamien#define IPW_CSR_RX_WRITE	0x0fa0
57145247Sdamien
58145247Sdamien/* possible flags for register IPW_CSR_INTR */
59145247Sdamien#define IPW_INTR_TX_TRANSFER	0x00000001
60145247Sdamien#define IPW_INTR_RX_TRANSFER	0x00000002
61145247Sdamien#define IPW_INTR_STATUS_CHANGE	0x00000010
62145247Sdamien#define IPW_INTR_COMMAND_DONE	0x00010000
63145247Sdamien#define IPW_INTR_FW_INIT_DONE	0x01000000
64145247Sdamien#define IPW_INTR_FATAL_ERROR	0x40000000
65145247Sdamien#define IPW_INTR_PARITY_ERROR	0x80000000
66145247Sdamien
67145247Sdamien#define IPW_INTR_MASK							\
68145247Sdamien	(IPW_INTR_TX_TRANSFER | IPW_INTR_RX_TRANSFER |			\
69145247Sdamien	 IPW_INTR_STATUS_CHANGE | IPW_INTR_COMMAND_DONE |		\
70145247Sdamien	 IPW_INTR_FW_INIT_DONE | IPW_INTR_FATAL_ERROR |			\
71145247Sdamien	 IPW_INTR_PARITY_ERROR)
72145247Sdamien
73145247Sdamien/* possible flags for register IPW_CSR_RST */
74145247Sdamien#define IPW_RST_PRINCETON_RESET	0x00000001
75145247Sdamien#define IPW_RST_SW_RESET	0x00000080
76145247Sdamien#define IPW_RST_MASTER_DISABLED	0x00000100
77145247Sdamien#define IPW_RST_STOP_MASTER	0x00000200
78145247Sdamien
79145247Sdamien/* possible flags for register IPW_CSR_CTL */
80145247Sdamien#define IPW_CTL_CLOCK_READY	0x00000001
81145247Sdamien#define IPW_CTL_ALLOW_STANDBY	0x00000002
82145247Sdamien#define IPW_CTL_INIT		0x00000004
83145247Sdamien
84145247Sdamien/* possible flags for register IPW_CSR_IO */
85145247Sdamien#define IPW_IO_GPIO1_ENABLE	0x00000008
86145247Sdamien#define IPW_IO_GPIO1_MASK	0x0000000c
87145247Sdamien#define IPW_IO_GPIO3_MASK	0x000000c0
88145247Sdamien#define IPW_IO_LED_OFF		0x00002000
89145247Sdamien#define IPW_IO_RADIO_DISABLED	0x00010000
90145247Sdamien
91172567Sthompsa/* state codes sent by fw on IPW_STATUS_CODE_NEWSTATE interrupt */
92172567Sthompsa#define IPW_STATE_INITIALIZED		0x0001
93172567Sthompsa#define IPW_STATE_CC_FOUND		0x0002	/* 802.11d cc received */
94145247Sdamien#define IPW_STATE_ASSOCIATED		0x0004
95145247Sdamien#define IPW_STATE_ASSOCIATION_LOST	0x0008
96172567Sthompsa#define IPW_STATE_ASSOCIATION_CHANGED	0x0010	/* assoc params changed? */
97145247Sdamien#define IPW_STATE_SCAN_COMPLETE		0x0020
98172567Sthompsa#define IPW_STATE_PS_ENTER		0x0040	/* entered power-save mode */
99172567Sthompsa#define IPW_STATE_PS_EXIT		0x0080	/* exited power-save mode */
100145247Sdamien#define IPW_STATE_RADIO_DISABLED	0x0100
101145247Sdamien#define IPW_STATE_DISABLED		0x0200
102172567Sthompsa#define IPW_STATE_POWER_DOWN		0x0400	/* ??? */
103145247Sdamien#define IPW_STATE_SCANNING		0x0800
104145247Sdamien
105145247Sdamien/* table1 offsets */
106145247Sdamien#define IPW_INFO_LOCK			480
107145247Sdamien#define IPW_INFO_APS_CNT		604
108145247Sdamien#define IPW_INFO_APS_BASE		608
109145247Sdamien#define IPW_INFO_CARD_DISABLED		628
110145247Sdamien#define IPW_INFO_CURRENT_CHANNEL	756
111145247Sdamien#define IPW_INFO_CURRENT_TX_RATE	768
112145247Sdamien
113145247Sdamien/* table2 offsets */
114145247Sdamien#define IPW_INFO_CURRENT_SSID	48
115145247Sdamien#define IPW_INFO_CURRENT_BSSID	112
116145247Sdamien
117145247Sdamien/* supported rates */
118145247Sdamien#define IPW_RATE_DS1	1
119145247Sdamien#define IPW_RATE_DS2	2
120145247Sdamien#define IPW_RATE_DS5	4
121145247Sdamien#define IPW_RATE_DS11	8
122145247Sdamien
123145247Sdamien/* firmware binary image header */
124145247Sdamienstruct ipw_firmware_hdr {
125156599Sdamien	uint32_t	version;
126156599Sdamien	uint32_t	mainsz;
127156599Sdamien	uint32_t	ucodesz;
128145247Sdamien} __packed;
129145247Sdamien
130145247Sdamien/* buffer descriptor */
131145247Sdamienstruct ipw_bd {
132156599Sdamien	uint32_t	physaddr;
133156599Sdamien	uint32_t	len;
134156599Sdamien	uint8_t		flags;
135145247Sdamien#define IPW_BD_FLAG_TX_FRAME_802_3		0x00
136145247Sdamien#define IPW_BD_FLAG_TX_NOT_LAST_FRAGMENT	0x01
137145247Sdamien#define IPW_BD_FLAG_TX_FRAME_COMMAND		0x02
138145247Sdamien#define IPW_BD_FLAG_TX_FRAME_802_11		0x04
139145247Sdamien#define IPW_BD_FLAG_TX_LAST_FRAGMENT		0x08
140156599Sdamien	uint8_t		nfrag;	/* number of fragments */
141156599Sdamien	uint8_t		reserved[6];
142145247Sdamien} __packed;
143145247Sdamien
144145247Sdamien/* status */
145145247Sdamienstruct ipw_status {
146156599Sdamien	uint32_t	len;
147156599Sdamien	uint16_t	code;
148145247Sdamien#define IPW_STATUS_CODE_COMMAND		0
149145247Sdamien#define IPW_STATUS_CODE_NEWSTATE	1
150145247Sdamien#define IPW_STATUS_CODE_DATA_802_11	2
151145247Sdamien#define IPW_STATUS_CODE_DATA_802_3	3
152145247Sdamien#define IPW_STATUS_CODE_NOTIFICATION	4
153156599Sdamien	uint8_t		flags;
154145247Sdamien#define IPW_STATUS_FLAG_DECRYPTED	0x01
155145247Sdamien#define IPW_STATUS_FLAG_WEP_ENCRYPTED	0x02
156172567Sthompsa#define IPW_STATUS_FLAG_CRC_ERROR	0x04
157156599Sdamien	uint8_t		rssi;	/* received signal strength indicator */
158172567Sthompsa#define	IPW_RSSI_TO_DBM	(-98)		/* XXX fixed nf to convert dBm */
159145247Sdamien} __packed;
160145247Sdamien
161145247Sdamien/* data header */
162145247Sdamienstruct ipw_hdr {
163156599Sdamien	uint32_t	type;
164145247Sdamien#define IPW_HDR_TYPE_SEND	33
165156599Sdamien	uint32_t	subtype;
166156599Sdamien	uint8_t		encrypted;
167156599Sdamien	uint8_t		encrypt;
168156599Sdamien	uint8_t		keyidx;
169156599Sdamien	uint8_t		keysz;
170156599Sdamien	uint8_t		key[IEEE80211_KEYBUF_SIZE];
171156599Sdamien	uint8_t		reserved[10];
172156599Sdamien	uint8_t		src_addr[IEEE80211_ADDR_LEN];
173156599Sdamien	uint8_t		dst_addr[IEEE80211_ADDR_LEN];
174156599Sdamien	uint16_t	fragmentsz;
175145247Sdamien} __packed;
176145247Sdamien
177145247Sdamien/* command */
178145247Sdamienstruct ipw_cmd {
179156599Sdamien	uint32_t	type;
180145247Sdamien#define IPW_CMD_ENABLE				2
181145247Sdamien#define IPW_CMD_SET_CONFIGURATION		6
182145247Sdamien#define IPW_CMD_SET_ESSID			8
183145247Sdamien#define IPW_CMD_SET_MANDATORY_BSSID		9
184145247Sdamien#define IPW_CMD_SET_MAC_ADDRESS			11
185145247Sdamien#define IPW_CMD_SET_MODE			12
186145247Sdamien#define IPW_CMD_SET_CHANNEL			14
187145247Sdamien#define IPW_CMD_SET_RTS_THRESHOLD		15
188145247Sdamien#define IPW_CMD_SET_FRAG_THRESHOLD		16
189145247Sdamien#define IPW_CMD_SET_POWER_MODE			17
190145247Sdamien#define IPW_CMD_SET_TX_RATES			18
191145247Sdamien#define IPW_CMD_SET_BASIC_TX_RATES		19
192145247Sdamien#define IPW_CMD_SET_WEP_KEY			20
193145247Sdamien#define IPW_CMD_SET_WEP_KEY_INDEX		25
194145247Sdamien#define IPW_CMD_SET_WEP_FLAGS			26
195145247Sdamien#define IPW_CMD_ADD_MULTICAST			27
196145247Sdamien#define IPW_CMD_SET_BEACON_INTERVAL		29
197145247Sdamien#define IPW_CMD_SET_TX_POWER_INDEX		36
198145247Sdamien#define IPW_CMD_BROADCAST_SCAN			43
199145247Sdamien#define IPW_CMD_DISABLE				44
200145247Sdamien#define IPW_CMD_SET_DESIRED_BSSID		45
201145247Sdamien#define IPW_CMD_SET_SCAN_OPTIONS		46
202172567Sthompsa#define IPW_CMD_SET_SCAN_DWELL_TIME		47
203172567Sthompsa#define IPW_CMD_SET_SHORT_RETRY			51
204172567Sthompsa#define IPW_CMD_SET_LONG_RETRY			52
205145247Sdamien#define IPW_CMD_PREPARE_POWER_DOWN		58
206145247Sdamien#define IPW_CMD_DISABLE_PHY			61
207172567Sthompsa#define IPW_CMD_SET_MSDU_TX_RATES		62
208172567Sthompsa#define IPW_CMD_SET_SECURITY_INFO		67
209172567Sthompsa#define IPW_CMD_DISASSOCIATE			68
210145247Sdamien#define IPW_CMD_SET_WPA_IE			69
211156599Sdamien	uint32_t	subtype;
212156599Sdamien	uint32_t	seq;
213156599Sdamien	uint32_t	len;
214156599Sdamien	uint8_t		data[400];
215156599Sdamien	uint32_t	status;
216156599Sdamien	uint8_t		reserved[68];
217145247Sdamien} __packed;
218145247Sdamien
219145247Sdamien/* possible values for command IPW_CMD_SET_POWER_MODE */
220145247Sdamien#define IPW_POWER_MODE_CAM	0
221172567Sthompsa#define IPW_POWER_MODE_AUTO	6
222145247Sdamien
223145247Sdamien/* possible values for command IPW_CMD_SET_MODE */
224145247Sdamien#define IPW_MODE_BSS		0
225145247Sdamien#define IPW_MODE_IBSS		1
226145247Sdamien#define IPW_MODE_MONITOR	2
227145247Sdamien
228145247Sdamien/* possible flags for command IPW_CMD_SET_WEP_FLAGS */
229145247Sdamien#define IPW_WEPON	0x8
230145247Sdamien
231145247Sdamien/* structure for command IPW_CMD_SET_WEP_KEY */
232145247Sdamienstruct ipw_wep_key {
233156599Sdamien	uint8_t	idx;
234156599Sdamien	uint8_t	len;
235156599Sdamien	uint8_t	key[13];
236145247Sdamien} __packed;
237145247Sdamien
238145247Sdamien/* structure for command IPW_CMD_SET_SECURITY_INFORMATION */
239145247Sdamienstruct ipw_security {
240156599Sdamien	uint32_t	ciphers;
241145247Sdamien#define IPW_CIPHER_NONE		0x00000001
242145247Sdamien#define IPW_CIPHER_WEP40	0x00000002
243145247Sdamien#define IPW_CIPHER_TKIP		0x00000004
244145247Sdamien#define IPW_CIPHER_CCMP		0x00000010
245145247Sdamien#define IPW_CIPHER_WEP104	0x00000020
246145247Sdamien#define IPW_CIPHER_CKIP		0x00000040
247156599Sdamien	uint16_t	reserved1;
248156599Sdamien	uint8_t		authmode;
249145247Sdamien#define IPW_AUTH_OPEN	0
250145247Sdamien#define IPW_AUTH_SHARED	1
251156599Sdamien	uint16_t	reserved2;
252145247Sdamien} __packed;
253145247Sdamien
254145247Sdamien/* structure for command IPW_CMD_SET_SCAN_OPTIONS */
255145247Sdamienstruct ipw_scan_options {
256156599Sdamien	uint32_t	flags;
257145247Sdamien#define IPW_SCAN_DO_NOT_ASSOCIATE	0x00000001
258172567Sthompsa#define IPW_SCAN_MIXED_CELL		0x00000002
259145247Sdamien#define IPW_SCAN_PASSIVE		0x00000008
260156599Sdamien	uint32_t	channels;
261145247Sdamien} __packed;
262145247Sdamien
263145247Sdamien/* structure for command IPW_CMD_SET_CONFIGURATION */
264145247Sdamienstruct ipw_configuration {
265156599Sdamien	uint32_t	flags;
266145247Sdamien#define IPW_CFG_PROMISCUOUS	0x00000004
267145247Sdamien#define IPW_CFG_PREAMBLE_AUTO	0x00000010
268145247Sdamien#define IPW_CFG_IBSS_AUTO_START	0x00000020
269145247Sdamien#define IPW_CFG_802_1x_ENABLE	0x00004000
270145247Sdamien#define IPW_CFG_BSS_MASK	0x00008000
271145247Sdamien#define IPW_CFG_IBSS_MASK	0x00010000
272156599Sdamien	uint32_t	bss_chan;
273156599Sdamien	uint32_t	ibss_chan;
274145247Sdamien} __packed;
275145247Sdamien
276145247Sdamien/* structure for command IPW_CMD_SET_WPA_IE */
277145247Sdamienstruct ipw_wpa_ie {
278156599Sdamien	uint16_t	mask;
279156599Sdamien	uint16_t	capinfo;
280156599Sdamien	uint16_t	lintval;
281156599Sdamien	uint8_t		bssid[IEEE80211_ADDR_LEN];
282156599Sdamien	uint32_t	len;
283145247Sdamien	struct ieee80211_ie_wpa	ie;
284145247Sdamien} __packed;
285145247Sdamien
286145247Sdamien/* element in AP table */
287145247Sdamienstruct ipw_node {
288156599Sdamien	uint32_t	reserved1[2];
289156599Sdamien	uint8_t		bssid[IEEE80211_ADDR_LEN];
290156599Sdamien	uint8_t		chan;
291156599Sdamien	uint8_t		rates;
292156599Sdamien	uint16_t	reserved2;
293156599Sdamien	uint16_t	capinfo;
294156599Sdamien	uint16_t	reserved3;
295156599Sdamien	uint16_t	intval;
296156599Sdamien	uint8_t		reserved4[28];
297156599Sdamien	uint8_t		essid[IEEE80211_NWID_LEN];
298156599Sdamien	uint16_t	reserved5;
299156599Sdamien	uint8_t		esslen;
300156599Sdamien	uint8_t		reserved6[7];
301156599Sdamien	uint8_t		rssi;
302145247Sdamien} __packed;
303145247Sdamien
304145247Sdamien/* EEPROM = Electrically Erasable Programmable Read-Only Memory */
305145247Sdamien
306145247Sdamien#define IPW_MEM_EEPROM_CTL	0x00300040
307145247Sdamien
308145247Sdamien#define IPW_EEPROM_RADIO	0x11
309145247Sdamien#define IPW_EEPROM_MAC		0x21
310145247Sdamien#define IPW_EEPROM_CHANNEL_LIST	0x37
311145247Sdamien
312145247Sdamien#define IPW_EEPROM_DELAY	1	/* minimum hold time (microsecond) */
313145247Sdamien
314145247Sdamien#define IPW_EEPROM_C	(1 << 0)	/* Serial Clock */
315145247Sdamien#define IPW_EEPROM_S	(1 << 1)	/* Chip Select */
316145247Sdamien#define IPW_EEPROM_D	(1 << 2)	/* Serial data input */
317145247Sdamien#define IPW_EEPROM_Q	(1 << 4)	/* Serial data output */
318145247Sdamien
319145247Sdamien#define IPW_EEPROM_SHIFT_D	2
320145247Sdamien#define IPW_EEPROM_SHIFT_Q	4
321145247Sdamien
322145247Sdamien/*
323145247Sdamien * control and status registers access macros
324145247Sdamien */
325145247Sdamien#define CSR_READ_1(sc, reg)						\
326145247Sdamien	bus_space_read_1((sc)->sc_st, (sc)->sc_sh, (reg))
327145247Sdamien
328145247Sdamien#define CSR_READ_2(sc, reg)						\
329145247Sdamien	bus_space_read_2((sc)->sc_st, (sc)->sc_sh, (reg))
330145247Sdamien
331145247Sdamien#define CSR_READ_4(sc, reg)						\
332145247Sdamien	bus_space_read_4((sc)->sc_st, (sc)->sc_sh, (reg))
333145247Sdamien
334145247Sdamien#define CSR_WRITE_1(sc, reg, val)					\
335145247Sdamien	bus_space_write_1((sc)->sc_st, (sc)->sc_sh, (reg), (val))
336145247Sdamien
337145247Sdamien#define CSR_WRITE_2(sc, reg, val)					\
338145247Sdamien	bus_space_write_2((sc)->sc_st, (sc)->sc_sh, (reg), (val))
339145247Sdamien
340145247Sdamien#define CSR_WRITE_4(sc, reg, val)					\
341145247Sdamien	bus_space_write_4((sc)->sc_st, (sc)->sc_sh, (reg), (val))
342145247Sdamien
343145247Sdamien#define CSR_WRITE_MULTI_1(sc, reg, buf, len)				\
344145247Sdamien	bus_space_write_multi_1((sc)->sc_st, (sc)->sc_sh, (reg), 	\
345145247Sdamien	    (buf), (len))
346145247Sdamien
347145247Sdamien/*
348145247Sdamien * indirect memory space access macros
349145247Sdamien */
350156599Sdamien#define MEM_READ_1(sc, addr)						\
351156599Sdamien	(CSR_WRITE_4((sc), IPW_CSR_INDIRECT_ADDR, (addr)),		\
352156599Sdamien	 CSR_READ_1((sc), IPW_CSR_INDIRECT_DATA))
353156599Sdamien
354156599Sdamien#define MEM_READ_4(sc, addr)						\
355156599Sdamien	(CSR_WRITE_4((sc), IPW_CSR_INDIRECT_ADDR, (addr)),		\
356156599Sdamien	 CSR_READ_4((sc), IPW_CSR_INDIRECT_DATA))
357156599Sdamien
358145247Sdamien#define MEM_WRITE_1(sc, addr, val) do {					\
359145247Sdamien	CSR_WRITE_4((sc), IPW_CSR_INDIRECT_ADDR, (addr));		\
360145247Sdamien	CSR_WRITE_1((sc), IPW_CSR_INDIRECT_DATA, (val));		\
361145247Sdamien} while (/* CONSTCOND */0)
362145247Sdamien
363145247Sdamien#define MEM_WRITE_2(sc, addr, val) do {					\
364145247Sdamien	CSR_WRITE_4((sc), IPW_CSR_INDIRECT_ADDR, (addr));		\
365145247Sdamien	CSR_WRITE_2((sc), IPW_CSR_INDIRECT_DATA, (val));		\
366145247Sdamien} while (/* CONSTCOND */0)
367145247Sdamien
368145247Sdamien#define MEM_WRITE_4(sc, addr, val) do {					\
369145247Sdamien	CSR_WRITE_4((sc), IPW_CSR_INDIRECT_ADDR, (addr));		\
370145247Sdamien	CSR_WRITE_4((sc), IPW_CSR_INDIRECT_DATA, (val));		\
371145247Sdamien} while (/* CONSTCOND */0)
372145247Sdamien
373145247Sdamien#define MEM_WRITE_MULTI_1(sc, addr, buf, len) do {			\
374145247Sdamien	CSR_WRITE_4((sc), IPW_CSR_INDIRECT_ADDR, (addr));		\
375145247Sdamien	CSR_WRITE_MULTI_1((sc), IPW_CSR_INDIRECT_DATA, (buf), (len));	\
376145247Sdamien} while (/* CONSTCOND */0)
377145247Sdamien
378145247Sdamien/*
379145247Sdamien * EEPROM access macro
380145247Sdamien */
381145247Sdamien#define IPW_EEPROM_CTL(sc, val) do {					\
382145247Sdamien	MEM_WRITE_4((sc), IPW_MEM_EEPROM_CTL, (val));			\
383145247Sdamien	DELAY(IPW_EEPROM_DELAY);					\
384145247Sdamien} while (0)
385