2 * ASIX AX88172/AX88772/AX88178 USB 2.0 Ethernet Driver.
3 * Copyright (c) 2008, 2011 S.Zharski <imker@gmx.li>
4 * Distributed under the terms of the MIT license.
6 * Heavily based on code of the
7 * Driver for USB Ethernet Control Model devices
8 * Copyright (C) 2008 Michael Lotz <mmlr@mlotz.ch>
9 * Distributed under the terms of the MIT license.
14 #include "AX88178Device.h"
16 #include <net/if_media.h>
18 #include "ASIXVendorRequests.h"
22 // Most of vendor requests for all supported chip types use the same
23 // constants (see ASIXVendorRequests.h) but the layout of request data
24 // may be slightly diferrent for specific chip type. Below is a quick
25 // reference for AX88178 vendor requests data layout.
27 // READ_RXTX_SRAM, //C002_AA0B_0C00_0800 Rx/Tx SRAM Read
28 // WRITE_RXTX_SRAM, //4003_AA0B_0C00_0800 Rx/Tx SRAM Write
29 // SW_MII_OP, //4006_0000_0000_0000 SW Serial Management Control
30 // READ_MII, //c007_aa00_cc00_0200 PHY Read
31 // WRITE_MII, //4008_aa00_cc00_0200 PHY Write
32 // READ_MII_STATUS, //c009_0000_0000_0100 Serial Management Status
33 // HW_MII_OP, //400a_0000_0000_0000 HW Serial Management Control
34 // READ_SROM, //C00B_AA00_0000_0200 SROM Read
35 // WRITE_SROM, //400C_AA00_CCDD_0000 SROM Write
36 // WRITE_SROM_ENABLE, //400D_0000_0000_0000 SROM Write Enable
37 // WRITE_SROM_DISABLE, //400E_0000_0000_0000 SROM Write Disable
38 // READ_RX_CONTROL, //C00F_0000_0000_0200 Read Rx Control
39 // WRITE_RX_CONTROL, //4010_AABB_0000_0000 Write Rx Control
40 // READ_IPGS, //C011_0000_0000_0300 Read IPG/IPG1/IPG2 Register
41 // WRITE_IPGS, //4012_AABB_CC00_0000 Write IPG/IPG1/IPG2 Register
42 // READ_NODEID, //C013_0000_0000_0600 Read Node ID
43 // WRITE_NODEID, //4014_0000_0000_0600 Write Node ID
44 // READ_MF_ARRAY, //C015_0000_0000_0800 Read Multicast Filter Array
45 // WRITE_MF_ARRAY, //4016_0000_0000_0800 Write Multicast Filter Array
46 // READ_TEST, //4017_AA00_0000_0000 Write Test Register
47 // READ_PHYID, //C019_0000_0000_0200 Read Ethernet/HomePNA PHY Address
48 // READ_MEDIUM_STATUS, //C01A_0000_0000_0200 Read Medium Status
49 // WRITE_MEDIUM_MODE, //401B_AABB_0000_0000 Write Medium Mode Register
50 // GET_MONITOR_MODE, //C01C_0000_0000_0100 Read Monitor Mode Status
51 // SET_MONITOR_MODE, //401D_AA00_0000_0000 Write Monitor Mode Register
52 // READ_GPIOS, //C01E_0000_0000_0100 Read GPIOs Status
53 // WRITE_GPIOS, //401F_AA00_0000_0000 Write GPIOs
54 // WRITE_SOFT_RESET, //4020_AA00_0000_0000 Write Software Reset
55 // READ_MIIS_IF_STATE, //C021_AA00_0000_0100 Read MII/GMII/RGMII Iface Status
56 // WRITE_MIIS_IF_STATE, //4022_AA00_0000_0000 Write MII/GMII/RGMII Iface Control
58 // RX Control Register bits
59 // RXCTL_PROMISCUOUS, // forward all frames up to the host
60 // RXCTL_ALL_MULTICAT, // forward all multicast frames up to the host
61 // RXCTL_SEP, // forward frames with CRC error up to the host
62 // RXCTL_BROADCAST, // forward broadcast frames up to the host
63 // RXCTL_MULTICAST, // forward multicast frames that are
64 // matching to multicast filter up to the host
65 // RXCTL_AP, // forward unicast frames that are matching
66 // to multicast filter up to the host
67 // RXCTL_START, // ethernet MAC start operating
68 // RXCTL_USB_MFB, // Max Frame Burst TX on USB
71 // PHY IDs request answer data layout
72 struct AX88178_PhyIDs
{
79 enum AX88178_MediumState
{
80 MEDIUM_STATE_GM
= 0x0001,
81 MEDIUM_STATE_FD
= 0x0002,
82 MEDIUM_STATE_AC
= 0x0004, // must be always set
83 MEDIUM_STATE_ENCK
= 0x0008,
84 MEDIUM_STATE_RFC
= 0x0010,
85 MEDIUM_STATE_TFC
= 0x0020,
86 MEDIUM_STATE_JFE
= 0x0040,
87 MEDIUM_STATE_PF_ON
= 0x0080,
88 MEDIUM_STATE_PF_OFF
= 0x0000,
89 MEDIUM_STATE_RE
= 0x0100,
90 MEDIUM_STATE_PS_100
= 0x0200,
91 MEDIUM_STATE_PS_10
= 0x0000,
92 MEDIUM_STATE_SBP1
= 0x0800,
93 MEDIUM_STATE_SBP0
= 0x0000,
94 MEDIUM_STATE_SM_ON
= 0x1000
99 enum AX88178_MonitorMode
{
100 MONITOR_MODE_MOM
= 0x01,
101 MONITOR_MODE_RWLU
= 0x02,
102 MONITOR_MODE_RWMP
= 0x04,
103 MONITOR_MODE_US
= 0x10
107 // General Purpose I/O Register
119 // Software Reset Register bits
120 enum AX88178_SoftwareReset
{
123 SW_RESET_PRTE
= 0x04,
126 SW_RESET_BIT6
= 0x40 // always set to 1
130 // MII/GMII/RGMII Interface Conttrol
131 enum AX88178_MIISInterfaceStatus
{
132 MIIS_IF_STATE_DM
= 0x01,
133 MIIS_IF_STATE_RB
= 0x02
137 // Notification data layout
138 struct AX88178_Notify
{
141 uint8 btBB
; // AX88178_BBState below
149 enum AX88178_BBState
{
150 LINK_STATE_PPLS
= 0x01,
151 LINK_STATE_SPLS
= 0x02,
152 LINK_STATE_FLE
= 0x04,
153 LINK_STATE_MDINT
= 0x08
157 const uint16 maxFrameSize
= 1536;
160 AX88178Device::AX88178Device(usb_device device
, DeviceInfo
& deviceInfo
)
162 ASIXDevice(device
, deviceInfo
)
164 fStatus
= InitDevice();
169 AX88178Device::InitDevice()
171 fFrameSize
= maxFrameSize
;
172 fUseTRXHeader
= true;
174 fReadNodeIDRequest
= READ_NODEID
;
176 fNotifyBufferLength
= sizeof(AX88178_Notify
);
177 fNotifyBuffer
= (uint8
*)malloc(fNotifyBufferLength
);
178 if (fNotifyBuffer
== NULL
) {
179 TRACE_ALWAYS("Error of allocating memory for notify buffer.\n");
189 AX88178Device::SetupDevice(bool deviceReplugged
)
191 status_t result
= ASIXDevice::SetupDevice(deviceReplugged
);
192 if (result
!= B_OK
) {
196 result
= fMII
.Init(fDevice
);
198 if (result
!= B_OK
) {
202 size_t actualLength
= 0;
203 // get the "magic" word from EEPROM
204 result
= gUSBModule
->send_request(fDevice
,
205 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_OUT
, WRITE_SROM_ENABLE
,
206 0, 0, 0, 0, &actualLength
);
208 if (result
!= B_OK
) {
209 TRACE_ALWAYS("Error of enabling SROM access:%#010x\n", result
);
213 uint16 eepromData
= 0;
214 status_t op_result
= gUSBModule
->send_request(fDevice
,
215 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_IN
, READ_SROM
,
216 0x17, 0, sizeof(eepromData
), &eepromData
, &actualLength
);
218 if (op_result
!= B_OK
) {
219 TRACE_ALWAYS("Error of reading SROM data:%#010x\n", result
);
222 if (actualLength
!= sizeof(eepromData
)) {
223 TRACE_ALWAYS("Mismatch of reading SROM data."
224 "Read %d bytes instead of %d\n", actualLength
, sizeof(eepromData
));
227 result
= gUSBModule
->send_request(fDevice
,
228 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_OUT
, WRITE_SROM_DISABLE
,
229 0, 0, 0, 0, &actualLength
);
231 if (result
!= B_OK
) {
232 TRACE_ALWAYS("Error of disabling SROM access: %#010x\n", result
);
236 if (op_result
!= B_OK
) {
240 // some shaman's dances with GPIO
245 // eeprom bit 8 is off
246 { 40000 , GPIO_OO_1EN
| GPIO_IO_1
| GPIO_RSE
},
247 { 30000 , GPIO_OO_2EN
| GPIO_IO_2
| GPIO_OO_1EN
| GPIO_IO_1
},
248 { 300000 , GPIO_OO_2EN
| GPIO_OO_1EN
| GPIO_IO_1
},
249 { 30000 , GPIO_OO_2EN
| GPIO_IO_2
| GPIO_OO_1EN
| GPIO_IO_1
},
250 // eeprom bit 8 is on
251 { 40000 , GPIO_OO_1EN
| GPIO_IO_1
| GPIO_RSE
},
252 { 30000 , GPIO_OO_1EN
},
253 { 30000 , GPIO_OO_1EN
| GPIO_IO_1
},
256 bool bCase8
= (eepromData
>> 8) != 1;
257 size_t from
= bCase8
? 0 : 4;
258 size_t to
= bCase8
? 3 : 6;
260 for (size_t i
= from
; i
<= to
; i
++) {
261 result
= gUSBModule
->send_request(fDevice
,
262 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_OUT
, WRITE_GPIOS
,
263 GPIOCommands
[i
].value
, 0, 0, 0, &actualLength
);
265 snooze(GPIOCommands
[i
].delay
);
267 if (result
!= B_OK
) {
268 TRACE_ALWAYS("Error of GPIO setup command %d:[%#04x]: %#010x\n",
269 i
, GPIOCommands
[i
].value
, result
);
275 // finally a bit of exercises for SW reset register...
276 result
= gUSBModule
->send_request(fDevice
,
277 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_OUT
, WRITE_SOFT_RESET
,
278 uSWReset
, 0, 0, 0, &actualLength
);
280 if (result
!= B_OK
) {
281 TRACE_ALWAYS("Error of SW reset to %#02x: %#010x\n", uSWReset
, result
);
287 uSWReset
= SW_RESET_PRL
| SW_RESET_BIT6
;
288 result
= gUSBModule
->send_request(fDevice
,
289 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_OUT
, WRITE_SOFT_RESET
,
290 uSWReset
, 0, 0, 0, &actualLength
);
292 if (result
!= B_OK
) {
293 TRACE_ALWAYS("Error of SW reset to %#02x: %#010x\n", uSWReset
, result
);
299 result
= WriteRXControlRegister(0);
300 if (result
!= B_OK
) {
301 TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n", 0, result
);
305 result
= fMII
.SetupPHY();
313 AX88178Device::StartDevice()
315 size_t actualLength
= 0;
316 status_t result
= gUSBModule
->send_request(fDevice
,
317 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_OUT
, WRITE_IPGS
,
318 0, 0, sizeof(fIPG
), fIPG
, &actualLength
);
320 if (result
!= B_OK
) {
321 TRACE_ALWAYS("Error of writing IPGs:%#010x\n", result
);
325 if (actualLength
!= sizeof(fIPG
)) {
326 TRACE_ALWAYS("Mismatch of written IPGs data. "
327 "%d bytes of %d written.\n", actualLength
, sizeof(fIPG
));
330 uint16 rxcontrol
= RXCTL_START
| RXCTL_BROADCAST
;
331 result
= WriteRXControlRegister(rxcontrol
);
332 if (result
!= B_OK
) {
333 TRACE_ALWAYS("Error of writing %#04x RX Control:%#010x\n",
343 AX88178Device::OnNotify(uint32 actualLength
)
345 if (actualLength
< sizeof(AX88178_Notify
)) {
346 TRACE_ALWAYS("Data underrun error. %d of %d bytes received\n",
347 actualLength
, sizeof(AX88178_Notify
));
351 AX88178_Notify
*notification
= (AX88178_Notify
*)fNotifyBuffer
;
353 if (notification
->btA1
!= 0xa1) {
354 TRACE_ALWAYS("Notify magic byte is invalid: %#02x\n",
359 bool linkIsUp
= fHasConnection
;
360 switch(fMII
.ActivePHY()) {
363 linkIsUp
= (notification
->btBB
& LINK_STATE_PPLS
)
368 linkIsUp
= (notification
->btBB
& LINK_STATE_SPLS
)
373 TRACE_ALWAYS("Error: PHY is not initialized.\n");
377 bool linkStateChange
= linkIsUp
!= fHasConnection
;
378 fHasConnection
= linkIsUp
;
380 if (linkStateChange
) {
381 TRACE("Link state of PHY%d has been changed to '%s'\n",
382 phyIndex
, fHasConnection
? "up" : "down");
385 if (linkStateChange
&& fLinkStateChangeSem
>= B_OK
)
386 release_sem_etc(fLinkStateChangeSem
, 1, B_DO_NOT_RESCHEDULE
);
393 AX88178Device::GetLinkState(ether_link_state
*linkState
)
395 size_t actualLength
= 0;
396 uint16 mediumStatus
= 0;
397 status_t result
= gUSBModule
->send_request(fDevice
,
398 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_IN
, READ_MEDIUM_STATUS
,
399 0, 0, sizeof(mediumStatus
), &mediumStatus
, &actualLength
);
401 if (result
!= B_OK
) {
402 TRACE_ALWAYS("Error of reading medium status:%#010x.\n", result
);
406 if (actualLength
!= sizeof(mediumStatus
)) {
407 TRACE_ALWAYS("Mismatch of reading medium status."
408 "Read %d bytes instead of %d\n",
409 actualLength
, sizeof(mediumStatus
));
412 TRACE_FLOW("Medium status is %#04x\n", mediumStatus
);
414 linkState
->quality
= 1000;
416 linkState
->media
= IFM_ETHER
| (fHasConnection
? IFM_ACTIVE
: 0);
417 linkState
->media
|= (mediumStatus
& MEDIUM_STATE_FD
)
418 ? IFM_FULL_DUPLEX
: IFM_HALF_DUPLEX
;
420 linkState
->speed
= (mediumStatus
& MEDIUM_STATE_PS_100
)
421 ? 100000000 : 10000000;
422 linkState
->speed
= (mediumStatus
& MEDIUM_STATE_GM
)
423 ? 1000000000 : linkState
->speed
;
425 TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n",
426 (linkState
->media
& IFM_ACTIVE
) ? "active" : "inactive",
427 linkState
->speed
/ 1000000,
428 (linkState
->media
& IFM_FULL_DUPLEX
) ? "full" : "half");