vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / drivers / network / vlance / vlance.c
blob267f3bacce9437dd5353fca26c25624b7f7947d2
1 /*
2 * Copyright 2006, Hideyuki Abe. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
6 //! Ethernet Driver for VMware PCnet/PCI virtual network controller
8 #include "vlance.h"
10 #include <ether_driver.h>
12 #include <Drivers.h>
13 #include <KernelExport.h>
14 #include <OS.h>
15 #include <PCI.h>
17 #include <stdarg.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
23 /* debug flag definitions */
24 #define ERR 0x0001
25 #define INFO 0x0002
26 #define RX 0x0004 /* dump received frames */
27 #define TX 0x0008 /* dump transmitted frames */
28 #define INTERRUPT 0x0010 /* interrupt calls */
29 #define FUNCTION 0x0020 /* function calls */
30 #define PCI_IO 0x0040 /* pci reads and writes */
31 #define SEQ 0x0080 /* trasnmit & receive TCP/IP sequence sequence numbers */
32 #define WARN 0x0100 /* Warnings - off on final release */
34 /* debug flag */
35 //#define DEBUG_FLG ( ERR | INFO | WARN )
36 //#define DEBUG_FLG ( ERR | INFO | INTERRUPT | FUNCTION | WARN )
37 #define DEBUG_FLG ( ERR | WARN )
39 #define DEBUG(x) (DEBUG_FLG & (x))
40 #define TRACE(x) dprintf x
42 /* PCI vendor and device ID's */
43 #define VENDOR_ID 0x1022 /* AMD */
44 #define DEVICE_ID 0x2000 /* PCnet/PCI */
47 #define DEVICE_NAME "vlance"
48 #define DEVICE_NAME_LEN 64
50 #define MAX_CARDS 4 /* maximum number of driver instances */
52 #define BUFFER_SIZE 2048L /* B_PAGE_SIZE divided into even amounts that will hold a 1518 frame */
53 #define MAX_FRAME_SIZE 1514 /* 1514 + 4 bytes checksum */
55 /* ring buffer sizes */
56 #define TX_BUFF_IDX (4)
57 #define RX_BUFF_IDX (5)
58 #define TX_BUFFERS (1 << TX_BUFF_IDX)
59 #define RX_BUFFERS (1 << RX_BUFF_IDX) /* Must be a power of 2 */
61 /* max number of multicast address */
62 #define MAX_MULTI (4)
66 * 6-octet MAC address
68 typedef struct {
69 uint8 ch[6];
70 uint8 rsv[2];
71 } mac_addr_t;
74 /* driver intance definition */
75 typedef struct {
76 mac_addr_t mac_addr; /* MAC address */
77 int32 devID; /* device identifier */
78 pci_info *devInfo; /* device information */
79 uint16 irq; /* our IRQ line */
80 sem_id ilock, olock; /* I/O semaphores */
81 int32 readLock, writeLock; /* reentrant read/write lock */
82 int32 blockFlg; /* for blocking (0) or nonblocking (!=0) read */
83 init_block_t init_blk; /* Initialization Block */
84 uint32 phys_init_blk; /* Initialization Block physical address */
85 area_id tx_desc_area; /* transmit descriptor area */
86 area_id tx_buf_area; /* transmit buffer area */
87 area_id rx_desc_area; /* receive descriptor area */
88 area_id rx_buf_area; /* receive buffer area */
89 uchar *tx_buf[TX_BUFFERS]; /* tx buffers */
90 uchar *rx_buf[RX_BUFFERS]; /* rx buffers */
91 trns_desc_t *tx_desc[TX_BUFFERS]; /* tx frame descriptors */
92 recv_desc_t *rx_desc[RX_BUFFERS]; /* rx frame descriptors */
93 uint32 phys_tx_buf; /* tx buffer physical address */
94 uint32 phys_rx_buf; /* rx buffer physical address */
95 uint32 phys_tx_desc; /* tx descriptor physical address */
96 uint32 phys_rx_desc; /* rx descriptor physical address */
97 int16 tx_sent, tx_acked; /* in & out index to tx buffers */
98 int16 rx_received, rx_acked; /* in & out index to rx buffers */
99 int32 nmulti; /* number of multicast address */
100 mac_addr_t multi[MAX_MULTI]; /* multicast address */
101 uint32 reg_base; /* base address of PCI regs */
102 } dev_info_t;
105 /* function prototypes */
106 static status_t vlance_open(const char *name, uint32 flags, void **_cookie);
107 static status_t vlance_close(void *_device);
108 static status_t vlance_free(void *_device);
109 static status_t vlance_control(void *cookie, uint32 msg, void *buf, size_t len);
110 static status_t vlance_read(void *_device, off_t pos, void *buf, size_t *len);
111 static status_t vlance_write(void *_device, off_t pos, const void *buf, size_t *len);
112 static int32 vlance_interrupt(void *_device);
114 static device_hooks sDeviceHooks = {
115 vlance_open, /* open entry point */
116 vlance_close, /* close entry point */
117 vlance_free, /* free entry point */
118 vlance_control, /* control entry point */
119 vlance_read, /* read entry point */
120 vlance_write, /* write entry point */
121 NULL, /* select entry point */
122 NULL, /* deselect entry point */
123 NULL, /* readv */
124 NULL /* writev */
127 int32 api_version = B_CUR_DRIVER_API_VERSION;
129 static pci_module_info *sPCI;
130 static uint32 sNumOfCards;
131 static char *sDeviceNames[MAX_CARDS + 1]; /* NULL-terminated */
132 static pci_info *sCardInfo[MAX_CARDS];
133 static int32 sOpenLock[MAX_CARDS];
136 #define write8(addr, val) (*sPCI->write_io_8)((addr), (val))
137 #define write16(addr, val) (*sPCI->write_io_16)((addr), (val))
138 #define write32(addr, val) (*sPCI->write_io_32)((addr), (val))
139 #define read8(addr) ((*sPCI->read_io_8)(addr))
140 #define read16(addr) ((*sPCI->read_io_16)(addr))
141 #define read32(addr) ((*sPCI->read_io_32)(addr))
143 #define RNDUP(x, y) (((x) + (y) - 1) & ~((y) - 1))
146 // #pragma mark - register access
149 static inline uint32
150 csr_read(dev_info_t *device, uint32 reg_num)
152 write32(device->reg_base + PCNET_RAP_OFFSET, reg_num);
153 return read32(device->reg_base + PCNET_RDP_OFFSET);
157 static inline void
158 csr_write(dev_info_t *device, uint32 reg_num, uint32 data)
160 write32(device->reg_base + PCNET_RAP_OFFSET, reg_num);
161 write32(device->reg_base + PCNET_RDP_OFFSET, data);
165 static inline uint32
166 bcr_read(dev_info_t *device, uint32 reg_num)
168 write32(device->reg_base + PCNET_RAP_OFFSET, reg_num);
169 return read32(device->reg_base + PCNET_BDP_OFFSET);
173 static inline void
174 bcr_write(dev_info_t *device, uint32 reg_num, uint32 data)
176 write32(device->reg_base + PCNET_RAP_OFFSET, reg_num);
177 write32(device->reg_base + PCNET_BDP_OFFSET, data);
181 // #pragma mark - misc
184 static int32
185 get_card_info(pci_info *info[])
187 status_t status;
188 int32 i, entries;
189 pci_info *item = (pci_info *)malloc(sizeof(pci_info));
190 if (item == NULL)
191 return 0;
193 for (i = 0, entries = 0; entries < MAX_CARDS; i++) {
194 status = sPCI->get_nth_pci_info(i, item);
195 if (status != B_OK)
196 break;
198 if (item->vendor_id == VENDOR_ID && item->device_id == DEVICE_ID) {
199 /* check if the device really has an IRQ */
200 if (item->u.h0.interrupt_line == 0 || item->u.h0.interrupt_line == 0xff) {
201 TRACE((DEVICE_NAME " found with invalid IRQ - check IRQ assignement\n"));
202 continue;
205 TRACE((DEVICE_NAME " found at IRQ %x\n", item->u.h0.interrupt_line));
207 info[entries++] = item;
208 item = (pci_info *)malloc(sizeof(pci_info));
212 free(item);
213 return entries;
217 static status_t
218 free_card_info(pci_info *info[])
220 int32 i;
222 for (i = 0; i < sNumOfCards; i++) {
223 free(info[i]);
226 return B_OK;
230 static status_t
231 map_pci_addr(dev_info_t *device)
233 pci_info *dev_info = device->devInfo;
234 int32 pci_cmd;
236 pci_cmd = sPCI->read_pci_config(dev_info->bus, dev_info->device,
237 dev_info->function, PCI_command, 2);
239 /* turn on I/O port decode, Memory Address Decode, and Bus Mastering */
240 sPCI->write_pci_config(dev_info->bus, dev_info->device,
241 dev_info->function, PCI_command, 2,
242 pci_cmd | PCI_command_io | PCI_command_memory | PCI_command_master);
244 device->reg_base = dev_info->u.h0.base_registers[0];
246 #if DEBUG(PCI_IO)
247 dprintf(DEVICE_NAME ": reg_base=%x\n", device->reg_base);
248 #endif
250 return B_OK;
254 static status_t
255 alloc_buffers(dev_info_t *device)
257 uint32 size;
258 uint16 i;
259 physical_entry entry;
261 /* get physical address of Initialization Block */
262 size = RNDUP(sizeof(dev_info_t), B_PAGE_SIZE);
263 get_memory_map(&(device->init_blk), size, &entry, 1);
264 device->phys_init_blk = entry.address;
266 TRACE((DEVICE_NAME " init block va=%p pa=%p, size %lx\n",
267 &(device->init_blk), (void *)device->phys_init_blk, size));
269 /* create tx descriptor area */
270 size = RNDUP(sizeof(trns_desc_t) * TX_BUFFERS, B_PAGE_SIZE);
271 device->tx_desc_area = create_area(DEVICE_NAME " tx descriptors",
272 (void **)device->tx_desc, B_ANY_KERNEL_ADDRESS, size,
273 B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
274 if (device->tx_desc_area < 0)
275 return device->tx_desc_area;
277 for (i = 1; i < TX_BUFFERS; i++) {
278 device->tx_desc[i] = (device->tx_desc[i-1]) + 1;
280 /* get physical address of tx descriptor */
281 get_memory_map(device->tx_desc[0], size, &entry, 1);
282 device->phys_tx_desc = entry.address;
284 TRACE((DEVICE_NAME " create tx desc area va=%p pa=%p sz=%lx\n",
285 device->tx_desc[0], (void *)device->phys_tx_desc, size));
287 /* create tx buffer area */
288 size = RNDUP(BUFFER_SIZE * TX_BUFFERS, B_PAGE_SIZE);
289 device->tx_buf_area = create_area(DEVICE_NAME " tx buffers",
290 (void **)device->tx_buf, B_ANY_KERNEL_ADDRESS, size,
291 B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
292 if (device->tx_buf_area < 0) {
293 delete_area(device->tx_desc_area); // sensitive to alloc ordering
294 return device->tx_buf_area;
297 for (i = 1; i < TX_BUFFERS; i++) {
298 device->tx_buf[i] = (device->tx_buf[i-1]) + BUFFER_SIZE;
301 /* get physical address of tx buffer */
302 get_memory_map(device->tx_buf[0], size, &entry, 1);
303 device->phys_tx_buf = entry.address;
305 TRACE((DEVICE_NAME " create tx buf area va=%p pa=%08lx sz=%lx\n",
306 device->tx_buf[0], device->tx_desc[0]->s.tbadr, size));
308 /* create rx descriptor area */
309 size = RNDUP( sizeof(recv_desc_t) * RX_BUFFERS, B_PAGE_SIZE);
310 device->rx_desc_area = create_area(DEVICE_NAME " rx descriptors",
311 (void **)device->rx_desc, B_ANY_KERNEL_ADDRESS, size,
312 B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
313 if (device->rx_desc_area < 0) {
314 delete_area(device->tx_desc_area);
315 delete_area(device->tx_buf_area); // sensitive to alloc ordering
316 return device->rx_desc_area;
319 for (i = 1; i < RX_BUFFERS; i++) {
320 device->rx_desc[i] = (device->rx_desc[i-1]) + 1;
322 /* get physical address of rx descriptor */
323 get_memory_map(device->rx_desc[0], size, &entry, 1);
324 device->phys_rx_desc = entry.address;
326 TRACE((DEVICE_NAME " create rx desc area va=%p pa=%p sz=%lx\n",
327 device->rx_desc[0], (void *)device->phys_rx_desc, size));
329 /* create rx buffer area */
330 size = RNDUP(BUFFER_SIZE * RX_BUFFERS, B_PAGE_SIZE);
331 device->rx_buf_area = create_area(DEVICE_NAME " rx buffers",
332 (void **)device->rx_buf, B_ANY_KERNEL_ADDRESS, size,
333 B_32_BIT_FULL_LOCK, B_READ_AREA | B_WRITE_AREA);
334 if (device->rx_buf_area < 0) {
335 delete_area(device->tx_desc_area);
336 delete_area(device->tx_buf_area);
337 delete_area(device->rx_desc_area); // sensitive to alloc ordering
338 return device->rx_buf_area;
340 for (i = 1; i < RX_BUFFERS; i++) {
341 device->rx_buf[i] = (device->rx_buf[i-1]) + BUFFER_SIZE;
343 /* get physical address of rx buffer */
344 get_memory_map(device->rx_buf[0], size, &entry, 1);
345 device->phys_rx_buf = entry.address;
347 TRACE((DEVICE_NAME " create rx buf area va=%p pa=%08lx sz=%lx\n",
348 device->rx_buf[0], device->rx_desc[0]->s.rbadr, size));
350 return B_OK;
354 static status_t
355 init_buffers(dev_info_t *device)
357 int i;
359 /* initilize tx descriptors */
360 for (i = 0; i < TX_BUFFERS; i++) {
361 device->tx_desc[i]->s.tbadr = device->phys_tx_buf + BUFFER_SIZE * i;
362 device->tx_desc[i]->s.bcnt = -BUFFER_SIZE;
363 device->tx_desc[i]->s.status = 0;
364 device->tx_desc[i]->s.misc = 0UL;
365 device->tx_desc[i]->s.rsvd = 0UL;
368 /* initialize rx descriptors */
369 for (i = 0; i < RX_BUFFERS; i++) {
370 device->rx_desc[i]->s.rbadr = device->phys_rx_buf + BUFFER_SIZE * i;
371 device->rx_desc[i]->s.bcnt = -BUFFER_SIZE;
372 // device->rx_desc[i]->s.status = 0;
373 device->rx_desc[i]->s.status = 0x8000; /* OWN */
374 device->rx_desc[i]->s.mcnt = 0UL;
375 device->rx_desc[i]->s.rsvd = 0UL;
378 /* initialize frame indexes */
379 device->tx_sent = device->tx_acked = device->rx_received = device->rx_acked = 0;
381 return B_OK;
385 static void
386 free_buffers(dev_info_t *device)
388 delete_area(device->tx_desc_area);
389 delete_area(device->tx_buf_area);
390 delete_area(device->rx_desc_area);
391 delete_area(device->rx_buf_area);
395 static void
396 get_mac_addr(dev_info_t *device)
398 int i;
400 TRACE((DEVICE_NAME ": Mac address: "));
402 for (i = 0; i < 6; i++) {
403 device->mac_addr.ch[i] = read8(device->reg_base + PCNET_APROM_OFFSET + i);
404 TRACE((" %02x", device->mac_addr.ch[i]));
407 TRACE(("\n"));
411 /* set hardware so all packets are received. */
412 static status_t
413 setpromisc(dev_info_t *device)
415 TRACE((DEVICE_NAME ":setpormisc\n"));
417 csr_write(device, PCNET_CSR_STATUS, 0x0004UL);
418 csr_write(device, PCNET_CSR_MODE, 0x8000UL); /* promiscous mode */
419 csr_write(device, PCNET_CSR_STATUS, 0x0042UL);
421 return B_OK;
425 #define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
427 static status_t
428 domulti(dev_info_t *device, uint8 *addr)
430 uint16 mcast_table[4];
431 uint8 *addrs;
432 int i, j, bit, byte;
433 uint32 crc, poly = CRC_POLYNOMIAL_LE;
435 if (device->nmulti == MAX_MULTI)
436 return B_ERROR;
438 for (i = 0; i < device->nmulti; i++) {
439 if (memcmp(&device->multi[i], addr, sizeof(device->multi[i])) == 0)
440 break;
442 if (i != device->nmulti)
443 return B_ERROR;
445 // only copy if it isn't there already
446 memcpy(&device->multi[i], addr, sizeof(device->multi[i]));
447 device->nmulti++;
449 TRACE((DEVICE_NAME ": domulti %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
450 addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]));
452 /* clear the multicast filter */
453 mcast_table[0] = 0; mcast_table[1] = 0;
454 mcast_table[2] = 0; mcast_table[3] = 0;
456 /* set addresses */
457 for (i = 0; i < device->nmulti; i++) {
458 addrs = (uint8 *)(&(device->multi[i]));
459 /* multicast address? */
460 if (!(*addrs & 1))
461 break;
463 crc = 0xffffffff;
464 for (byte = 0; byte < 6; byte++) {
465 for (bit = *addrs++, j = 0; j < 8; j++, bit >>= 1) {
466 int test;
468 test = ((bit ^ crc) & 0x01);
469 crc >>= 1;
470 if (test)
471 crc = crc ^ poly;
474 crc = crc >> 26;
475 mcast_table[crc >> 4] |= 1 << (crc & 0xf);
478 csr_write(device, PCNET_CSR_STATUS, 0x0004UL);
479 csr_write(device, PCNET_CSR_MODE, 0x0000UL); /* portsel ?? */
480 csr_write(device, PCNET_CSR_LADRF0, mcast_table[0]);
481 csr_write(device, PCNET_CSR_LADRF1, mcast_table[1]);
482 csr_write(device, PCNET_CSR_LADRF2, mcast_table[2]);
483 csr_write(device, PCNET_CSR_LADRF3, mcast_table[3]);
484 csr_write(device, PCNET_CSR_STATUS, 0x0042UL);
486 return B_OK;
490 static void
491 reset_device(dev_info_t *device)
493 TRACE((DEVICE_NAME ": reset_device reset the NIC hardware\n"));
495 read32(device->reg_base + PCNET_RST_OFFSET);
496 write32(device->reg_base + PCNET_RST_OFFSET, 0UL);
497 snooze(2); /* wait >1us */
502 * allocate and initialize semaphores.
504 static status_t
505 alloc_resources(dev_info_t *device)
507 /* rx semaphores */
508 device->ilock = create_sem(0, DEVICE_NAME " rx");
509 if (device->ilock < 0)
510 return device->ilock;
512 set_sem_owner(device->ilock, B_SYSTEM_TEAM);
514 /* tx semaphores */
515 device->olock = create_sem(TX_BUFFERS, DEVICE_NAME " tx");
516 if (device->olock < 0) {
517 delete_sem(device->ilock);
518 return device->olock;
521 set_sem_owner(device->olock, B_SYSTEM_TEAM);
523 device->readLock = device->writeLock = 0;
524 device->blockFlg = 0; // set blocking
526 return B_OK;
530 static void
531 free_resources(dev_info_t *device)
533 delete_sem(device->ilock);
534 delete_sem(device->olock);
538 // #pragma mark - driver API
541 status_t
542 init_hardware(void)
544 TRACE((DEVICE_NAME ": init hardware\n"));
545 return B_OK;
549 status_t
550 init_driver()
552 status_t status;
553 char devName[DEVICE_NAME_LEN];
554 int32 i;
556 TRACE((DEVICE_NAME ": init_driver\n"));
558 // TODO: this does not compile with our GCC 2.95.3
559 #if 0
561 uint32 mgc_num;
562 /* check VMware */
563 asm volatile (
564 "movl $0x564d5868, %%eax; "
565 "movl $0, %%ebx; "
566 "movw $0x000a, %%cx; "
567 "movw $0x5658, %%dx; "
568 "inl %%dx, %%eax"
569 : "=b"(mgc_num)
571 : "eax", "ecx", "edx");
573 TRACE((DEVICE_NAME ": VMware magic number %lx\n", mgc_num));
575 if (!(mgc_num == 0x564d5868))
576 return ENODEV;
578 #endif
580 status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCI);
581 if (status != B_OK)
582 return status;
584 /* find LAN cards */
585 sNumOfCards = get_card_info(sCardInfo);
586 if (sNumOfCards == 0) {
587 free_card_info(sCardInfo);
588 put_module(B_PCI_MODULE_NAME);
589 return B_ERROR;
592 /* create device name list*/
593 for (i = 0; i < sNumOfCards; i++) {
594 sprintf(devName, "net/%s/%ld", DEVICE_NAME, i);
595 sDeviceNames[i] = (char *)malloc(DEVICE_NAME_LEN);
596 strcpy(sDeviceNames[i], devName);
598 sDeviceNames[sNumOfCards] = NULL;
600 return B_OK;
604 void
605 uninit_driver(void)
607 int32 i;
609 /* free device name list*/
610 for (i = 0; i < sNumOfCards; i++) {
611 free(sDeviceNames[i]);
614 /* free device list*/
615 free_card_info(sCardInfo);
616 put_module(B_PCI_MODULE_NAME);
620 const char **
621 publish_devices(void)
623 TRACE((DEVICE_NAME ": publish_devices()\n" ));
624 return (const char **)sDeviceNames;
628 device_hooks *
629 find_device(const char *name)
631 int32 i;
633 /* find device name */
634 for (i = 0; i < sNumOfCards; i++) {
635 if (!strcmp(name, sDeviceNames[i]))
636 return &sDeviceHooks;
639 return NULL;
643 // #pragma mark - device API
646 static status_t
647 vlance_open(const char *name, uint32 flags, void **cookie)
649 int32 devID;
650 status_t status;
651 dev_info_t *device;
653 /* find device name */
654 for (devID = 0; devID < sNumOfCards; devID++) {
655 if (!strcmp(name, sDeviceNames[devID]))
656 break;
658 if (devID >= sNumOfCards)
659 return B_BAD_VALUE;
661 /* check if the device is busy and set in-use flag if not */
662 if (atomic_or(&(sOpenLock[devID]), 1))
663 return B_BUSY;
665 /* allocate storage for the cookie */
666 *cookie = device = (dev_info_t *)malloc(sizeof(dev_info_t));
667 if (device == NULL) {
668 status = B_NO_MEMORY;
669 goto err0;
671 memset(device, 0, sizeof(dev_info_t));
673 /* setup the cookie */
674 device->devInfo = sCardInfo[devID];
675 device->devID = devID;
677 TRACE((DEVICE_NAME ": open %s device=%p\n", name, device));
679 /* enable access to the cards address space */
680 status = map_pci_addr(device);
681 if (status != B_OK)
682 goto err1;
684 status = alloc_resources(device);
685 if (status != B_OK)
686 goto err1;
688 /* init device */
689 reset_device(device);
691 /* allocate and initialize frame buffer rings & descriptors */
692 status = alloc_buffers(device);
693 if (status != B_OK)
694 goto err2;
695 status = init_buffers(device);
696 if (status != B_OK)
697 goto err2;
699 /* setup interrupts */
700 install_io_interrupt_handler(device->devInfo->u.h0.interrupt_line,
701 vlance_interrupt, *cookie, 0);
702 /* init hardware */
704 TRACE((DEVICE_NAME ": hardware specific init\n"));
706 write32(device->reg_base + PCNET_RDP_OFFSET, 0UL); /* DWIO mode */
707 bcr_write(device, PCNET_BCR_SWS, 0x0002UL); /* 32bit mode */
709 get_mac_addr(device);
711 device->init_blk.s.mode = ((TX_BUFF_IDX & 0x0f) << 28) | ((RX_BUFF_IDX & 0x0f) << 20) | 0x0000UL; /* TLEN, RLEN */
712 memcpy(device->init_blk.s.padr, &(device->mac_addr), sizeof(mac_addr_t));
713 device->init_blk.s.padr[6] = 0;
714 device->init_blk.s.padr[7] = 0;
715 device->init_blk.s.ladr[0] = 0UL;
716 device->init_blk.s.ladr[1] = 0UL;
717 device->init_blk.s.rdra = device->phys_rx_desc;
718 device->init_blk.s.tdra = device->phys_tx_desc;
721 int i;
722 for (i = 0; i < sizeof(init_block_t); i++) {
723 TRACE((" %02X", *(((unsigned char *)&(device->init_blk)) + i)));
725 TRACE(("\n"));
728 csr_write(device, PCNET_CSR_IADDR0, (device->phys_init_blk) & 0xffffUL); /* set init block address L */
729 csr_write(device, PCNET_CSR_IADDR1, (device->phys_init_blk) >> 16); /* set init block address H */
730 csr_write(device, PCNET_CSR_STATUS, 0x0001UL); /* INIT */
731 while (!(csr_read(device, PCNET_CSR_STATUS) & 0x0100UL)); /* check IDON */
732 csr_write(device, PCNET_CSR_STATUS, 0x0004UL); /* STOP */
734 #if DEBUG(INFO)
735 dprintf(DEVICE_NAME ": STATUS = %04X\n", csr_read(device, PCNET_CSR_STATUS));
736 dprintf(DEVICE_NAME ": IADDR0 = %04X\n", csr_read(device, PCNET_CSR_IADDR0));
737 dprintf(DEVICE_NAME ": IADDR1 = %04X\n", csr_read(device, PCNET_CSR_IADDR1));
738 dprintf(DEVICE_NAME ": MODE = %04X\n", csr_read(device, PCNET_CSR_MODE));
739 dprintf(DEVICE_NAME ": PADR0 = %04X\n", csr_read(device, PCNET_CSR_PADR0));
740 dprintf(DEVICE_NAME ": PADR1 = %04X\n", csr_read(device, PCNET_CSR_PADR1));
741 dprintf(DEVICE_NAME ": PADR2 = %04X\n", csr_read(device, PCNET_CSR_PADR2));
742 dprintf(DEVICE_NAME ": LADRF0 = %04X\n", csr_read(device, PCNET_CSR_LADRF0));
743 dprintf(DEVICE_NAME ": LADRF1 = %04X\n", csr_read(device, PCNET_CSR_LADRF1));
744 dprintf(DEVICE_NAME ": LADRF2 = %04X\n", csr_read(device, PCNET_CSR_LADRF2));
745 dprintf(DEVICE_NAME ": LADRF3 = %04X\n", csr_read(device, PCNET_CSR_LADRF3));
746 dprintf(DEVICE_NAME ": BADRL = %04X\n", csr_read(device, PCNET_CSR_BADRL));
747 dprintf(DEVICE_NAME ": BADRH = %04X\n", csr_read(device, PCNET_CSR_BADRH));
748 dprintf(DEVICE_NAME ": BADXL = %04X\n", csr_read(device, PCNET_CSR_BADXL));
749 dprintf(DEVICE_NAME ": BADXH = %04X\n", csr_read(device, PCNET_CSR_BADXH));
750 dprintf(DEVICE_NAME ": BCR18 = %04X\n", bcr_read(device, PCNET_BCR_BSBC));
751 dprintf(DEVICE_NAME ": BCR20 = %04X\n", bcr_read(device, PCNET_BCR_SWS));
752 #endif
753 csr_write(device, PCNET_CSR_STATUS, 0x7f00); /* clear int source */
754 csr_write(device, PCNET_CSR_STATUS, 0x0042); /* IENA, STRT */
756 return B_OK;
758 err2:
759 free_buffers(device);
760 err1:
761 free_resources(device);
762 free(device);
763 err0:
764 atomic_and(&(sOpenLock[devID]), 0);
765 return status;
769 static status_t
770 vlance_close(void *_device)
772 dev_info_t *device = (dev_info_t *) _device;
774 TRACE((DEVICE_NAME ": vlance_close\n"));
776 csr_write(device, PCNET_CSR_STATUS, 0x0004); /* STOP */
777 TRACE((DEVICE_NAME ": STATUS = %04lx\n", csr_read(device,PCNET_CSR_STATUS)));
779 /* release resources */
780 free_resources(device);
782 return B_OK;
786 static status_t
787 vlance_free(void *cookie)
789 dev_info_t *device = (dev_info_t *)cookie;
791 TRACE((DEVICE_NAME": free %p\n", device));
793 /* remove Interrupt Handler */
794 remove_io_interrupt_handler(device->devInfo->u.h0.interrupt_line, vlance_interrupt, cookie);
796 free_buffers(device);
798 /* device is now available again */
799 atomic_and(&(sOpenLock[device->devID]), 0);
801 free(device);
802 return B_OK;
806 static status_t
807 vlance_control(void *cookie, uint32 op, void *buf, size_t len)
809 dev_info_t *device = (dev_info_t *)cookie;
811 switch (op) {
812 case ETHER_GETADDR: {
813 uint8 i;
814 TRACE((DEVICE_NAME ": control ether_getaddr\n"));
816 for (i = 0; i < 6; i++) {
817 ((uint8 *)buf)[i] = device->mac_addr.ch[i];
819 return B_OK;
821 case ETHER_INIT:
822 TRACE((DEVICE_NAME ": control init\n"));
823 return B_OK;
825 case ETHER_GETFRAMESIZE:
826 TRACE((DEVICE_NAME ": control get_framesize\n"));
827 *(uint32 *)buf = MAX_FRAME_SIZE;
828 return B_OK;
830 case ETHER_ADDMULTI:
831 TRACE((DEVICE_NAME ": control add multi\n"));
832 return domulti(device, (unsigned char *)buf);
834 case ETHER_SETPROMISC:
835 TRACE((DEVICE_NAME ": control set promiscuous\n"));
836 return setpromisc(device);
838 case ETHER_NONBLOCK:
839 TRACE((DEVICE_NAME ": control blocking %ld\n", *((int32*)buf)));
841 if (*((int32 *)buf))
842 device->blockFlg = 1; // set non-blocking
843 else
844 device->blockFlg = 0; // set blocking
845 return B_OK;
848 return B_BAD_VALUE;
852 static status_t
853 vlance_read(void *_device, off_t pos, void *buf, size_t *len)
855 dev_info_t *device = (dev_info_t *) _device;
856 int16 frame_size;
857 uint32 flags;
858 status_t status;
860 // *len = 0;
862 #if DEBUG(INFO)
863 dprintf(DEVICE_NAME ": read buf %p, len %d\n", buf, *len);
864 #endif
866 /* block until data is available (default) */
867 flags = B_CAN_INTERRUPT;
868 if(device->blockFlg) flags |= B_RELATIVE_TIMEOUT; // non-blocking (0-timeout)
869 status = acquire_sem_etc(device->ilock, 1, flags, 0);
870 if(status != B_NO_ERROR) {
871 #if DEBUG(INFO)
872 dprintf(DEVICE_NAME ": cannot acquire rx semaphore\n");
873 #endif
874 *len = 0;
875 return status;
877 #if DEBUG(INFO)
878 dprintf(DEVICE_NAME ": try to atomic_or readLock\n");
879 #endif
880 /* prevent reentrant read */
881 if(atomic_or(&device->readLock, 1)) {
882 #if DEBUG(ERR)
883 dprintf(DEVICE_NAME ": cannot atomic_or readLock\n");
884 #endif
885 release_sem_etc(device->ilock, 1, 0);
886 *len = 0;
887 return B_ERROR;
890 /* hardware specific code to copy data from the NIC into buf */
891 if((device->rx_desc[device->rx_acked]->s.status) & 0x8000) { /* owned by controller */
892 #if DEBUG(ERR)
893 dprintf(DEVICE_NAME ": rx desc owned by controller\n");
894 #endif
895 *len = 0;
896 status = B_ERROR;
897 } else {
898 #if DEBUG(INFO)
899 dprintf(DEVICE_NAME ": rx desc owned by host\n");
900 #endif
901 frame_size = 0;
902 status = B_ERROR;
903 if(!((device->rx_desc[device->rx_acked]->s.status) & 0x4000)) { /* not receive error */
904 frame_size = (device->rx_desc[device->rx_acked]->s.mcnt) & 0xfff;
905 if(frame_size > *len) frame_size = *len;
906 memcpy(buf, device->rx_buf[device->rx_acked], frame_size);
907 status = B_OK;
909 if(frame_size < *len) *len = frame_size;
910 device->rx_desc[device->rx_acked]->s.mcnt = 0;
911 device->rx_desc[device->rx_acked]->s.status = 0x8000; /* OWN */
912 device->rx_acked = (device->rx_acked + 1) & (RX_BUFFERS - 1);
915 /* release reentrant lock */
916 atomic_and(&device->readLock, 0);
918 return status;
922 static status_t
923 vlance_write(void *_device, off_t pos, const void *buf, size_t *len)
925 dev_info_t *device = (dev_info_t *)_device;
926 int16 frame_size;
927 status_t status;
929 TRACE((DEVICE_NAME ": write buf %p len %lu\n", buf, *len));
931 if (*len > MAX_FRAME_SIZE) {
932 #if DEBUG(ERR)
933 dprintf(DEVICE_NAME ": write %lu > 1514 tooo long\n", *len);
934 #endif
935 *len = MAX_FRAME_SIZE;
937 frame_size = *len;
939 status = acquire_sem_etc(device->olock, 1, B_CAN_INTERRUPT, 0);
940 if (status != B_NO_ERROR) {
941 *len = 0;
942 return status;
945 /* prevent reentrant write */
946 if (atomic_or(&device->writeLock, 1)) {
947 release_sem_etc(device->olock, 1, 0);
948 *len = 0;
949 return B_ERROR;
952 /* hardware specific code to transmit buff */
953 if ((device->tx_desc[device->tx_sent]->s.status) & 0x8000) {
954 /* owned by controller */
955 #if DEBUG(ERR)
956 dprintf(DEVICE_NAME ": tx desc owned by controller\n");
957 #endif
958 } else {
959 TRACE((DEVICE_NAME ": tx desc owned by host\n"));
961 memcpy(device->tx_buf[device->tx_sent], buf, frame_size);
962 device->tx_desc[device->tx_sent]->s.bcnt = -frame_size;
963 // (device->tx_desc[device->tx_sent]->s.status) |= 0x8300; /* OWN, STP, ENP */
964 (device->tx_desc[device->tx_sent]->s.status) |= 0x9300; /* OWN, LTINT, STP, ENP */
965 device->tx_sent = (device->tx_sent + 1) & (TX_BUFFERS - 1);
966 csr_write(device, PCNET_CSR_STATUS, 0x0048UL); /* IENA, TDMD */
969 /* release reentrant lock */
970 atomic_and(&device->writeLock, 0);
972 return B_OK;
976 /*! LAN controller interrupt handler */
977 static int32
978 vlance_interrupt(void *_device)
980 dev_info_t *device = (dev_info_t *)_device;
981 int32 handled = B_UNHANDLED_INTERRUPT;
982 int32 interruptStatus;
983 cpu_status state;
985 #if DEBUG(INTERRUPT)
986 dprintf(DEVICE_NAME ": ISR_ENTRY\n");
987 #endif
988 state = disable_interrupts(); /* disable int state */
990 interruptStatus = csr_read(device, PCNET_CSR_STATUS);
991 if (interruptStatus & 0x0080) {
992 #if DEBUG(INTERRUPT)
993 dprintf(DEVICE_NAME ": status %04X\n", interruptStatus);
994 #endif
996 /* clear interrupts */
997 csr_write(device, PCNET_CSR_STATUS, 0x7f00);
999 if (interruptStatus & 0x8000) {
1000 /* Error */
1001 #if DEBUG(ERR)
1002 dprintf(DEVICE_NAME ": int error status %04lx\n", interruptStatus);
1003 #endif
1004 csr_write(device, PCNET_CSR_STATUS, 0x0004); /* STOP */
1005 init_buffers(device);
1006 csr_write(device, PCNET_CSR_STATUS, 0x0001UL); /* INIT */
1007 while(!(csr_read(device, PCNET_CSR_STATUS) & 0x0100UL)); /* check IDON */
1008 csr_write(device, PCNET_CSR_STATUS, 0x0042); /* IENA, STRT */
1009 /* init semaphore ??? */
1010 release_sem_etc(device->olock, TX_BUFFERS, B_DO_NOT_RESCHEDULE);
1011 acquire_sem_etc(device->ilock, RX_BUFFERS, B_RELATIVE_TIMEOUT, 0);
1012 /* not count TINT & RINT ??? */
1013 interruptStatus &= ~0x0600;
1015 if (interruptStatus & 0x0200) { /* TINT */
1016 while (!((device->tx_desc[device->tx_acked]->s.status) & 0x8000)) {
1017 //dprintf(DEVICE_NAME ": rel tx sem\n");
1018 release_sem_etc(device->olock, 1, B_DO_NOT_RESCHEDULE);
1019 device->tx_acked = (device->tx_acked + 1) & (TX_BUFFERS - 1);
1020 if(device->tx_acked == device->tx_sent) break;
1023 if (interruptStatus & 0x0400) { /* RINT */
1024 while (!((device->rx_desc[device->rx_received]->s.status) & 0x8000)) {
1025 //dprintf(DEVICE_NAME ": rel rx sem\n");
1026 release_sem_etc(device->ilock, 1, B_DO_NOT_RESCHEDULE);
1027 device->rx_received = (device->rx_received + 1) & (RX_BUFFERS - 1);
1031 handled = B_INVOKE_SCHEDULER; /* set because the interrupt was from the NIC, not some other device sharing the interrupt line */
1033 #if DEBUG(INTERRUPT)
1034 dprintf(DEVICE_NAME ": ISR - its ours\n");
1035 #endif
1038 csr_write(device, PCNET_CSR_STATUS, 0x0042);
1040 restore_interrupts(state); /* restore int state */
1042 return handled;