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.
16 #include "ASIXVendorRequests.h"
21 #define MII_OUI(id1, id2) (((id1) << 6) | ((id2) >> 10))
22 #define MII_MODEL(id2) (((id2) & 0x03f0) >> 4)
23 #define MII_REV(id2) ((id2) & 0x000f)
30 fSelectedPHY(CurrentPHY
)
32 for (size_t i
= 0; i
< PHYsCount
; i
++) {
33 fPHYs
[i
] = PHYNotInstalled
;
39 MIIBus::Init(usb_device device
)
41 // reset to default state
43 fSelectedPHY
= CurrentPHY
;
44 for (size_t i
= 0; i
< PHYsCount
; i
++) {
45 fPHYs
[i
] = PHYNotInstalled
;
48 size_t actual_length
= 0;
49 status_t result
= gUSBModule
->send_request(device
,
50 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_IN
, READ_PHYID
, 0, 0,
51 sizeof(fPHYs
), fPHYs
, &actual_length
);
54 TRACE_ALWAYS("Request of the PHYIDs failed:%#010x\n", result
);
58 if (sizeof(fPHYs
) != actual_length
) {
59 TRACE_ALWAYS("Mismatch of reading %d PHYIDs bytes instead of %d.\n",
60 actual_length
, sizeof(fPHYs
));
63 TRACE("PHYIDs are:%#02x:%#02x\n", fPHYs
[0], fPHYs
[1]);
65 // simply tactic - we use first available PHY
66 if (PHYType(PrimaryPHY
) != PHYNotInstalled
) {
67 fSelectedPHY
= PrimaryPHY
;
69 if (PHYType(SecondaryPHY
) != PHYNotInstalled
) {
70 fSelectedPHY
= SecondaryPHY
;
73 TRACE("PHYs are configured: Selected:%#02x; Primary:%#02x; 2ndary:%#02x\n",
74 PHYID(CurrentPHY
), PHYID(PrimaryPHY
), PHYID(SecondaryPHY
));
75 if (fSelectedPHY
== CurrentPHY
) {
76 TRACE_ALWAYS("No PHYs found!\n");
77 return B_ENTRY_NOT_FOUND
;
91 status_t result
= Read(MII_BMCR
, &control
);
93 TRACE_ALWAYS("Error of reading control word:%#010x.\n", result
);
97 TRACE("MII Control word is %#04x\n", control
);
99 control
&= ~BMCR_Isolate
;
100 result
= Write(MII_BMCR
, control
);
101 if (result
!= B_OK
) {
102 TRACE_ALWAYS("Error of writing control word %#04x:%#010x.\n",
106 result
= Write(MII_BMCR
, BMCR_Reset
);
107 if (result
!= B_OK
) {
108 TRACE_ALWAYS("Error of resetting PHY:%#010x.\n", result
);
111 uint16 id01
= 0, id02
= 0;
112 result
= Read(MII_PHYID0
, &id01
);
113 if (result
!= B_OK
) {
114 TRACE_ALWAYS("Error of reading PHY ID1:%#010x.\n", result
);
117 result
= Read(MII_PHYID1
, &id02
);
118 if (result
!= B_OK
) {
119 TRACE_ALWAYS("Error of reading PHY ID2:%#010x.\n", result
);
122 TRACE("MII Info: OUI:%04x; Model:%04x; rev:%02x.\n",
123 MII_OUI(id01
, id02
), MII_MODEL(id02
), MII_REV(id02
));
134 if (fSelectedPHY
== CurrentPHY
) {
135 return B_ENTRY_NOT_FOUND
;
143 MIIBus::PHYID(PHYIndex phyIndex
/*= CurrentPHY*/)
145 if (phyIndex
== CurrentPHY
) {
146 return (fSelectedPHY
== CurrentPHY
147 ? 0 : fPHYs
[fSelectedPHY
]) & PHYIDMask
;
150 return fPHYs
[phyIndex
] & PHYIDMask
;
155 MIIBus::PHYType(PHYIndex phyIndex
/*= CurrentPHY*/)
157 if (phyIndex
== CurrentPHY
) {
158 return (fSelectedPHY
== CurrentPHY
159 ? PHYNotInstalled
: fPHYs
[fSelectedPHY
]) & PHYTypeMask
;
162 return fPHYs
[phyIndex
] & PHYTypeMask
;
167 MIIBus::Read(uint16 miiRegister
, uint16
*value
, PHYIndex phyIndex
/*= CurrPHY*/)
169 status_t result
= InitCheck();
170 if (B_OK
!= result
) {
171 TRACE_ALWAYS("Error: MII is not ready:%#010x\n", result
);
175 if (PHYType(phyIndex
) == PHYNotInstalled
) {
176 TRACE_ALWAYS("Error: Invalid PHY index:%#02x.\n", phyIndex
);
177 return B_ENTRY_NOT_FOUND
;
180 uint16 phyId
= PHYID(phyIndex
);
182 size_t actual_length
= 0;
183 // switch to SW operation mode
184 result
= gUSBModule
->send_request(fDevice
, USB_REQTYPE_VENDOR
185 | USB_REQTYPE_DEVICE_OUT
, SW_MII_OP
, 0, 0, 0, 0, &actual_length
);
187 if (result
!= B_OK
) {
188 TRACE_ALWAYS("Error of switching MII to SW op.mode: %#010x\n", result
);
192 // read register value
193 status_t op_result
= gUSBModule
->send_request(fDevice
, USB_REQTYPE_VENDOR
194 | USB_REQTYPE_DEVICE_IN
, READ_MII
, phyId
, miiRegister
, sizeof(*value
),
195 value
, &actual_length
);
197 if (op_result
!= B_OK
) {
198 TRACE_ALWAYS("Error of reading MII reg.%d at PHY%d:%#010x.\n",
199 miiRegister
, phyId
, op_result
);
202 if (sizeof(*value
) != actual_length
) {
203 TRACE_ALWAYS("Mismatch of reading MII reg.%d at PHY %d. "
204 "Read %d bytes instead of %d.\n", miiRegister
, phyId
,
205 actual_length
, sizeof(*value
));
208 // switch to HW operation mode
209 result
= gUSBModule
->send_request(fDevice
, USB_REQTYPE_VENDOR
210 | USB_REQTYPE_DEVICE_OUT
, HW_MII_OP
, 0, 0, 0, 0, &actual_length
);
212 if (result
!= B_OK
) {
213 TRACE_ALWAYS("Error of switching MII to HW op.mode: %#010x\n", result
);
221 MIIBus::Write(uint16 miiRegister
, uint16 value
, PHYIndex phyIndex
/*= CurrPHY*/)
223 size_t actual_length
= 0;
225 status_t result
= InitCheck();
226 if (B_OK
!= result
) {
227 TRACE_ALWAYS("Error: MII is not ready:%#010x\n", result
);
231 if (PHYType(phyIndex
) == PHYNotInstalled
) {
232 TRACE_ALWAYS("Error: Invalid PHY index:%#02x\n", phyIndex
);
233 return B_ENTRY_NOT_FOUND
;
236 uint16 phyId
= PHYID(phyIndex
);
238 // switch to SW operation mode
239 result
= gUSBModule
->send_request(fDevice
, USB_REQTYPE_VENDOR
240 | USB_REQTYPE_DEVICE_OUT
, SW_MII_OP
, 0, 0, 0, 0, &actual_length
);
242 if (result
!= B_OK
) {
243 TRACE_ALWAYS("Error of switching MII to SW op.mode: %#010x\n", result
);
247 // write register value
248 status_t op_result
= gUSBModule
->send_request(fDevice
, USB_REQTYPE_VENDOR
249 | USB_REQTYPE_DEVICE_OUT
, WRITE_MII
, phyId
, miiRegister
, sizeof(value
),
250 &value
, &actual_length
);
252 if (op_result
!= B_OK
) {
253 TRACE_ALWAYS("Error of writing MII reg.%d at PHY %d:%#010x.\n",
254 miiRegister
, phyId
, op_result
);
257 if (sizeof(value
) != actual_length
) {
258 TRACE_ALWAYS("Mismatch of writing MII reg.%d at PHY %d."
259 "Write %d bytes instead of %d.\n", miiRegister
, phyId
,
260 actual_length
, sizeof(value
));
263 // switch to HW operation mode
264 result
= gUSBModule
->send_request(fDevice
, USB_REQTYPE_VENDOR
265 | USB_REQTYPE_DEVICE_OUT
, HW_MII_OP
, 0, 0, 0, 0, &actual_length
);
267 if (result
!= B_OK
) {
268 TRACE_ALWAYS("Error of switching MII to HW op.mode: %#010x\n", result
);
276 MIIBus::Status(uint16
*status
, PHYIndex phyIndex
/*= CurrentPHY*/)
278 return Read(MII_BMSR
, status
, phyIndex
);
285 status_t result
= InitCheck();
286 if (B_OK
!= result
) {
287 TRACE_ALWAYS("Error: MII is not ready:%#010x.\n", result
);
291 if (PHYType(CurrentPHY
) == PHYNotInstalled
) {
292 TRACE_ALWAYS("Error: Current PHY index is invalid!\n");
293 return B_ENTRY_NOT_FOUND
;
296 uint16 phyId
= PHYID(CurrentPHY
);
298 size_t actual_length
= 0;
299 // switch to SW operation mode
300 result
= gUSBModule
->send_request(fDevice
,
301 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_OUT
,
302 SW_MII_OP
, 0, 0, 0, 0, &actual_length
);
304 if (result
!= B_OK
) {
305 TRACE_ALWAYS("Error of switching MII to SW op.mode: %#010x\n", result
);
309 uint8 regs
[] = { MII_BMCR
, MII_BMSR
, MII_PHYID0
,
310 MII_PHYID1
, MII_ANAR
, MII_ANLPAR
/*, MII_ANER*/};
312 for (size_t i
= 0; i
< sizeof(regs
)/ sizeof(regs
[0]); i
++) {
314 // read register value
315 status_t op_result
= gUSBModule
->send_request(fDevice
,
316 USB_REQTYPE_VENDOR
| USB_REQTYPE_DEVICE_IN
, READ_MII
, phyId
,
317 regs
[i
], sizeof(value
), &value
, &actual_length
);
319 if (op_result
!= B_OK
) {
320 TRACE_ALWAYS("Error of reading MII reg.%d at PHY%d:%#010x.\n",
321 regs
[i
], phyId
, op_result
);
324 if (sizeof(value
) != actual_length
) {
325 TRACE_ALWAYS("Mismatch of reading MII reg.%d at PHY%d."
326 " Read %d bytes instead of %d.\n", regs
[i
], phyId
,
327 actual_length
, sizeof(value
));
330 TRACE_ALWAYS("MII reg: %d has %#04x\n", regs
[i
], value
);
333 // switch to HW operation mode
334 result
= gUSBModule
->send_request(fDevice
, USB_REQTYPE_VENDOR
335 | USB_REQTYPE_DEVICE_OUT
, HW_MII_OP
, 0, 0, 0, 0, &actual_length
);
337 if (result
!= B_OK
) {
338 TRACE_ALWAYS("Error of switching MII to HW op.mode: %#010x\n", result
);