BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / drivers / network / wb840 / device.c
blob0190ab6ca7468fa4784abb9a31f70f86d6e4af7f
1 /* Copyright (c) 2003-2011
2 * Stefano Ceccherini <stefano.ceccherini@gmail.com>. All rights reserved.
3 * This file is released under the MIT license
4 */
5 #include <KernelExport.h>
6 #include <Errors.h>
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
11 #include <net/if_media.h>
13 #include "debug.h"
14 #include "device.h"
15 #include "driver.h"
16 #include "interface.h"
17 #include "wb840.h"
20 #define MAX_CARDS 4
22 extern char* gDevNameList[];
23 extern pci_info* gDevList[];
25 static int32 sOpenMask = 0;
27 static status_t
28 wb840_open(const char* name, uint32 flags, void** cookie)
30 char* deviceName = NULL;
31 int32 i;
32 int32 mask;
33 struct wb_device* data;
34 status_t status;
36 LOG((DEVICE_NAME ": open()\n"));
38 for (i = 0; (deviceName = gDevNameList[i]) != NULL; i++) {
39 if (!strcmp(name, deviceName))
40 break;
43 if (deviceName == NULL) {
44 LOG(("invalid device name"));
45 return EINVAL;
48 // There can be only one access at time
49 mask = 1L << i;
50 if (atomic_or(&sOpenMask, mask) & mask)
51 return B_BUSY;
53 // Allocate a wb_device structure
54 if (!(data = (wb_device*)calloc(1, sizeof(wb_device)))) {
55 sOpenMask &= ~(1L << i);
56 return B_NO_MEMORY;
59 *cookie = data;
61 #ifdef DEBUG
62 load_driver_symbols("wb840");
63 #endif
65 data->devId = i;
66 data->pciInfo = gDevList[i];
67 data->deviceName = gDevNameList[i];
68 data->blockFlag = 0;
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);
77 if (status < B_OK) {
78 LOG((DEVICE_NAME": couldn't create semaphores\n"));
79 goto err;
82 status = wb_stop(data);
83 if (status < B_OK) {
84 LOG((DEVICE_NAME": can't stop device\n"));
85 goto err1;
88 status = wb_initPHYs(data);
89 if (status < B_OK) {
90 LOG((DEVICE_NAME": can't init PHYs\n"));
91 goto err1;
94 wb_init(data);
96 /* Setup interrupts */
97 data->irq = data->pciInfo->u.h0.interrupt_line;
98 status = install_io_interrupt_handler(data->irq, wb_interrupt, data, 0);
99 if (status < B_OK) {
100 LOG((DEVICE_NAME
101 ": can't install interrupt handler: %s\n", strerror(status)));
102 goto err1;
105 LOG((DEVICE_NAME ": interrupts installed at irq line %x\n", data->irq));
107 status = wb_create_rings(data);
108 if (status < B_OK) {
109 LOG((DEVICE_NAME": can't create ring buffers\n"));
110 goto err2;
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
123 err2:
124 remove_io_interrupt_handler(data->irq, wb_interrupt, data);
126 err1:
127 wb_delete_semaphores(data);
129 err:
130 sOpenMask &= ~(1L << i);
132 free(data);
133 LOG(("wb840: Open Failed\n"));
135 return status;
139 static status_t
140 wb840_read(void* cookie, off_t position, void* buf, size_t* num_bytes)
142 wb_device* device = (wb_device*)cookie;
143 int16 current;
144 status_t status;
145 size_t size;
146 int32 blockFlag;
147 uint32 check;
149 LOG((DEVICE_NAME ": read()\n"));
151 blockFlag = device->blockFlag;
153 if (atomic_or(&device->rxLock, 1)) {
154 *num_bytes = 0;
155 return B_ERROR;
158 status = acquire_sem_etc(device->rxSem, 1, B_CAN_INTERRUPT | blockFlag, 0);
159 if (status < B_OK) {
160 atomic_and(&device->rxLock, 0);
161 *num_bytes = 0;
162 return status;
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);
171 *num_bytes = 0;
172 return B_BUSY;
175 if (check & (WB_RXSTAT_RXERR | WB_RXSTAT_CRCERR | WB_RXSTAT_RUNT)) {
176 LOG(("Error read: packet with errors."));
177 *num_bytes = 0;
178 } else {
179 size = WB_RXBYTES(check);
180 size -= CRC_SIZE;
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));
184 size = *num_bytes;
186 *num_bytes = size;
187 memcpy(buf, (void*)device->rxBuffer[current], size);
190 device->rxCurrent = (current + 1) & WB_RX_CNT_MASK;
192 cpu_status former;
193 former = disable_interrupts();
194 acquire_spinlock(&device->rxSpinlock);
196 // release buffer to ring
197 wb_put_rx_descriptor(&device->rxDescriptor[current]);
198 device->rxFree++;
200 release_spinlock(&device->rxSpinlock);
201 restore_interrupts(former);
204 atomic_and(&device->rxLock, 0);
206 return B_OK;
210 static status_t
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;
215 uint16 frameSize;
216 int16 current;
217 uint32 check;
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);
231 if (status < B_OK) {
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);
236 *num_bytes = 0;
237 return status;
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);
245 *num_bytes = 0;
246 return B_ERROR;
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
260 | WB_TXCTL_LASTFRAG;
261 device->txDescriptor[current].wb_status = WB_TXSTAT_OWN;
262 device->txSent++;
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);
273 return B_OK;
277 static status_t
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"));
283 switch (op) {
284 case ETHER_INIT:
285 LOG(("%s: ETHER_INIT\n", data->deviceName));
286 return B_OK;
288 case ETHER_GETADDR:
289 LOG(("%s: ETHER_GETADDR\n", data->deviceName));
290 memcpy(arg, &data->MAC_Address, sizeof(data->MAC_Address));
291 print_address(arg);
292 return B_OK;
294 case ETHER_NONBLOCK:
295 LOG(("ETHER_NON_BLOCK\n"));
296 data->blockFlag = *(int32*)arg ? B_TIMEOUT : 0;
297 return B_OK;
299 case ETHER_GETFRAMESIZE:
300 LOG(("ETHER_GETFRAMESIZE\n"));
301 *(uint32 *)arg = WB_MAX_FRAMELEN;
302 return B_OK;
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));
319 case ETHER_ADDMULTI:
320 LOG(("ETHER_ADDMULTI\n"));
321 break;
323 case ETHER_REMMULTI:
324 LOG(("ETHER_REMMULTI\n"));
325 break;
327 case ETHER_SETPROMISC:
328 LOG(("ETHER_SETPROMISC\n"));
329 break;
331 default:
332 LOG(("Invalid command\n"));
333 break;
336 return B_ERROR;
340 static status_t
341 wb840_close(void* cookie)
343 wb_device* device = (wb_device*)cookie;
345 LOG((DEVICE_NAME ": close()\n"));
347 cancel_timer(&device->timer);
349 wb_stop(device);
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);
360 return B_OK;
364 static status_t
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);
375 free(device);
377 return B_OK;
381 device_hooks
382 gDeviceHooks = {
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 */
389 NULL,
390 NULL,
391 NULL,
392 NULL