BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / network / wb840 / interface.c
blob324185f9536d39e4ac37710a9de7ce5418dfecd5
1 /*
2 * Copyright (c) 2003-2004 Stefano Ceccherini (burton666@libero.it)
3 * Copyright (c) 1997, 1998
4 * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Bill Paul.
17 * 4. Neither the name of the author nor the names of any co-contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31 * THE POSSIBILITY OF SUCH DAMAGE.
35 #include "wb840.h"
36 #include "device.h"
37 #include "interface.h"
39 #include <ByteOrder.h>
40 #include <KernelExport.h>
42 #include <string.h>
45 #define SIO_SET(x) \
46 write32(device->reg_base + WB_SIO, \
47 read32(device->reg_base + WB_SIO) | x)
49 #define SIO_CLR(x) \
50 write32(device->reg_base + WB_SIO, \
51 read32(device->reg_base + WB_SIO) & ~x)
53 #define MII_DELAY(x) read32(x->reg_base + WB_SIO)
56 static void
57 mii_sync(struct wb_device *device)
59 // Set data bit and strobe the clock 32 times
60 int bits = 32;
62 SIO_SET(WB_SIO_MII_DIR|WB_SIO_MII_DATAIN);
64 while (--bits >= 0) {
65 SIO_SET(WB_SIO_MII_CLK);
66 MII_DELAY(device);
67 SIO_CLR(WB_SIO_MII_CLK);
68 MII_DELAY(device);
73 static void
74 mii_send(wb_device *device, uint32 bits, int count)
76 int i;
78 SIO_CLR(WB_SIO_MII_CLK);
80 for (i = (0x1 << (count - 1)); i; i >>= 1) {
81 if (bits & i)
82 SIO_SET(WB_SIO_MII_DATAIN);
83 else
84 SIO_CLR(WB_SIO_MII_DATAIN);
85 MII_DELAY(device);
86 SIO_CLR(WB_SIO_MII_CLK);
87 MII_DELAY(device);
88 SIO_SET(WB_SIO_MII_CLK);
93 * Read an PHY register through the MII.
95 static int
96 wb_mii_readreg(wb_device *device, wb_mii_frame *frame)
98 int i, ack;
101 * Set up frame for RX.
103 frame->mii_stdelim = WB_MII_STARTDELIM;
104 frame->mii_opcode = WB_MII_READOP;
105 frame->mii_turnaround = 0;
106 frame->mii_data = 0;
108 write32(device->reg_base + WB_SIO, 0);
111 * Turn on data xmit.
113 SIO_SET(WB_SIO_MII_DIR);
115 mii_sync(device);
118 * Send command/address info.
120 mii_send(device, frame->mii_stdelim, 2);
121 mii_send(device, frame->mii_opcode, 2);
122 mii_send(device, frame->mii_phyaddr, 5);
123 mii_send(device, frame->mii_regaddr, 5);
125 /* Idle bit */
126 SIO_CLR((WB_SIO_MII_CLK|WB_SIO_MII_DATAIN));
127 MII_DELAY(device);
128 SIO_SET(WB_SIO_MII_CLK);
129 MII_DELAY(device);
131 /* Turn off xmit. */
132 SIO_CLR(WB_SIO_MII_DIR);
133 /* Check for ack */
134 SIO_CLR(WB_SIO_MII_CLK);
135 MII_DELAY(device);
136 ack = read32(device->reg_base + WB_SIO) & WB_SIO_MII_DATAOUT;
137 SIO_SET(WB_SIO_MII_CLK);
138 MII_DELAY(device);
139 SIO_CLR(WB_SIO_MII_CLK);
140 MII_DELAY(device);
141 SIO_SET(WB_SIO_MII_CLK);
142 MII_DELAY(device);
145 * Now try reading data bits. If the ack failed, we still
146 * need to clock through 16 cycles to keep the PHY(s) in sync.
148 if (ack) {
149 for(i = 0; i < 16; i++) {
150 SIO_CLR(WB_SIO_MII_CLK);
151 MII_DELAY(device);
152 SIO_SET(WB_SIO_MII_CLK);
153 MII_DELAY(device);
155 goto fail;
158 for (i = 0x8000; i; i >>= 1) {
159 SIO_CLR(WB_SIO_MII_CLK);
160 MII_DELAY(device);
161 if (!ack) {
162 if (read32(device->reg_base + WB_SIO) & WB_SIO_MII_DATAOUT)
163 frame->mii_data |= i;
164 MII_DELAY(device);
166 SIO_SET(WB_SIO_MII_CLK);
167 MII_DELAY(device);
170 fail:
172 SIO_CLR(WB_SIO_MII_CLK);
173 MII_DELAY(device);
174 SIO_SET(WB_SIO_MII_CLK);
175 MII_DELAY(device);
177 if (ack)
178 return 1;
179 return 0;
183 * Write to a PHY register through the MII.
185 static int
186 wb_mii_writereg(wb_device *device, wb_mii_frame *frame)
189 * Set up frame for TX.
192 frame->mii_stdelim = WB_MII_STARTDELIM;
193 frame->mii_opcode = WB_MII_WRITEOP;
194 frame->mii_turnaround = WB_MII_TURNAROUND;
197 * Turn on data output.
199 SIO_SET(WB_SIO_MII_DIR);
201 mii_sync(device);
203 mii_send(device, frame->mii_stdelim, 2);
204 mii_send(device, frame->mii_opcode, 2);
205 mii_send(device, frame->mii_phyaddr, 5);
206 mii_send(device, frame->mii_regaddr, 5);
207 mii_send(device, frame->mii_turnaround, 2);
208 mii_send(device, frame->mii_data, 16);
210 /* Idle bit. */
211 SIO_SET(WB_SIO_MII_CLK);
212 MII_DELAY(device);
213 SIO_CLR(WB_SIO_MII_CLK);
214 MII_DELAY(device);
217 * Turn off xmit.
219 SIO_CLR(WB_SIO_MII_DIR);
221 return 0;
226 wb_miibus_readreg(wb_device *device, int phy, int reg)
228 struct wb_mii_frame frame;
230 memset(&frame, 0, sizeof(frame));
232 frame.mii_phyaddr = phy;
233 frame.mii_regaddr = reg;
234 wb_mii_readreg(device, &frame);
236 return frame.mii_data;
240 void
241 wb_miibus_writereg(wb_device *device, int phy, int reg, int data)
243 struct wb_mii_frame frame;
245 memset(&frame, 0, sizeof(frame));
247 frame.mii_phyaddr = phy;
248 frame.mii_regaddr = reg;
249 frame.mii_data = data;
251 wb_mii_writereg(device, &frame);
253 return;
257 #define EEPROM_DELAY(x) read32(x->reg_base + WB_SIO)
259 #if 0
260 static void
261 wb_eeprom_putbyte(wb_device *device, int addr)
263 int d, i;
264 int delay;
266 d = addr | WB_EECMD_READ;
269 * Feed in each bit and strobe the clock.
271 for (i = 0x400; i; i >>= 1) {
272 if (d & i) {
273 SIO_SET(WB_SIO_EE_DATAIN);
274 } else {
275 SIO_CLR(WB_SIO_EE_DATAIN);
277 for (delay = 0; delay < 100; delay++)
278 MII_DELAY(device);
280 SIO_SET(WB_SIO_EE_CLK);
282 for (delay = 0; delay < 150; delay++)
283 MII_DELAY(device);
285 SIO_CLR(WB_SIO_EE_CLK);
287 for (delay = 0; delay < 100; delay++)
288 MII_DELAY(device);
292 return;
294 #endif
297 static void
298 wb_eeprom_askdata(wb_device *device, int addr)
300 int command, i;
301 int delay;
303 command = addr | WB_EECMD_READ;
305 /* Feed in each bit and strobe the clock. */
306 for(i = 0x400; i; i >>= 1) {
307 if (command & i)
308 SIO_SET(WB_SIO_EE_DATAIN);
309 else
310 SIO_CLR(WB_SIO_EE_DATAIN);
312 SIO_SET(WB_SIO_EE_CLK);
314 SIO_CLR(WB_SIO_EE_CLK);
315 for (delay = 0; delay < 100; delay++)
316 EEPROM_DELAY(device);
321 /* Read a word of data stored in the EEPROM at address "addr". */
322 static void
323 wb_eeprom_getword(wb_device *device, int addr, uint16 *dest)
325 int i;
326 uint16 word = 0;
328 /* Enter EEPROM access mode */
329 write32(device->reg_base + WB_SIO, WB_SIO_EESEL|WB_SIO_EE_CS);
331 /* Send address of word we want to read. */
332 wb_eeprom_askdata(device, addr);
334 write32(device->reg_base + WB_SIO, WB_SIO_EESEL|WB_SIO_EE_CS);
336 /* Start reading bits from EEPROM */
337 for (i = 0x8000; i > 0; i >>= 1) {
338 SIO_SET(WB_SIO_EE_CLK);
339 if (read32(device->reg_base + WB_SIO) & WB_SIO_EE_DATAOUT)
340 word |= i;
341 SIO_CLR(WB_SIO_EE_CLK);
344 /* Turn off EEPROM access mode */
345 write32(device->reg_base + WB_SIO, 0);
347 *dest = word;
351 void
352 wb_read_eeprom(wb_device *device, void* dest,
353 int offset, int count, bool swap)
355 int i;
356 uint16 word = 0, *ptr;
358 for (i = 0; i < count; i++) {
359 wb_eeprom_getword(device, offset + i, &word);
360 ptr = (uint16 *)((uint8 *)dest + (i * 2));
361 if (swap)
362 *ptr = ntohs(word);
363 else
364 *ptr = word;