revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / networks / realtek8180 / radio.c
blob2d0f74bd633e855f844487fa23f866f695d75fb8
1 /*
3 Copyright (C) 2001-2017 Neil Cafferkey
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 MA 02111-1307, USA.
23 #include "device.h"
25 #include "radio_protos.h"
26 #include "eeprom_protos.h"
27 #include "timer_protos.h"
28 #include "realtek8187.h"
31 static UBYTE GetPowerPair(struct DevUnit *unit, UWORD index,
32 struct DevBase *base);
33 static VOID WritePHY(struct DevUnit *unit, UWORD index, ULONG value,
34 struct DevBase *base);
37 static const UWORD gain_table[] =
39 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409,
40 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541,
41 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583,
42 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644,
43 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688,
44 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745,
45 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789,
46 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793,
47 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d,
48 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9,
49 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3,
50 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bb
54 static const UBYTE agc_table[] =
56 0x5e, 0x5e, 0x5e, 0x5e, 0x5d, 0x5b, 0x59, 0x57,
57 0x55, 0x53, 0x51, 0x4f, 0x4d, 0x4b, 0x49, 0x47,
58 0x45, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x39, 0x37,
59 0x35, 0x33, 0x31, 0x2f, 0x2d, 0x2b, 0x29, 0x27,
60 0x25, 0x23, 0x21, 0x1f, 0x1d, 0x1b, 0x19, 0x17,
61 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0b, 0x09, 0x07,
62 0x05, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
63 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
64 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
65 0x19, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
66 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2a,
67 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d,
68 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f,
69 0x2f, 0x2f, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
70 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
71 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31
75 static const UBYTE ofdm_table[] =
77 0x10, 0x0d, 0x01, 0x00, 0x14, 0xfb, 0xfb, 0x60,
78 0x00, 0x60, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00,
79 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xa8, 0x26,
80 0x32, 0x33, 0x07, 0xa5, 0x6f, 0x55, 0xc8, 0xb3,
81 0x0a, 0xe1, 0x2C, 0x8a, 0x86, 0x83, 0x34, 0x0f,
82 0x4f, 0x24, 0x6f, 0xc2, 0x6b, 0x40, 0x80, 0x00,
83 0xc0, 0xc1, 0x58, 0xf1, 0x00, 0xe4, 0x90, 0x3e,
84 0x6d, 0x3c, 0xfb, 0x07
88 static UBYTE rtl8225_power_tables[][8] =
90 {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02},
91 {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02},
92 {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02},
93 {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02},
94 {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03},
95 {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03},
96 {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},
97 {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}
101 static UBYTE rtl8225_ch14_power_tables[][8] =
103 {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00},
104 {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00},
105 {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00},
106 {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00},
107 {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00},
108 {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00},
109 {0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00},
110 {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}
114 static UBYTE rtl8225_ofdm_power[] = {0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4};
117 static const UBYTE eeprom_power_locations_l[] =
119 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x7a, 0x7b,
120 0x7c, 0x7d, 0x36, 0x37, 0x38, 0x39
124 static const UBYTE eeprom_power_locations_b[] =
126 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x7a, 0x7b,
127 0x7c, 0x7d, 0x36, 0x14, 0x38, 0x39
131 /****i* realtek8180.device/InitialiseRadio *********************************
133 * NAME
134 * InitialiseRadio
136 * SYNOPSIS
137 * success = InitialiseRadio(unit, reinsertion)
139 * BOOL InitialiseRadio(struct DevUnit *, BOOL);
141 * FUNCTION
143 * INPUTS
144 * unit
145 * reinsertion
147 * RESULT
148 * success - Success indicator.
150 ****************************************************************************
154 BOOL InitialiseRadio(struct DevUnit *unit, struct DevBase *base)
156 BOOL success = TRUE;
157 UWORD i;
159 /* Get radio revision */
161 if((LEWord(ReadEEPROM(unit, R8180ROM_RFCHIPID, base)) & 0xff) == 5)
163 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, 0x80);
164 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSSELECT, 0x80);
165 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSENABLE, 0x80);
166 BusyMilliDelay(500, base);
168 WriteRadio(unit, 0x0, 0x1b7, base);
170 if(ReadRadio(unit, 0x8, base) != 0x588 ||
171 ReadRadio(unit, 0x9, base) != 0x700)
172 unit->radio_type = RTL8225_RADIO;
173 else
174 unit->radio_type = RTL8225V2_RADIO;
175 WriteRadio(unit, 0x0, 0xb7, base);
177 else
178 unit->radio_type = RTL8225V2B_RADIO;
180 /* Initialise radio */
182 WriteRadio(unit, 0x0, 0xb7, base);
183 WriteRadio(unit, 0x1, 0xee0, base);
184 WriteRadio(unit, 0x2, 0x44d, base);
185 WriteRadio(unit, 0x3, 0x441, base);
186 WriteRadio(unit, 0x4, 0x8c3, base);
187 WriteRadio(unit, 0x5, 0xc72, base);
188 WriteRadio(unit, 0x6, 0xe6, base);
189 WriteRadio(unit, 0x7, 0x82a, base);
190 WriteRadio(unit, 0x8, 0x3f, base);
191 WriteRadio(unit, 0x9, 0x335, base);
192 WriteRadio(unit, 0xa, 0x9d4, base);
193 WriteRadio(unit, 0xb, 0x7bb, base);
194 WriteRadio(unit, 0xc, 0x850, base);
195 WriteRadio(unit, 0xd, 0xcdf, base);
196 WriteRadio(unit, 0xe, 0x2b, base);
197 WriteRadio(unit, 0xf, 0x114, base);
198 WriteRadio(unit, 0x0, 0x1b7, base);
200 for(i = 0; i < sizeof(gain_table) / sizeof(UWORD); i++)
202 WriteRadio(unit, 0x1, i + 1, base);
203 WriteRadio(unit, 0x2, gain_table[i], base);
206 WriteRadio(unit, 0x3, 0x80, base);
207 WriteRadio(unit, 0x5, 0x4, base);
208 WriteRadio(unit, 0x0, 0xb7, base);
209 BusyMilliDelay(100, base);
211 WriteRadio(unit, 0x2, 0xc4d, base);
212 WriteRadio(unit, 0x2, 0x44d, base);
213 WriteRadio(unit, 0x0, 0x2bf, base);
215 unit->ByteOut(unit->card, 0x100 + R8180REG_TXGAINCCK, 0x3);
216 unit->ByteOut(unit->card, 0x100 + R8180REG_TXGAINOFDM, 0x7);
217 unit->ByteOut(unit->card, 0x100 + R8180REG_TXANTENNA, 0x3);
219 WriteOFDM(unit, 0x80, 0x12, base);
220 for(i = 0; i < sizeof(agc_table); i++)
222 WriteOFDM(unit, 0xf, agc_table[i], base);
223 WriteOFDM(unit, 0xe, 0x80 + i, base);
224 WriteOFDM(unit, 0xe, 0, base);
226 WriteOFDM(unit, 0x80, 0x10, base);
228 for(i = 0; i < sizeof(ofdm_table); i++)
229 WriteOFDM(unit, i, ofdm_table[i], base);
231 unit->LELongOut(unit->card, 0x100 + R8180REG_ACVO, (7 << 12) | (3 << 8) | 0x1c);
232 unit->LELongOut(unit->card, 0x100 + R8180REG_ACVI, (7 << 12) | (3 << 8) | 0x1c);
233 unit->LELongOut(unit->card, 0x100 + R8180REG_ACBE, (7 << 12) | (3 << 8) | 0x1c);
234 unit->LELongOut(unit->card, 0x100 + R8180REG_ACBK, (7 << 12) | (3 << 8) | 0x1c);
236 WriteOFDM(unit, 0x97, 0x46, base);
237 WriteOFDM(unit, 0xa4, 0xb6, base);
238 WriteOFDM(unit, 0x85, 0xfc, base);
239 WriteCCK(unit, 0xc1, 0x88, base);
241 /* Return */
243 return success;
248 VOID GetPower(struct DevUnit *unit, struct DevBase *base)
250 const UBYTE *locations;
251 UBYTE value;
252 UWORD i;
254 if(unit->generation == RTL8187L_GEN)
255 locations = eeprom_power_locations_l;
256 else
257 locations = eeprom_power_locations_b;
259 for(i = 0; i < 14; i++)
261 value = GetPowerPair(unit, locations[i], base);
262 unit->cck_power[i] = value & 0xf;
263 unit->ofdm_power[i] = value >> 4;
269 static UBYTE GetPowerPair(struct DevUnit *unit, UWORD index,
270 struct DevBase *base)
272 UWORD value;
274 value = LEWord(ReadEEPROM(unit, index >> 1, base));
275 if((index & 0x1) != 0)
276 value >>= 8;
278 return (UBYTE)value;
283 VOID SetPower(struct DevUnit *unit, struct DevBase *base)
285 UBYTE power_level, tx_gain, table_no, n;
286 const UBYTE *power_table;
287 UWORD i;
288 ULONG tx_conf, loop_tx_conf, channel_code;
290 /* Get CCK power level and gain */
292 power_level = unit->cck_power[unit->channel];
293 if(unit->radio_type == RTL8225_RADIO)
295 if(power_level > 11)
296 power_level = 11;
297 table_no = power_level % 6;
298 tx_gain = (2 << power_level / 6) - 1;
300 else
302 if(power_level > 15)
303 power_level = 15;
304 if(unit->generation != RTL8187B1_GEN)
305 power_level += 7;
306 power_level += unit->base_cck_power;
307 if(power_level > 35)
308 power_level = 35;
310 table_no = 7;
311 tx_gain = power_level << 1;
314 /* Adjust power table number for RTL8225v2b */
316 if(unit->radio_type == RTL8225V2B_RADIO)
318 if(unit->generation == RTL8187B1_GEN)
320 if(power_level > 11 && unit->channel != 14)
321 table_no = 5;
322 else if(power_level > 6)
323 table_no = 6;
324 else
325 table_no = 7;
327 else
329 if(power_level > 5)
330 table_no = 6;
331 else
332 table_no = 7;
333 if(unit->channel != 14)
335 if(power_level > 17)
336 table_no = 4;
337 else if(power_level > 11)
338 table_no = 5;
343 /* Get CCK power table and write it to chip */
345 if(unit->channel == 14)
346 power_table = rtl8225_ch14_power_tables[table_no];
347 else
348 power_table = rtl8225_power_tables[table_no];
350 for(i = 0; i < 8; i++)
351 WriteCCK(unit, 0x44 + i, power_table[i], base);
353 /* Set CCK gain */
355 unit->ByteOut(unit->card, 0x100 + R8180REG_TXGAINCCK, tx_gain);
356 BusyMilliDelay(1, base);
358 /* Get OFDM power level */
360 power_level = unit->ofdm_power[unit->channel];
361 if(power_level > 15)
362 power_level = 15;
363 if(unit->radio_type <= RTL8225V2_RADIO)
365 power_level += 10;
367 else
369 if(unit->generation != RTL8187B1_GEN)
370 power_level += 10;
371 else
372 power_level += 2;
374 if(unit->radio_type >= RTL8225V2_RADIO)
375 power_level += unit->base_ofdm_power;
376 if(power_level > 35)
377 power_level = 35;
379 /* Enable analogue parameter 2 */
381 if(unit->radio_type <= RTL8225V2_RADIO)
383 unit->ByteOut(unit->card, 0x100 + R8180REG_EEPROM, R8180ECMD_CONFIG);
384 unit->ByteOut(unit->card, 0x100 + R8180REG_CONFIG3,
385 unit->ByteIn(unit->card, 0x100 + R8180REG_CONFIG3)
386 | R8180REG_CONFIG3F_ANAPARAMWRITE);
387 unit->LELongOut(unit->card, 0x100 + R8180REG_ANAPARAM2, 0x860c7312);
388 unit->ByteOut(unit->card, 0x100 + R8180REG_CONFIG3,
389 unit->ByteIn(unit->card, 0x100 + R8180REG_CONFIG3)
390 & ~R8180REG_CONFIG3F_ANAPARAMWRITE);
391 unit->ByteOut(unit->card, 0x100 + R8180REG_EEPROM, 0);
394 /* Set OFDM gain */
396 if(unit->radio_type == RTL8225_RADIO)
397 tx_gain = (2 << power_level / 6) - 1;
398 else
399 tx_gain = power_level << 1;
401 unit->ByteOut(unit->card, 0x100 + R8180REG_TXGAINOFDM, tx_gain);
403 /* Set up OFDM power */
405 if(unit->radio_type == RTL8225V2B_RADIO)
407 if(unit->generation == RTL8187B1_GEN)
409 if(power_level > 11)
410 n = 0x5c;
411 else
412 n = 0x60;
414 else
416 if(power_level > 17)
417 n = 0x50;
418 else if(power_level > 11)
419 n = 0x54;
420 else
421 n = 0x5c;
423 WriteOFDM(unit, 0x87, n, base);
424 WriteOFDM(unit, 0x89, n, base);
426 else if(unit->radio_type == RTL8225V2_RADIO)
428 WriteOFDM(unit, 0x2, 0x42, base);
429 WriteOFDM(unit, 0x5, 0, base);
430 WriteOFDM(unit, 0x6, 0x40, base);
431 WriteOFDM(unit, 0x7, 0, base);
432 WriteOFDM(unit, 0x8, 0x40, base);
434 else
436 n = rtl8225_ofdm_power[power_level % 6];
437 WriteOFDM(unit, 0x2, 0x42, base);
438 WriteOFDM(unit, 0x5, n, base);
439 WriteOFDM(unit, 0x6, 0, base);
440 WriteOFDM(unit, 0x7, n, base);
441 WriteOFDM(unit, 0x8, 0, base);
444 BusyMilliDelay(1, base);
446 /* Set channel */
448 tx_conf = unit->LELongIn(unit->card, 0x100 + R8180REG_TXCONF);
449 loop_tx_conf = tx_conf & ~R8180REG_TXCONFF_LOOPBACK
450 | 1 << R8180REG_TXCONFB_LOOPBACK;
451 unit->LELongOut(unit->card, 0x100 + R8180REG_TXCONF,
452 loop_tx_conf);
453 if(unit->channel == 14)
454 channel_code = 0xf72;
455 else
456 channel_code = 0x7dc + unit->channel * 0x80;
457 WriteRadio(unit, 0x7, channel_code, base);
458 BusyMilliDelay(10, base);
459 unit->LELongOut(unit->card, 0x100 + R8180REG_TXCONF, tx_conf);
461 return;
466 /****i* realtek8180.device/WriteCCK ****************************************
468 * NAME
469 * WriteCCK -- Write to a CCK PHY register.
471 * SYNOPSIS
472 * WriteCCK(unit, index, value)
474 * VOID WriteCCK(struct DevUnit *, UWORD, UWORD);
476 * INPUTS
477 * unit - A unit of this device.
478 * index - Offset of register.
479 * value - Value to write to register.
481 * RESULT
482 * None
484 ****************************************************************************
488 VOID WriteCCK(struct DevUnit *unit, UWORD index, UWORD value,
489 struct DevBase *base)
491 WritePHY(unit, index, value | 1 << 16, base);
493 return;
498 /****i* realtek8180.device/WriteOFDM ***************************************
500 * NAME
501 * WriteOFDM -- Write to an OFDM PHY register.
503 * SYNOPSIS
504 * WriteOFDM(unit, index, value)
506 * VOID WriteOFDM(struct DevUnit *, UWORD, UWORD);
508 * INPUTS
509 * unit - A unit of this device.
510 * index - Offset of register.
511 * value - Value to write to register.
513 * RESULT
514 * None
516 ****************************************************************************
520 VOID WriteOFDM(struct DevUnit *unit, UWORD index, UWORD value,
521 struct DevBase *base)
523 WritePHY(unit, index, value, base);
525 return;
530 /****i* realtek8180.device/WritePHY ****************************************
532 * NAME
533 * WritePHY -- Write to a CCK PHY register.
535 * SYNOPSIS
536 * WritePHY(unit, index, value)
538 * VOID WritePHY(struct DevUnit *, UWORD, ULONG);
540 * INPUTS
541 * unit - A unit of this device.
542 * index - Offset of register.
543 * value - Value to write to register.
545 * RESULT
546 * None
548 ****************************************************************************
552 static VOID WritePHY(struct DevUnit *unit, UWORD index, ULONG value,
553 struct DevBase *base)
555 ULONG data;
557 data = value << 8 | index | 0x80;
558 unit->ByteOut(unit->card, 0x100 + R8180REG_PHY + 3, data >> 24);
559 unit->ByteOut(unit->card, 0x100 + R8180REG_PHY + 2, data >> 16);
560 unit->ByteOut(unit->card, 0x100 + R8180REG_PHY + 1, data >> 8);
561 unit->ByteOut(unit->card, 0x100 + R8180REG_PHY, data);
563 return;
568 /****i* realtek8180.device/ReadRadio ***************************************
570 * NAME
571 * ReadRadio -- Read a radio register.
573 * SYNOPSIS
574 * value = ReadRadio(unit, index)
576 * UWORD ReadRadio(struct DevUnit *, UWORD);
578 * INPUTS
579 * unit - A unit of this device.
580 * index - Offset of register.
582 * RESULT
583 * value - Value read from radio register.
585 ****************************************************************************
589 UWORD ReadRadio(struct DevUnit *unit, UWORD index,
590 struct DevBase *base)
592 UWORD value = 0, value2, output_reg, enable_reg, select_reg;
593 WORD i, j;
595 output_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSOUTPUT)
596 & 0xfff0;
597 enable_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSENABLE);
598 select_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSSELECT);
599 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSENABLE,
600 enable_reg | 0xf);
601 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSSELECT,
602 select_reg | 0xf);
603 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
604 output_reg | 0x4);
605 BusyMicroDelay(4, base);
607 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, output_reg);
608 BusyMicroDelay(5, base);
610 for(i = 4; i >= 0; i--)
612 value2 = output_reg | index >> i & 1;
614 if((i & 0x1) == 0)
616 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, value2);
617 BusyMicroDelay(1, base);
620 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, value2 | 0x2);
621 BusyMicroDelay(2, base);
623 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, value2 | 0x2);
624 BusyMicroDelay(2, base);
626 if((i & 0x1) != 0)
628 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, value2);
629 BusyMicroDelay(1, base);
633 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
634 output_reg | 0xa);
635 BusyMicroDelay(2, base);
637 for(i = 0; i < 2; i++)
639 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
640 output_reg | 0x8);
641 BusyMicroDelay(2, base);
644 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSENABLE,
645 (enable_reg | 0xe) & ~1);
647 for(i = 11; i >= 0; i--)
649 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
650 output_reg | 0x8);
651 BusyMicroDelay(1, base);
653 for(j = 0; j < 3; j++)
655 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
656 output_reg | 0xa);
657 BusyMicroDelay(2, base);
660 if((unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSINPUT) & 0x2)
661 != 0)
662 value |= 1 << i;
664 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
665 output_reg | 0x8);
666 BusyMicroDelay(2, base);
669 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, output_reg | 0xc);
670 BusyMicroDelay(2, base);
672 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSENABLE, enable_reg);
673 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSSELECT, select_reg);
674 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, 0x3a0);
676 return value;
681 /****i* realtek8180.device/WriteRadio **************************************
683 * NAME
684 * WriteRadio -- Write to a radio register.
686 * SYNOPSIS
687 * WriteRadio(unit, index, value)
689 * VOID WriteRadio(struct DevUnit *, UWORD, UWORD);
691 * INPUTS
692 * unit - A unit of this device.
693 * index - Offset of register.
694 * value - Value to write to register.
696 * RESULT
697 * None
699 ****************************************************************************
703 VOID WriteRadio(struct DevUnit *unit, UWORD index, UWORD value,
704 struct DevBase *base)
706 UWORD output_reg, enable_reg, select_reg, value2;
707 ULONG data;
708 WORD i;
710 data = (value << 4) | (index & 0xf);
712 output_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSOUTPUT)
713 & 0xfff3;
714 enable_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSENABLE);
715 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSENABLE,
716 enable_reg | 0x7);
717 select_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSSELECT);
718 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSSELECT,
719 select_reg | 0x7);
720 BusyMicroDelay(10, base);
722 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
723 output_reg | 0x4);
724 BusyMicroDelay(2, base);
726 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, output_reg);
727 BusyMicroDelay(10, base);
729 if(unit->bus == USB_BUS && unit->generation >= RTL8187B0_GEN)
730 unit->LEWordOut(unit->card, 0x8225 << 16 | 0x200 + index, value);
731 else
733 for(i = 15; i >= 0; i--)
735 value2 = output_reg | (data & (1 << i)) >> i;
737 if((i & 1) != 0)
738 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
739 value2);
740 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
741 value2 | 0x2);
742 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
743 value2 | 0x2);
744 if((i & 1) == 0)
745 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
746 value2);
750 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
751 output_reg | 0x4);
752 BusyMicroDelay(10, base);
754 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
755 output_reg | 0x4);
756 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSSELECT, select_reg);
758 return;