xref: /minix/minix/drivers/net/vt6105/vt6105.c (revision 117b6ea0)
1 #include <minix/drivers.h>
2 #include <minix/netdriver.h>
3 #include <machine/pci.h>
4 #include "vt6105.h"
5 #include "io.h"
6 
7 /* global value */
8 static vt_driver g_driver;
9 static int g_instance;
10 
11 /* driver interface */
12 static int vt_init(unsigned int instance, ether_addr_t *addr);
13 static void vt_stop(void);
14 static void vt_mode(unsigned int mode);
15 static ssize_t vt_recv(struct netdriver_data *data, size_t max);
16 static int vt_send(struct netdriver_data *data, size_t size);
17 static void vt_intr(unsigned int mask);
18 static void vt_stat(eth_stat_t *stat);
19 
20 /* internal function */
21 static int vt_probe(vt_driver *pdev, int instance);
22 static int vt_init_buf(vt_driver *pdev);
23 static int vt_init_hw(vt_driver *pdev, ether_addr_t *addr);
24 static int vt_reset_hw(vt_driver *pdev);
25 static void vt_conf_addr(vt_driver *pdev, ether_addr_t *addr);
26 static void vt_handler(vt_driver *pdev);
27 static void vt_check_ints(vt_driver *pdev);
28 
29 /* developer interface */
30 static void vt_init_rx_desc(vt_desc *desc, size_t size, phys_bytes dma);
31 static void vt_init_tx_desc(vt_desc *desc, size_t size, phys_bytes dma);
32 static int vt_real_reset(u32_t base);
33 static int vt_init_power(u32_t base);
34 static int vt_init_mii(u32_t base);
35 static int vt_init_io(u32_t base);
36 static void vt_start_rx_tx(u32_t base);
37 static void vt_get_addr(u32_t base, u8_t *pa);
38 static int vt_check_link(u32_t base);
39 static void vt_stop_rx_tx(u32_t base);
40 static int vt_rx_status_ok(vt_desc *desc);
41 static int vt_get_rx_len(vt_desc *desc);
42 static void vt_tx_desc_start(vt_desc *desc, size_t size);
43 static void vt_wakeup_tx(u32_t base);
44 static int vt_tx_status_ok(vt_desc *desc);
45 
46 /* ======= Developer-defined function ======= */
47 /* Intialize Rx descriptor (### RX_DESC_INIT ###) */
48 static void vt_init_rx_desc(vt_desc *desc, size_t size, phys_bytes dma) {
49 	desc->status = DESC_OWN | ((size << 16) & DESC_RX_LENMASK);
50 	desc->addr = dma;
51 	desc->length = size;
52 }
53 
54 /* Intialize Tx descriptor (### TX_DESC_INIT ###) */
55 static void vt_init_tx_desc(vt_desc *desc, size_t size, phys_bytes dma) {
56 	desc->addr = dma;
57 	desc->length = size;
58 }
59 
60 /* Real hardware reset (### RESET_HARDWARE_CAN_FAIL ###)
61  * -- Return OK means success, Others means failure */
62 static int vt_real_reset(u32_t base) {
63 	vt_out16(base, REG_CR, CMD_RESET);
64 	micro_delay(10000);
65 	if (vt_in16(base, REG_CR) & CMD_RESET) {
66 		vt_out8(base, REG_MCR1, 0x40);
67 		micro_delay(10000);
68 		if (vt_in16(base, REG_CR) & CMD_RESET)
69 			return -EIO;
70 	}
71 	return OK;
72 }
73 
74 /* Intialize power (### POWER_INIT_CAN_FAIL ###)
75  * -- Return OK means success, Others means failure */
76 static int vt_init_power(u32_t base) {
77 	u8_t stick;
78 	stick = vt_in8(base, REG_STICK);
79 	vt_out8(base, REG_STICK, stick & 0xfc);
80 	return OK;
81 }
82 
83 /* Intialize MII interface (### MII_INIT_CAN_FAIL ###)
84  * -- Return OK means success, Others means failure */
85 static int vt_init_mii(u32_t base) {
86 	return OK;
87 }
88 
89 /* Intialize other hardware I/O registers (### INIT_HARDWARE_IO_CAN_FAIL ###)
90  * -- Return OK means success, Others means failure */
91 static int vt_init_io(u32_t base) {
92 	vt_out16(base, REG_BCR0, 0x0006);
93 	vt_out8(base, REG_TCR, 0x20);
94 	vt_out8(base, REG_RCR, 0x78);
95 	return OK;
96 }
97 
98 /* Start Rx/Tx (### START_RX_TX ###) */
99 static void vt_start_rx_tx(u32_t base) {
100 	u16_t cmd = CMD_START | CMD_RX_ON | CMD_TX_ON | CMD_NO_POLL | CMD_FDUPLEX;
101 	vt_out16(base, REG_CR, cmd);
102 	micro_delay(1000);
103 }
104 
105 /* Get MAC address to the array 'pa' (### GET_MAC_ADDR ###) */
106 static void vt_get_addr(u32_t base, u8_t *pa) {
107 	int i;
108 	for (i = 0; i < 6; i++)
109 		pa[i] = vt_in8(base, REG_ADDR + i);
110 }
111 
112 /* Check link status (### CHECK_LINK ###)
113  * -- Return LINK_UP or LINK_DOWN */
114 static int vt_check_link(u32_t base) {
115 	u32_t r;
116 	vt_out8(base, REG_MII_CFG, 0x01);
117 	vt_out8(base, REG_MII_ADDR, 0x01);
118 	vt_out8(base, REG_MII_CR, 0x40);
119 	micro_delay(10000);
120 	r = vt_in16(base, REG_MII_DATA);
121 	if (r & 0x0004)
122 		return LINK_UP;
123 	return LINK_DOWN;
124 }
125 
126 /* Stop Rx/Tx (### STOP_RX_TX ###) */
127 static void vt_stop_rx_tx(u32_t base) {
128 	vt_out16(base, REG_CR, CMD_STOP);
129 }
130 
131 /* Check whether Rx status OK (### CHECK_RX_STATUS_OK ###)
132  * -- Return TRUE or FALSE */
133 static int vt_rx_status_ok(vt_desc *desc) {
134 	if (!(desc->status & DESC_OWN)) {
135 		if ((desc->status & DESC_RX_NORMAL) == DESC_RX_NORMAL)
136 			return TRUE;
137 	}
138 	return FALSE;
139 }
140 
141 /* Get Rx data length from descriptor (### GET_RX_LEN ###)
142  * --- Return the length */
143 static int vt_get_rx_len(vt_desc *desc) {
144 	int len;
145 	len = ((desc->status & DESC_RX_LENMASK) >> 16) - ETH_CRC_SIZE;
146 	return len;
147 }
148 
149 /* Set Tx descriptor in send (### TX_DESC_START ###) */
150 static void vt_tx_desc_start(vt_desc *desc, size_t size) {
151 	desc->status = DESC_OWN | DESC_FIRST | DESC_LAST;
152 	desc->length = 0x00e08000 | (size > 60 ? size : 60);
153 }
154 
155 /* Wake up Tx channel (### WAKE_UP_TX ###) */
156 static void vt_wakeup_tx(u32_t base) {
157 	u8_t cmd;
158 	cmd = vt_in8(base, REG_CR);
159 	cmd |= CMD_TX_DEMAND;
160 	vt_out8(base, REG_CR, cmd);
161 }
162 
163 /* Check whether Tx status OK (### CHECK_TX_STATUS_OK ###)
164  * -- Return TRUE or FALSE */
165 static int vt_tx_status_ok(vt_desc *desc) {
166 	if (!(desc->status & DESC_OWN))
167 		return TRUE;
168 	return FALSE;
169 }
170 
171 /* Driver interface table */
172 static const struct netdriver vt_table = {
173 	.ndr_init = vt_init,
174 	.ndr_stop = vt_stop,
175 	.ndr_mode = vt_mode,
176 	.ndr_recv = vt_recv,
177 	.ndr_send = vt_send,
178 	.ndr_stat = vt_stat,
179 	.ndr_intr = vt_intr,
180 };
181 
182 int main(int argc, char *argv[]) {
183 	env_setargs(argc, argv);
184 	netdriver_task(&vt_table);
185 }
186 
187 /* Initialize the driver */
188 static int vt_init(unsigned int instance, ether_addr_t *addr) {
189 	int ret = 0;
190 
191 	/* Intialize driver data structure */
192 	memset(&g_driver, 0, sizeof(g_driver));
193 	g_driver.link = LINK_UNKNOWN;
194 	strcpy(g_driver.name, "netdriver#0");
195 	g_driver.name[10] += instance;
196 	g_instance = instance;
197 
198 	/* Probe the device */
199 	if (vt_probe(&g_driver, instance)) {
200 		printf("vt6105: Device is not found\n");
201 		ret = -ENODEV;
202 		goto err_probe;
203 	}
204 
205 	/* Allocate and initialize buffer */
206 	if (vt_init_buf(&g_driver)) {
207 		printf("vt6105: Fail to initialize buffer\n");
208 		ret = -ENODEV;
209 		goto err_init_buf;
210 	}
211 
212 	/* Intialize hardware */
213 	if (vt_init_hw(&g_driver, addr)) {
214 		printf("vt6105: Fail to initialize hardware\n");
215 		ret = -EIO;
216 		goto err_init_hw;
217 	}
218 
219 	/* Use a synchronous alarm instead of a watchdog timer */
220 	sys_setalarm(sys_hz(), 0);
221 
222 	/* Clear send and recv flag */
223 	g_driver.send_flag = FALSE;
224 	g_driver.recv_flag = FALSE;
225 
226 	return 0;
227 
228 err_init_hw:
229 	free_contig(g_driver.buf, g_driver.buf_size);
230 err_init_buf:
231 err_probe:
232 	return ret;
233 }
234 
235 /* Match the device and get base address */
236 static int vt_probe(vt_driver *pdev, int instance) {
237 	int devind, ioflag;
238 	u16_t cr, vid, did;
239 	u32_t bar, size;
240 	u8_t irq, rev;
241 	u8_t *reg;
242 
243 	/* Find pci device */
244 	pci_init();
245 	if (!pci_first_dev(&devind, &vid, &did))
246 		return -EIO;
247 	while (instance--) {
248 		if (!pci_next_dev(&devind, &vid, &did))
249 			return -EIO;
250 	}
251 	pci_reserve(devind);
252 
253 	/* Enable bus mastering */
254 	cr = pci_attr_r16(devind, PCI_CR);
255 	if (!(cr & PCI_CR_MAST_EN))
256 		pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);
257 
258 	/* Get base address */
259 #ifdef DMA_REG_MODE
260 	if (pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) {
261 		printf("vt6105: Fail to get PCI BAR\n");
262 		return -EIO;
263 	}
264 	if (ioflag) {
265 		printf("vt6105: PCI BAR is not for memory\n");
266 		return -EIO;
267 	}
268 	if ((reg = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) {
269 		printf("vt6105: Fail to map hardware registers from PCI\n");
270 		return -EIO;
271 	}
272 	pdev->base_addr = (u32_t)reg;
273 #else
274 	bar = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
275 	if (bar < 0x400) {
276 		printf("vt6105: Base address is not properly configured\n");
277 		return -EIO;
278 	}
279 	pdev->base_addr = bar;
280 #endif
281 
282 	/* Get irq number */
283 	irq = pci_attr_r8(devind, PCI_ILR);
284 	pdev->irq = irq;
285 
286 	/* Get revision ID */
287 	rev = pci_attr_r8(devind, PCI_REV);
288 	pdev->revision = rev;
289 
290 #ifdef MY_DEBUG
291 	printf("vt6105: Base address is 0x%08x\n", pdev->base_addr);
292 	printf("vt6105: IRQ number is 0x%02x\n", pdev->irq);
293 	printf("vt6105: Revision ID is 0x%02x\n", pdev->revision);
294 #endif
295 
296 	return 0;
297 }
298 
299 /* Allocate and initialize buffer */
300 static int vt_init_buf(vt_driver *pdev) {
301 	size_t rx_desc_size, tx_desc_size, rx_buf_size, tx_buf_size, tot_buf_size;
302 	vt_desc *desc;
303 	phys_bytes buf_dma, next;
304 	char *buf;
305 	int i;
306 
307 	/* Build Rx and Tx descriptor buffer */
308 	rx_desc_size = RX_DESC_NUM * sizeof(vt_desc);
309 	tx_desc_size = TX_DESC_NUM * sizeof(vt_desc);
310 
311 	/* Allocate Rx and Tx buffer */
312 	tx_buf_size = TX_BUF_SIZE;
313 	if (tx_buf_size % 4)
314 		tx_buf_size += 4 - (tx_buf_size % 4);
315 	rx_buf_size = RX_BUF_SIZE;
316 	tot_buf_size = rx_desc_size + tx_desc_size;
317 	tot_buf_size += TX_DESC_NUM * tx_buf_size + RX_DESC_NUM * rx_buf_size;
318 	if (tot_buf_size % 4096)
319 		tot_buf_size += 4096 - (tot_buf_size % 4096);
320 
321 	if (!(buf = alloc_contig(tot_buf_size, 0, &buf_dma))) {
322 		printf("vt6105: Fail to allocate memory\n");
323 		return -ENOMEM;
324 	}
325 	pdev->buf_size = tot_buf_size;
326 	pdev->buf = buf;
327 
328 	/* Rx descriptor */
329 	pdev->rx_desc = (vt_desc *)buf;
330 	pdev->rx_desc_dma = buf_dma;
331 	memset(buf, 0, rx_desc_size);
332 	buf += rx_desc_size;
333 	buf_dma += rx_desc_size;
334 
335 	/* Tx descriptor */
336 	pdev->tx_desc = (vt_desc *)buf;
337 	pdev->tx_desc_dma = buf_dma;
338 	memset(buf, 0, tx_desc_size);
339 	buf += tx_desc_size;
340 	buf_dma += tx_desc_size;
341 
342 	/* Rx buffer assignment */
343 	desc = pdev->rx_desc;
344 	next = pdev->rx_desc_dma;
345 	for (i = 0; i < RX_DESC_NUM; i++) {
346 		/* Set Rx buffer */
347 		pdev->rx[i].buf_dma = buf_dma;
348 		pdev->rx[i].buf = buf;
349 		buf_dma += rx_buf_size;
350 		buf += rx_buf_size;
351 
352 		/* Set Rx descriptor */
353 		/* ### RX_DESC_INIT ### */
354 		vt_init_rx_desc(desc, rx_buf_size, pdev->rx[i].buf_dma);
355 		if (i == (RX_DESC_NUM - 1))
356 			desc->next = pdev->rx_desc_dma;
357 		else {
358 			next += sizeof(vt_desc);
359 			desc->next = next;
360 			desc++;
361 		}
362 	}
363 
364 	/* Tx buffer assignment */
365 	desc = pdev->tx_desc;
366 	next = pdev->tx_desc_dma;
367 	for (i = 0; i < TX_DESC_NUM; i++) {
368 		/* Set Tx buffer */
369 		pdev->tx[i].busy = 0;
370 		pdev->tx[i].buf_dma = buf_dma;
371 		pdev->tx[i].buf = buf;
372 		buf_dma += tx_buf_size;
373 		buf += tx_buf_size;
374 
375 		/* Set Rx descriptor */
376 		/* ### TX_DESC_INIT ### */
377 		vt_init_tx_desc(desc, tx_buf_size, pdev->tx[i].buf_dma);
378 		if (i == (TX_DESC_NUM - 1))
379 			desc->next = pdev->tx_desc_dma;
380 		else {
381 			next += sizeof(vt_desc);
382 			desc->next = next;
383 			desc++;
384 		}
385 	}
386 	pdev->tx_busy_num = 0;
387 	pdev->tx_head = 0;
388 	pdev->tx_tail = 0;
389 	pdev->rx_head = 0;
390 
391 	return 0;
392 }
393 
394 /* Intialize hardware */
395 static int vt_init_hw(vt_driver *pdev, ether_addr_t *addr) {
396 	int r, ret;
397 
398 	/* Set the OS interrupt handler */
399 	pdev->hook = pdev->irq;
400 	if ((r = sys_irqsetpolicy(pdev->irq, 0, &pdev->hook)) != OK) {
401 		printf("vt6105: Fail to set OS IRQ policy: %d\n", r);
402 		ret = -EFAULT;
403 		goto err_irq_policy;
404 	}
405 
406 	/* Reset hardware */
407 	if (vt_reset_hw(pdev)) {
408 		printf("vt6105: Fail to reset the device\n");
409 		ret = -EIO;
410 		goto err_reset_hw;
411 	}
412 
413 	/* Enable OS IRQ */
414 	if ((r = sys_irqenable(&pdev->hook)) != OK) {
415 		printf("vt6105: Fail to enable OS IRQ: %d\n", r);
416 		ret = -EFAULT;
417 		goto err_irq_enable;
418 	}
419 
420 	/* Configure MAC address */
421 	vt_conf_addr(pdev, addr);
422 
423 	/* Detect link status */
424 	pdev->link = vt_check_link(pdev->base_addr);
425 #ifdef MY_DEBUG
426 	if (pdev->link)
427 		printf("vt6105: Link up\n");
428 	else
429 		printf("vt6105: Link down\n");
430 #endif
431 
432 	return 0;
433 
434 err_reset_hw:
435 err_irq_enable:
436 err_irq_policy:
437 	return ret;
438 }
439 
440 /* Reset hardware */
441 static int vt_reset_hw(vt_driver *pdev) {
442 	u32_t base = pdev->base_addr;
443 	int ret;
444 
445 	/* Reset the chip */
446 	/* ### RESET_HARDWARE_CAN_FAIL ### */
447 	if (vt_real_reset(base)) {
448 		printf("vt6105: Fail to reset the hardware\n");
449 		ret = -EIO;
450 		goto err_real_reset;
451 	}
452 
453 	/* Initialize power */
454 	/* ### POWER_INIT_CAN_FAIL ### */
455 	if (vt_init_power(base)) {
456 		printf("vt6105: Fail to initialize power\n");
457 		ret = -EIO;
458 		goto err_init_power;
459 	}
460 
461 	/* Initialize MII interface */
462 	/* ### MII_INIT_CAN_FAIL ### */
463 	if (vt_init_mii(base)) {
464 		printf("vt6105: Fail to initialize MII interface\n");
465 		ret = -EIO;
466 		goto err_init_mii;
467 	}
468 
469 	/* Initialize hardware I/O registers */
470 	/* ### SET_RX_DESC_REG ### */
471 	if (vt_init_io(base)) {
472 		printf("vt6105: Fail to initialize I/O registers\n");
473 		ret = -EIO;
474 		goto err_init_io;
475 	}
476 
477 	/* Set Rx/Tx descriptor into register */
478 	/* ### SET_RX_DESC_REG ### */
479 	vt_out32(base, REG_RX_DESC_BASEL, pdev->rx_desc_dma);
480 #ifdef DESC_BASE_DMA64
481 	vt_out32(base, REG_RX_DESC_BASEU, 0x00000000);
482 #endif
483 	/* ### SET_TX_DESC_REG ### */
484 	vt_out32(base, REG_TX_DESC_BASEL, pdev->tx_desc_dma);
485 #ifdef DESC_BASE_DMA64
486 	vt_out32(base, REG_TX_DESC_BASEU, 0x00000000);
487 #endif
488 
489 	/* Enable interrupts */
490 	/* ### ENABLE_INTR ### */
491 	vt_out16(base, REG_IMR, INTR_IMR_ENABLE);
492 
493 	/* Start the device, Rx and Tx */
494 	/* ### START_RX_TX ### */
495 	vt_start_rx_tx(base);
496 
497 	return 0;
498 
499 err_init_io:
500 err_init_mii:
501 err_init_power:
502 err_real_reset:
503 	return ret;
504 }
505 
506 /* Configure MAC address */
507 static void vt_conf_addr(vt_driver *pdev, ether_addr_t *addr) {
508 	u8_t pa[6];
509 	u32_t base = pdev->base_addr;
510 
511 	/* Get MAC address */
512 	/* ### GET_MAC_ADDR ### */
513 	vt_get_addr(base, pa);
514 	addr->ea_addr[0] = pa[0];
515 	addr->ea_addr[1] = pa[1];
516 	addr->ea_addr[2] = pa[2];
517 	addr->ea_addr[3] = pa[3];
518 	addr->ea_addr[4] = pa[4];
519 	addr->ea_addr[5] = pa[5];
520 #ifdef MY_DEBUG
521 	printf("vt6105: Ethernet address is %02x:%02x:%02x:%02x:%02x:%02x\n",
522 			addr->ea_addr[0], addr->ea_addr[1], addr->ea_addr[2],
523 			addr->ea_addr[3], addr->ea_addr[4], addr->ea_addr[5]);
524 #endif
525 }
526 
527 /* Stop the driver */
528 static void vt_stop(void) {
529 	u32_t base = g_driver.base_addr;
530 
531 	/* Free Rx and Tx buffer*/
532 	free_contig(g_driver.buf, g_driver.buf_size);
533 
534 	/* Stop interrupt */
535 	/* ### DISABLE_INTR ### */
536 	vt_out16(base, REG_IMR, INTR_IMR_DISABLE);
537 
538 	/* Stop Rx/Tx */
539 	/* ### STOP_RX_TX ### */
540 	vt_stop_rx_tx(base);
541 }
542 
543 /* Set driver mode */
544 static void vt_mode(unsigned int mode) {
545 	vt_driver *pdev = &g_driver;
546 	u32_t base = pdev->base_addr;
547 	u8_t rcr;
548 
549 	pdev->mode = mode;
550 
551 	/* ### READ_RCR ### */
552 	rcr = vt_in8(base, REG_RCR);
553 	rcr &= ~(RCR_UNICAST | RCR_MULTICAST | RCR_BROADCAST);
554 	if (pdev->mode & NDEV_PROMISC)
555 		rcr |= RCR_UNICAST | RCR_MULTICAST;
556 	if (pdev->mode & NDEV_BROAD)
557 		rcr |= RCR_BROADCAST;
558 	if (pdev->mode & NDEV_MULTI)
559 		rcr |= RCR_MULTICAST;
560 	rcr |= RCR_UNICAST;
561 	/* ### WRITE_RCR ### */
562 	vt_out8(base, REG_RCR, rcr);
563 }
564 
565 /* Receive data */
566 static ssize_t vt_recv(struct netdriver_data *data, size_t max) {
567 	vt_driver *pdev = &g_driver;
568 	u32_t totlen, packlen;
569 	vt_desc *desc;
570 	int index, i;
571 
572 	index = pdev->rx_head;
573 	desc = pdev->rx_desc;
574 	desc += index;
575 
576 	/* Check whether the receiving is OK */
577 	/* ### CHECK_RX_STATUS_OK ### */
578 	if (vt_rx_status_ok(desc) != TRUE)
579 		return SUSPEND;
580 
581 	/* Check Rx status error */
582 	/* ### CHECK_RX_STATUS_ERROR ### */
583 	if (desc->status & DESC_STATUS_RX_RECV_ERR)
584 		printf("vt6105: Rx error\n");
585 
586 	/* Get data length */
587 	/* ### Get Rx data length ### */
588 	totlen = vt_get_rx_len(desc);
589 	if (totlen < 8 || totlen > 2 * ETH_MAX_PACK_SIZE) {
590 		printf("vt6105: Bad data length: %d\n", totlen);
591 		panic(NULL);
592 	}
593 
594 	packlen = totlen;
595 	if (packlen > max)
596 		packlen = max;
597 
598 	/* Copy data to user */
599 	netdriver_copyout(data, 0, pdev->rx[index].buf, packlen);
600 	pdev->stat.ets_packetR++;
601 
602 	/* Set Rx descriptor status */
603 	/* ### SET_RX_STATUS_INTR ### */
604 	desc->status = DESC_STATUS_RX_RECV_CLEAR;
605 	if (index == RX_DESC_NUM - 1)
606 		index = 0;
607 	else
608 		index++;
609 	pdev->rx_head = index;
610 
611 #ifdef MY_DEBUG
612 	printf("vt6105: Successfully receive a packet, length = %d\n", packlen);
613 #endif
614 
615 	return packlen;
616 }
617 
618 /* Transmit data */
619 static int vt_send(struct netdriver_data *data, size_t size) {
620 	vt_driver *pdev = &g_driver;
621 	vt_desc *desc;
622 	int tx_head, i;
623 	u32_t base = pdev->base_addr;
624 
625 	tx_head = pdev->tx_head;
626 	desc = pdev->tx_desc;
627 	desc += tx_head;
628 
629 	if (pdev->tx[tx_head].busy)
630 		return SUSPEND;
631 
632 	/* Copy data from user */
633 	netdriver_copyin(data, 0, pdev->tx[tx_head].buf, size);
634 
635 	/* Set busy */
636 	pdev->tx[tx_head].busy = TRUE;
637 	pdev->tx_busy_num++;
638 
639 	/* Set Tx descriptor status */
640 	/* ### TX_DESC_START ### */
641 	vt_tx_desc_start(desc, size);
642 	if (tx_head == TX_DESC_NUM - 1)
643 		tx_head = 0;
644 	else
645 		tx_head++;
646 	pdev->tx_head = tx_head;
647 
648 	/* Wake up transmit channel */
649 	/* ### WAKE_UP_TX ### */
650 	vt_wakeup_tx(base);
651 
652 	return 0;
653 }
654 
655 /* Handle Interrupt */
656 static void vt_intr(unsigned int mask) {
657 	int s;
658 
659 	/* Run interrupt handler at driver level */
660 	vt_handler(&g_driver);
661 
662 	/* Reenable interrupts for this hook */
663 	if ((s = sys_irqenable(&g_driver.hook)) != OK)
664 		printf("vt6105: Cannot enable OS interrupts: %d\n", s);
665 
666 	/* Perform tasks based on the flagged conditions */
667 	vt_check_ints(&g_driver);
668 }
669 
670 /* Real handler interrupt */
671 static void vt_handler(vt_driver *pdev) {
672 	u32_t base = pdev->base_addr;
673 	u16_t intr_status;
674 	int flag = 0, tx_head, tx_tail;
675 	vt_desc *desc;
676 
677 	/* Get interrupt status */
678 	/* ### GET_INTR_STATUS ### */
679 	intr_status = vt_in16(base, REG_ISR);
680 
681 	/* Clear interrupt */
682 	/* ### CLEAR_INTR ### */
683 	vt_out16(base, REG_ISR, intr_status & INTR_ISR_CLEAR);
684 
685 	/* Enable interrupt */
686 	/* ### ENABLE_INTR ### */
687 	vt_out16(base, REG_IMR, INTR_IMR_ENABLE);
688 
689 	/* Check interrupt error */
690 	/* ### CHECK_INTR_ERROR ### */
691 	if (intr_status & INTR_ISR_ERR) {
692 		printf("vt6105: interrupt error\n");
693 		return;
694 	}
695 
696 	/* Check link status */
697 	/* ### CHECK_LINK_INTR ### */
698 	if (intr_status & INTR_ISR_LINK_EVENT) {
699 		pdev->link = vt_check_link(base);
700 #ifdef MY_DEBUG
701 		printf("vt6105: Link state change\n");
702 #endif
703 		flag++;
704 	}
705 
706 	/* Check Rx request status */
707 	/* ### CHECK_RX_INTR ### */
708 	if (intr_status & INTR_ISR_RX_DONE) {
709 		pdev->recv_flag = TRUE;
710 		flag++;
711 	}
712 
713 	/* Check Tx request status */
714 	/* ### CHECK_TX_INTR ### */
715 	if (intr_status & INTR_ISR_TX_DONE) {
716 		pdev->send_flag = TRUE;
717 		flag++;
718 
719 		/* Manage Tx Buffer */
720 		tx_head = pdev->tx_head;
721 		tx_tail = pdev->tx_tail;
722 		while (tx_tail != tx_head) {
723 			desc = pdev->tx_desc;
724 			desc += tx_tail;
725 			if (!pdev->tx[tx_tail].busy)
726 				printf("vt6105: Strange, buffer not busy?\n");
727 
728 			/* Check whether the transmiting is OK */
729 			/* ### CHECK_TX_STATUS_OK ### */
730 			if (vt_tx_status_ok(desc) != TRUE)
731 				break;
732 
733 			/* Check Tx status error */
734 			/* ### CHECK_TX_STATUS_ERROR ### */
735 			if (desc->status & DESC_STATUS_TX_SEND_ERR)
736 				printf("vt6105: Tx error\n");
737 
738 			pdev->stat.ets_packetT++;
739 			pdev->tx[tx_tail].busy = FALSE;
740 			pdev->tx_busy_num--;
741 
742 			if (++tx_tail >= TX_DESC_NUM)
743 				tx_tail = 0;
744 
745 			pdev->send_flag = TRUE;
746 			pdev->recv_flag = TRUE;
747 
748 			/* Set Tx descriptor status in interrupt */
749 			/* ### SET_TX_STATUS_INTR ### */
750 			desc->status = DESC_STATUS_TX_SEND_CLEAR;
751 
752 #ifdef MY_DEBUG
753 			printf("vt6105: Successfully send a packet\n");
754 #endif
755 		}
756 		pdev->tx_tail = tx_tail;
757 	}
758 #ifdef MY_DEBUG
759 	if (!flag) {
760 		printf("vt6105: Unknown error in interrupt\n");
761 		return;
762 	}
763 #endif
764 }
765 
766 /* Check interrupt and perform */
767 static void vt_check_ints(vt_driver *pdev) {
768 	if (!pdev->recv_flag)
769 		return;
770 	pdev->recv_flag = FALSE;
771 
772 	/* Handle data receive */
773 	netdriver_recv();
774 
775 	/* Handle data transmit */
776 	if (pdev->send_flag) {
777 		pdev->send_flag = FALSE;
778 		netdriver_send();
779 	}
780 }
781 
782 static void vt_stat(eth_stat_t *stat) {
783 	memcpy(stat, &g_driver.stat, sizeof(*stat));
784 }
785