BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / network / usb_asix / MIIBus.cpp
blob2832a5e05eb20d2fb8eb41e5b05dbe18c9847074
1 /*
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 "MIIBus.h"
16 #include "ASIXVendorRequests.h"
17 #include "Driver.h"
18 #include "Settings.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)
26 MIIBus::MIIBus()
28 fStatus(B_NO_INIT),
29 fDevice(0),
30 fSelectedPHY(CurrentPHY)
32 for (size_t i = 0; i < PHYsCount; i++) {
33 fPHYs[i] = PHYNotInstalled;
38 status_t
39 MIIBus::Init(usb_device device)
41 // reset to default state
42 fDevice = 0;
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);
53 if (result != B_OK) {
54 TRACE_ALWAYS("Request of the PHYIDs failed:%#010x\n", result);
55 return 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;
68 } else
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;
80 fDevice = device;
81 fStatus = result;
83 return fStatus;
87 status_t
88 MIIBus::SetupPHY()
90 uint16 control = 0;
91 status_t result = Read(MII_BMCR, &control);
92 if (result != B_OK) {
93 TRACE_ALWAYS("Error of reading control word:%#010x.\n", result);
94 return 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",
103 control, result);
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));
125 // Dump();
127 return result;
131 status_t
132 MIIBus::InitCheck()
134 if (fSelectedPHY == CurrentPHY) {
135 return B_ENTRY_NOT_FOUND;
138 return fStatus;
142 uint8
143 MIIBus::PHYID(PHYIndex phyIndex /*= CurrentPHY*/)
145 if (phyIndex == CurrentPHY) {
146 return (fSelectedPHY == CurrentPHY
147 ? 0 : fPHYs[fSelectedPHY]) & PHYIDMask;
150 return fPHYs[phyIndex] & PHYIDMask;
154 uint8
155 MIIBus::PHYType(PHYIndex phyIndex /*= CurrentPHY*/)
157 if (phyIndex == CurrentPHY) {
158 return (fSelectedPHY == CurrentPHY
159 ? PHYNotInstalled : fPHYs[fSelectedPHY]) & PHYTypeMask;
162 return fPHYs[phyIndex] & PHYTypeMask;
166 status_t
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);
172 return 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);
189 return 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);
216 return op_result;
220 status_t
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);
228 return 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);
244 return 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);
271 return op_result;
275 status_t
276 MIIBus::Status(uint16 *status, PHYIndex phyIndex /*= CurrentPHY*/)
278 return Read(MII_BMSR, status, phyIndex);
282 status_t
283 MIIBus::Dump()
285 status_t result = InitCheck();
286 if (B_OK != result) {
287 TRACE_ALWAYS("Error: MII is not ready:%#010x.\n", result);
288 return 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);
306 return result;
309 uint8 regs[] = { MII_BMCR, MII_BMSR, MII_PHYID0,
310 MII_PHYID1, MII_ANAR, MII_ANLPAR/*, MII_ANER*/};
311 uint16 value = 0;
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);
341 return result;