grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / networks / realtek8180 / radio.c
blob54d68009d46dd6f199314ae42eeacd3b31a2edee
1 /*
3 Copyright (C) 2001-2011 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
87 #if !defined(__AROS__)
88 static const UBYTE cck_power_table1[] =
90 0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03
94 static const UBYTE cck_power_table2[] =
96 0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03
98 #endif
100 static UBYTE rtl8225_power_tables[][8] =
102 {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02},
103 {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02},
104 {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02},
105 {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02},
106 {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03},
107 {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03},
108 {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},
109 {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}
113 static UBYTE rtl8225_ch14_power_tables[][8] =
115 {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00},
116 {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00},
117 {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00},
118 {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00},
119 {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00},
120 {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00},
121 {0x30, 0x2f, 0x29, 0x15, 0x00, 0x00, 0x00, 0x00},
122 {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}
126 static UBYTE rtl8225_ofdm_power[] = {0x80, 0x90, 0xa2, 0xb5, 0xcb, 0xe4};
129 static const UBYTE eeprom_power_locations_l[] =
131 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x7a, 0x7b,
132 0x7c, 0x7d, 0x36, 0x37, 0x38, 0x39
136 static const UBYTE eeprom_power_locations_b[] =
138 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x7a, 0x7b,
139 0x7c, 0x7d, 0x36, 0x14, 0x38, 0x39
143 /****i* realtek8180.device/InitialiseRadio *********************************
145 * NAME
146 * InitialiseRadio
148 * SYNOPSIS
149 * success = InitialiseRadio(unit, reinsertion)
151 * BOOL InitialiseRadio(struct DevUnit *, BOOL);
153 * FUNCTION
155 * INPUTS
156 * unit
157 * reinsertion
159 * RESULT
160 * success - Success indicator.
162 ****************************************************************************
166 BOOL InitialiseRadio(struct DevUnit *unit, struct DevBase *base)
168 BOOL success = TRUE;
169 UWORD i;
171 /* Get radio revision */
173 if((LEWord(ReadEEPROM(unit, R8180ROM_RFCHIPID, base)) & 0xff) == 5)
175 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, 0x80);
176 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSSELECT, 0x80);
177 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSENABLE, 0x80);
178 BusyMilliDelay(500, base);
180 WriteRadio(unit, 0x0, 0x1b7, base);
182 if(ReadRadio(unit, 0x8, base) != 0x588 ||
183 ReadRadio(unit, 0x9, base) != 0x700)
184 unit->radio_type = RTL8225_RADIO;
185 else
186 unit->radio_type = RTL8225V2_RADIO;
187 WriteRadio(unit, 0x0, 0xb7, base);
189 else
190 unit->radio_type = RTL8225V2B_RADIO;
192 /* Initialise radio */
194 WriteRadio(unit, 0x0, 0xb7, base);
195 WriteRadio(unit, 0x1, 0xee0, base);
196 WriteRadio(unit, 0x2, 0x44d, base);
197 WriteRadio(unit, 0x3, 0x441, base);
198 WriteRadio(unit, 0x4, 0x8c3, base);
199 WriteRadio(unit, 0x5, 0xc72, base);
200 WriteRadio(unit, 0x6, 0xe6, base);
201 WriteRadio(unit, 0x7, 0x82a, base);
202 WriteRadio(unit, 0x8, 0x3f, base);
203 WriteRadio(unit, 0x9, 0x335, base);
204 WriteRadio(unit, 0xa, 0x9d4, base);
205 WriteRadio(unit, 0xb, 0x7bb, base);
206 WriteRadio(unit, 0xc, 0x850, base);
207 WriteRadio(unit, 0xd, 0xcdf, base);
208 WriteRadio(unit, 0xe, 0x2b, base);
209 WriteRadio(unit, 0xf, 0x114, base);
210 WriteRadio(unit, 0x0, 0x1b7, base);
212 for(i = 0; i < sizeof(gain_table) / sizeof(UWORD); i++)
214 WriteRadio(unit, 0x1, i + 1, base);
215 WriteRadio(unit, 0x2, gain_table[i], base);
218 WriteRadio(unit, 0x3, 0x80, base);
219 WriteRadio(unit, 0x5, 0x4, base);
220 WriteRadio(unit, 0x0, 0xb7, base);
221 BusyMilliDelay(100, base);
223 WriteRadio(unit, 0x2, 0xc4d, base);
224 WriteRadio(unit, 0x2, 0x44d, base);
225 WriteRadio(unit, 0x0, 0x2bf, base);
227 unit->ByteOut(unit->card, 0x100 + R8180REG_TXGAINCCK, 0x3);
228 unit->ByteOut(unit->card, 0x100 + R8180REG_TXGAINOFDM, 0x7);
229 unit->ByteOut(unit->card, 0x100 + R8180REG_TXANTENNA, 0x3);
231 WriteOFDM(unit, 0x80, 0x12, base);
232 for(i = 0; i < sizeof(agc_table); i++)
234 WriteOFDM(unit, 0xf, agc_table[i], base);
235 WriteOFDM(unit, 0xe, 0x80 + i, base);
236 WriteOFDM(unit, 0xe, 0, base);
238 WriteOFDM(unit, 0x80, 0x10, base);
240 for(i = 0; i < sizeof(ofdm_table); i++)
241 WriteOFDM(unit, i, ofdm_table[i], base);
243 unit->LELongOut(unit->card, 0x100 + R8180REG_ACVO, (7 << 12) | (3 << 8) | 0x1c);
244 unit->LELongOut(unit->card, 0x100 + R8180REG_ACVI, (7 << 12) | (3 << 8) | 0x1c);
245 unit->LELongOut(unit->card, 0x100 + R8180REG_ACBE, (7 << 12) | (3 << 8) | 0x1c);
246 unit->LELongOut(unit->card, 0x100 + R8180REG_ACBK, (7 << 12) | (3 << 8) | 0x1c);
248 WriteOFDM(unit, 0x97, 0x46, base);
249 WriteOFDM(unit, 0xa4, 0xb6, base);
250 WriteOFDM(unit, 0x85, 0xfc, base);
251 WriteCCK(unit, 0xc1, 0x88, base);
253 /* Return */
255 return success;
260 VOID GetPower(struct DevUnit *unit, struct DevBase *base)
262 const UBYTE *locations;
263 UBYTE value;
264 UWORD i;
266 if(unit->generation == RTL8187L_GEN)
267 locations = eeprom_power_locations_l;
268 else
269 locations = eeprom_power_locations_b;
271 for(i = 0; i < 14; i++)
273 value = GetPowerPair(unit, locations[i], base);
274 unit->cck_power[i] = value & 0xf;
275 unit->ofdm_power[i] = value >> 4;
281 static UBYTE GetPowerPair(struct DevUnit *unit, UWORD index,
282 struct DevBase *base)
284 UWORD value;
286 value = LEWord(ReadEEPROM(unit, index >> 1, base));
287 if((index & 0x1) != 0)
288 value >>= 8;
290 return (UBYTE)value;
295 VOID SetPower(struct DevUnit *unit, struct DevBase *base)
297 UBYTE power_level, tx_gain, table_no, n;
298 const UBYTE *power_table;
299 UWORD i;
300 ULONG tx_conf, loop_tx_conf, channel_code;
302 /* Get CCK power level and gain */
304 power_level = unit->cck_power[unit->channel];
305 if(unit->radio_type == RTL8225_RADIO)
307 if(power_level > 11)
308 power_level = 11;
309 table_no = power_level % 6;
310 tx_gain = (2 << power_level / 6) - 1;
312 else
314 if(power_level > 15)
315 power_level = 15;
316 if(unit->generation != RTL8187B1_GEN)
317 power_level += 7;
318 power_level += unit->base_cck_power;
319 if(power_level > 35)
320 power_level = 35;
322 table_no = 7;
323 tx_gain = power_level << 1;
326 /* Adjust power table number for RTL8225v2b */
328 if(unit->radio_type == RTL8225V2B_RADIO)
330 if(unit->generation == RTL8187B1_GEN)
332 if(power_level > 11 && unit->channel != 14)
333 table_no = 5;
334 else if(power_level > 6)
335 table_no = 6;
336 else
337 table_no = 7;
339 else
341 if(power_level > 5)
342 table_no = 6;
343 else
344 table_no = 7;
345 if(unit->channel != 14)
347 if(power_level > 17)
348 table_no = 4;
349 else if(power_level > 11)
350 table_no = 5;
355 /* Get CCK power table and write it to chip */
357 if(unit->channel == 14)
358 power_table = rtl8225_ch14_power_tables[table_no];
359 else
360 power_table = rtl8225_power_tables[table_no];
362 for(i = 0; i < 8; i++)
363 WriteCCK(unit, 0x44 + i, power_table[i], base);
365 /* Set CCK gain */
367 unit->ByteOut(unit->card, 0x100 + R8180REG_TXGAINCCK, tx_gain);
368 BusyMilliDelay(1, base);
370 /* Get OFDM power level */
372 power_level = unit->ofdm_power[unit->channel];
373 if(power_level > 15)
374 power_level = 15;
375 if(unit->radio_type <= RTL8225V2_RADIO)
377 power_level += 10;
379 else
381 if(unit->generation != RTL8187B1_GEN)
382 power_level += 10;
383 else
384 power_level += 2;
386 if(unit->radio_type >= RTL8225V2_RADIO)
387 power_level += unit->base_ofdm_power;
388 if(power_level > 35)
389 power_level = 35;
391 /* Enable analogue parameter 2 */
393 if(unit->radio_type <= RTL8225V2_RADIO)
395 unit->ByteOut(unit->card, 0x100 + R8180REG_EEPROM, R8180ECMD_CONFIG);
396 unit->ByteOut(unit->card, 0x100 + R8180REG_CONFIG3,
397 unit->ByteIn(unit->card, 0x100 + R8180REG_CONFIG3)
398 | R8180REG_CONFIG3F_ANAPARAMWRITE);
399 unit->LELongOut(unit->card, 0x100 + R8180REG_ANAPARAM2, 0x860c7312);
400 unit->ByteOut(unit->card, 0x100 + R8180REG_CONFIG3,
401 unit->ByteIn(unit->card, 0x100 + R8180REG_CONFIG3)
402 & ~R8180REG_CONFIG3F_ANAPARAMWRITE);
403 unit->ByteOut(unit->card, 0x100 + R8180REG_EEPROM, 0);
406 /* Set OFDM gain */
408 if(unit->radio_type == RTL8225_RADIO)
409 tx_gain = (2 << power_level / 6) - 1;
410 else
411 tx_gain = power_level << 1;
413 unit->ByteOut(unit->card, 0x100 + R8180REG_TXGAINOFDM, tx_gain);
415 /* Set up OFDM power */
417 if(unit->radio_type == RTL8225V2B_RADIO)
419 if(unit->generation == RTL8187B1_GEN)
421 if(power_level > 11)
422 n = 0x5c;
423 else
424 n = 0x60;
426 else
428 if(power_level > 17)
429 n = 0x50;
430 else if(power_level > 11)
431 n = 0x54;
432 else
433 n = 0x5c;
435 WriteOFDM(unit, 0x87, n, base);
436 WriteOFDM(unit, 0x89, n, base);
438 else if(unit->radio_type == RTL8225V2_RADIO)
440 WriteOFDM(unit, 0x2, 0x42, base);
441 WriteOFDM(unit, 0x5, 0, base);
442 WriteOFDM(unit, 0x6, 0x40, base);
443 WriteOFDM(unit, 0x7, 0, base);
444 WriteOFDM(unit, 0x8, 0x40, base);
446 else
448 n = rtl8225_ofdm_power[power_level % 6];
449 WriteOFDM(unit, 0x2, 0x42, base);
450 WriteOFDM(unit, 0x5, n, base);
451 WriteOFDM(unit, 0x6, 0, base);
452 WriteOFDM(unit, 0x7, n, base);
453 WriteOFDM(unit, 0x8, 0, base);
456 BusyMilliDelay(1, base);
458 /* Set channel */
460 tx_conf = unit->LELongIn(unit->card, 0x100 + R8180REG_TXCONF);
461 loop_tx_conf = tx_conf & ~R8180REG_TXCONFF_LOOPBACK
462 | 1 << R8180REG_TXCONFB_LOOPBACK;
463 unit->LELongOut(unit->card, 0x100 + R8180REG_TXCONF,
464 loop_tx_conf);
465 if(unit->channel == 14)
466 channel_code = 0xf72;
467 else
468 channel_code = 0x7dc + unit->channel * 0x80;
469 WriteRadio(unit, 0x7, channel_code, base);
470 BusyMilliDelay(10, base);
471 unit->LELongOut(unit->card, 0x100 + R8180REG_TXCONF, tx_conf);
473 return;
478 /****i* realtek8180.device/WriteCCK ****************************************
480 * NAME
481 * WriteCCK -- Write to a CCK PHY register.
483 * SYNOPSIS
484 * WriteCCK(unit, index, value)
486 * VOID WriteCCK(struct DevUnit *, UWORD, UWORD);
488 * INPUTS
489 * unit - A unit of this device.
490 * index - Offset of register.
491 * value - Value to write to register.
493 * RESULT
494 * None
496 ****************************************************************************
500 VOID WriteCCK(struct DevUnit *unit, UWORD index, UWORD value,
501 struct DevBase *base)
503 WritePHY(unit, index, value | 1 << 16, base);
505 return;
510 /****i* realtek8180.device/WriteOFDM ***************************************
512 * NAME
513 * WriteOFDM -- Write to an OFDM PHY register.
515 * SYNOPSIS
516 * WriteOFDM(unit, index, value)
518 * VOID WriteOFDM(struct DevUnit *, UWORD, UWORD);
520 * INPUTS
521 * unit - A unit of this device.
522 * index - Offset of register.
523 * value - Value to write to register.
525 * RESULT
526 * None
528 ****************************************************************************
532 VOID WriteOFDM(struct DevUnit *unit, UWORD index, UWORD value,
533 struct DevBase *base)
535 WritePHY(unit, index, value, base);
537 return;
542 /****i* realtek8180.device/WritePHY ****************************************
544 * NAME
545 * WritePHY -- Write to a CCK PHY register.
547 * SYNOPSIS
548 * WritePHY(unit, index, value)
550 * VOID WritePHY(struct DevUnit *, UWORD, ULONG);
552 * INPUTS
553 * unit - A unit of this device.
554 * index - Offset of register.
555 * value - Value to write to register.
557 * RESULT
558 * None
560 ****************************************************************************
564 static VOID WritePHY(struct DevUnit *unit, UWORD index, ULONG value,
565 struct DevBase *base)
567 ULONG data;
569 data = value << 8 | index | 0x80;
570 unit->ByteOut(unit->card, 0x100 + R8180REG_PHY + 3, data >> 24);
571 unit->ByteOut(unit->card, 0x100 + R8180REG_PHY + 2, data >> 16);
572 unit->ByteOut(unit->card, 0x100 + R8180REG_PHY + 1, data >> 8);
573 unit->ByteOut(unit->card, 0x100 + R8180REG_PHY, data);
575 return;
580 /****i* realtek8180.device/ReadRadio ***************************************
582 * NAME
583 * ReadRadio -- Read a radio register.
585 * SYNOPSIS
586 * value = ReadRadio(unit, index)
588 * UWORD ReadRadio(struct DevUnit *, UWORD);
590 * INPUTS
591 * unit - A unit of this device.
592 * index - Offset of register.
594 * RESULT
595 * value - Value read from radio register.
597 ****************************************************************************
601 UWORD ReadRadio(struct DevUnit *unit, UWORD index,
602 struct DevBase *base)
604 UWORD value = 0, value2, output_reg, enable_reg, select_reg;
605 WORD i, j;
607 output_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSOUTPUT)
608 & 0xfff0;
609 enable_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSENABLE);
610 select_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSSELECT);
611 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSENABLE,
612 enable_reg | 0xf);
613 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSSELECT,
614 select_reg | 0xf);
615 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
616 output_reg | 0x4);
617 BusyMicroDelay(4, base);
619 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, output_reg);
620 BusyMicroDelay(5, base);
622 for(i = 4; i >= 0; i--)
624 value2 = output_reg | index >> i & 1;
626 if((i & 0x1) == 0)
628 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, value2);
629 BusyMicroDelay(1, base);
632 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, value2 | 0x2);
633 BusyMicroDelay(2, base);
635 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, value2 | 0x2);
636 BusyMicroDelay(2, base);
638 if((i & 0x1) != 0)
640 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, value2);
641 BusyMicroDelay(1, base);
645 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
646 output_reg | 0xa);
647 BusyMicroDelay(2, base);
649 for(i = 0; i < 2; i++)
651 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
652 output_reg | 0x8);
653 BusyMicroDelay(2, base);
656 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSENABLE,
657 (enable_reg | 0xe) & ~1);
659 for(i = 11; i >= 0; i--)
661 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
662 output_reg | 0x8);
663 BusyMicroDelay(1, base);
665 for(j = 0; j < 3; j++)
667 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
668 output_reg | 0xa);
669 BusyMicroDelay(2, base);
672 if((unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSINPUT) & 0x2)
673 != 0)
674 value |= 1 << i;
676 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
677 output_reg | 0x8);
678 BusyMicroDelay(2, base);
681 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, output_reg | 0xc);
682 BusyMicroDelay(2, base);
684 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSENABLE, enable_reg);
685 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSSELECT, select_reg);
686 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, 0x3a0);
688 return value;
693 /****i* realtek8180.device/WriteRadio **************************************
695 * NAME
696 * WriteRadio -- Write to a radio register.
698 * SYNOPSIS
699 * WriteRadio(unit, index, value)
701 * VOID WriteRadio(struct DevUnit *, UWORD, UWORD);
703 * INPUTS
704 * unit - A unit of this device.
705 * index - Offset of register.
706 * value - Value to write to register.
708 * RESULT
709 * None
711 ****************************************************************************
715 VOID WriteRadio(struct DevUnit *unit, UWORD index, UWORD value,
716 struct DevBase *base)
718 UWORD output_reg, enable_reg, select_reg, value2;
719 ULONG data;
720 WORD i;
722 data = (value << 4) | (index & 0xf);
724 output_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSOUTPUT)
725 & 0xfff3;
726 enable_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSENABLE);
727 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSENABLE,
728 enable_reg | 0x7);
729 select_reg = unit->LEWordIn(unit->card, 0x100 + R8180REG_RFPINSSELECT);
730 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSSELECT,
731 select_reg | 0x7);
732 BusyMicroDelay(10, base);
734 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
735 output_reg | 0x4);
736 BusyMicroDelay(2, base);
738 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT, output_reg);
739 BusyMicroDelay(10, base);
741 if(unit->bus == USB_BUS && unit->generation >= RTL8187B0_GEN)
742 unit->LEWordOut(unit->card, 0x8225 << 16 | 0x200 + index, value);
743 else
745 for(i = 15; i >= 0; i--)
747 value2 = output_reg | (data & (1 << i)) >> i;
749 if((i & 1) != 0)
750 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
751 value2);
752 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
753 value2 | 0x2);
754 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
755 value2 | 0x2);
756 if((i & 1) == 0)
757 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
758 value2);
762 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
763 output_reg | 0x4);
764 BusyMicroDelay(10, base);
766 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSOUTPUT,
767 output_reg | 0x4);
768 unit->LEWordOut(unit->card, 0x100 + R8180REG_RFPINSSELECT, select_reg);
770 return;