1 /* Copyright (c) 2003-2011
2 * Stefano Ceccherini <stefano.ceccherini@gmail.com>. All rights reserved.
3 * This file is released under the MIT license
5 #include <KernelExport.h>
11 #include <net/if_media.h>
16 #include "interface.h"
22 extern char* gDevNameList
[];
23 extern pci_info
* gDevList
[];
25 static int32 sOpenMask
= 0;
28 wb840_open(const char* name
, uint32 flags
, void** cookie
)
30 char* deviceName
= NULL
;
33 struct wb_device
* data
;
36 LOG((DEVICE_NAME
": open()\n"));
38 for (i
= 0; (deviceName
= gDevNameList
[i
]) != NULL
; i
++) {
39 if (!strcmp(name
, deviceName
))
43 if (deviceName
== NULL
) {
44 LOG(("invalid device name"));
48 // There can be only one access at time
50 if (atomic_or(&sOpenMask
, mask
) & mask
)
53 // Allocate a wb_device structure
54 if (!(data
= (wb_device
*)calloc(1, sizeof(wb_device
)))) {
55 sOpenMask
&= ~(1L << i
);
62 load_driver_symbols("wb840");
66 data
->pciInfo
= gDevList
[i
];
67 data
->deviceName
= gDevNameList
[i
];
69 data
->reg_base
= data
->pciInfo
->u
.h0
.base_registers
[0];
70 data
->wb_cachesize
= gPci
->read_pci_config(data
->pciInfo
->bus
,
71 data
->pciInfo
->device
, data
->pciInfo
->function
, PCI_line_size
,
72 sizeof(PCI_line_size
)) & 0xff;
74 wb_read_eeprom(data
, &data
->MAC_Address
, 0, 3, false);
76 status
= wb_create_semaphores(data
);
78 LOG((DEVICE_NAME
": couldn't create semaphores\n"));
82 status
= wb_stop(data
);
84 LOG((DEVICE_NAME
": can't stop device\n"));
88 status
= wb_initPHYs(data
);
90 LOG((DEVICE_NAME
": can't init PHYs\n"));
96 /* Setup interrupts */
97 data
->irq
= data
->pciInfo
->u
.h0
.interrupt_line
;
98 status
= install_io_interrupt_handler(data
->irq
, wb_interrupt
, data
, 0);
101 ": can't install interrupt handler: %s\n", strerror(status
)));
105 LOG((DEVICE_NAME
": interrupts installed at irq line %x\n", data
->irq
));
107 status
= wb_create_rings(data
);
109 LOG((DEVICE_NAME
": can't create ring buffers\n"));
113 wb_enable_interrupts(data
);
115 WB_SETBIT(data
->reg_base
+ WB_NETCFG
, WB_NETCFG_RX_ON
);
116 write32(data
->reg_base
+ WB_RXSTART
, 0xFFFFFFFF);
117 WB_SETBIT(data
->reg_base
+ WB_NETCFG
, WB_NETCFG_TX_ON
);
119 add_timer(&data
->timer
, wb_tick
, 1000000LL, B_PERIODIC_TIMER
);
121 return B_OK
; // Everything after this line is an error
124 remove_io_interrupt_handler(data
->irq
, wb_interrupt
, data
);
127 wb_delete_semaphores(data
);
130 sOpenMask
&= ~(1L << i
);
133 LOG(("wb840: Open Failed\n"));
140 wb840_read(void* cookie
, off_t position
, void* buf
, size_t* num_bytes
)
142 wb_device
* device
= (wb_device
*)cookie
;
149 LOG((DEVICE_NAME
": read()\n"));
151 blockFlag
= device
->blockFlag
;
153 if (atomic_or(&device
->rxLock
, 1)) {
158 status
= acquire_sem_etc(device
->rxSem
, 1, B_CAN_INTERRUPT
| blockFlag
, 0);
160 atomic_and(&device
->rxLock
, 0);
165 current
= device
->rxCurrent
;
166 check
= device
->rxDescriptor
[current
].wb_status
;
167 if (check
& WB_RXSTAT_OWN
) {
168 LOG((DEVICE_NAME
":ERROR: read: buffer %d still in use: %x\n",
169 (int)current
, (int)status
));
170 atomic_and(&device
->rxLock
, 0);
175 if (check
& (WB_RXSTAT_RXERR
| WB_RXSTAT_CRCERR
| WB_RXSTAT_RUNT
)) {
176 LOG(("Error read: packet with errors."));
179 size
= WB_RXBYTES(check
);
181 LOG((DEVICE_NAME
": received %ld bytes\n", size
));
182 if (size
> WB_MAX_FRAMELEN
|| size
> *num_bytes
) {
183 LOG(("ERROR: Bad frame size: %ld", size
));
187 memcpy(buf
, (void*)device
->rxBuffer
[current
], size
);
190 device
->rxCurrent
= (current
+ 1) & WB_RX_CNT_MASK
;
193 former
= disable_interrupts();
194 acquire_spinlock(&device
->rxSpinlock
);
196 // release buffer to ring
197 wb_put_rx_descriptor(&device
->rxDescriptor
[current
]);
200 release_spinlock(&device
->rxSpinlock
);
201 restore_interrupts(former
);
204 atomic_and(&device
->rxLock
, 0);
211 wb840_write(void* cookie
, off_t position
, const void* buffer
, size_t* num_bytes
)
213 wb_device
* device
= (wb_device
*)cookie
;
214 status_t status
= B_OK
;
219 LOG((DEVICE_NAME
": write()\n"));
221 atomic_add(&device
->txLock
, 1);
223 if (*num_bytes
> WB_MAX_FRAMELEN
)
224 *num_bytes
= WB_MAX_FRAMELEN
;
226 frameSize
= *num_bytes
;
227 current
= device
->txCurrent
;
229 // block until a free tx descriptor is available
230 status
= acquire_sem_etc(device
->txSem
, 1, B_TIMEOUT
, ETHER_TRANSMIT_TIMEOUT
);
232 write32(device
->reg_base
+ WB_TXSTART
, 0xFFFFFFFF);
233 LOG((DEVICE_NAME
": write: acquiring sem failed: %ld, %s\n",
234 status
, strerror(status
)));
235 atomic_add(&device
->txLock
, -1);
240 check
= device
->txDescriptor
[current
].wb_status
;
241 if (check
& WB_TXSTAT_OWN
) {
242 // descriptor is still in use
243 dprintf(DEVICE_NAME
": card owns buffer %d\n", (int)current
);
244 atomic_add(&device
->txLock
, -1);
249 /* Copy data to tx buffer */
250 memcpy((void*)device
->txBuffer
[current
], buffer
, frameSize
);
251 device
->txCurrent
= (current
+ 1) & WB_TX_CNT_MASK
;
252 LOG((DEVICE_NAME
": %d bytes written\n", frameSize
));
255 cpu_status former
= disable_interrupts();
256 acquire_spinlock(&device
->txSpinlock
);
258 device
->txDescriptor
[current
].wb_ctl
= WB_TXCTL_TLINK
| frameSize
;
259 device
->txDescriptor
[current
].wb_ctl
|= WB_TXCTL_FIRSTFRAG
261 device
->txDescriptor
[current
].wb_status
= WB_TXSTAT_OWN
;
264 release_spinlock(&device
->txSpinlock
);
265 restore_interrupts(former
);
268 // re-enable transmit state machine
269 write32(device
->reg_base
+ WB_TXSTART
, 0xFFFFFFFF);
271 atomic_add(&device
->txLock
, -1);
278 wb840_control (void* cookie
, uint32 op
, void* arg
, size_t len
)
280 wb_device
* data
= (wb_device
*)cookie
;
282 LOG((DEVICE_NAME
": control()\n"));
285 LOG(("%s: ETHER_INIT\n", data
->deviceName
));
289 LOG(("%s: ETHER_GETADDR\n", data
->deviceName
));
290 memcpy(arg
, &data
->MAC_Address
, sizeof(data
->MAC_Address
));
295 LOG(("ETHER_NON_BLOCK\n"));
296 data
->blockFlag
= *(int32
*)arg
? B_TIMEOUT
: 0;
299 case ETHER_GETFRAMESIZE
:
300 LOG(("ETHER_GETFRAMESIZE\n"));
301 *(uint32
*)arg
= WB_MAX_FRAMELEN
;
304 case ETHER_GET_LINK_STATE
:
306 ether_link_state_t state
;
307 LOG(("ETHER_GET_LINK_STATE"));
309 state
.media
= (data
->link
? IFM_ACTIVE
: 0) | IFM_ETHER
310 | (data
->full_duplex
? IFM_FULL_DUPLEX
: IFM_HALF_DUPLEX
)
311 | (data
->speed
== LINK_SPEED_100_MBIT
? IFM_100_TX
: IFM_10_T
);
312 state
.speed
= data
->speed
== LINK_SPEED_100_MBIT
313 ? 100000000 : 10000000;
314 state
.quality
= 1000;
316 return user_memcpy(arg
, &state
, sizeof(ether_link_state_t
));
320 LOG(("ETHER_ADDMULTI\n"));
324 LOG(("ETHER_REMMULTI\n"));
327 case ETHER_SETPROMISC
:
328 LOG(("ETHER_SETPROMISC\n"));
332 LOG(("Invalid command\n"));
341 wb840_close(void* cookie
)
343 wb_device
* device
= (wb_device
*)cookie
;
345 LOG((DEVICE_NAME
": close()\n"));
347 cancel_timer(&device
->timer
);
351 write32(device
->reg_base
+ WB_TXADDR
, 0x00000000);
352 write32(device
->reg_base
+ WB_RXADDR
, 0x00000000);
354 wb_disable_interrupts(device
);
355 remove_io_interrupt_handler(device
->irq
, wb_interrupt
, device
);
357 delete_sem(device
->rxSem
);
358 delete_sem(device
->txSem
);
365 wb840_free(void* cookie
)
367 wb_device
* device
= (wb_device
*)cookie
;
369 LOG((DEVICE_NAME
": free()\n"));
371 sOpenMask
&= ~(1L << device
->devId
);
373 wb_delete_rings(device
);
374 free(device
->firstPHY
);
383 wb840_open
, /* -> open entry point */
384 wb840_close
, /* -> close entry point */
385 wb840_free
, /* -> free cookie */
386 wb840_control
, /* -> control entry point */
387 wb840_read
, /* -> read entry point */
388 wb840_write
, /* -> write entry point */