📄 rtl_rtl8139_drv.c
字号:
u32 pio_start, pio_end, pio_flags, pio_len; unsigned long mmio_start, mmio_end, mmio_flags; unsigned int mmio_len; u8 tmp8; int rc=0, i, option, addr_len; static int board_idx=0; u32 tmp; void *ioaddr = NULL; char *print_name; print_name = dev ? dev->slot_name : "rtl8139"; pio_start = rt_pci_resource_start (dev, 0); pio_end = rt_pci_resource_end (dev, 0); pio_flags = rt_pci_resource_flags (dev, 0); pio_len = rt_pci_resource_len (dev, 0); mmio_start = rt_pci_resource_start (dev, 1); mmio_end = rt_pci_resource_end (dev, 1); mmio_flags = rt_pci_resource_flags (dev, 1); mmio_len = rt_pci_resource_len (dev, 1); rtl_8139_tp.mmio_len = mmio_len; /* set this immediately, we need to know before * we talk to the chip directly */ if (pio_len == RTL8139B_IO_SIZE) { rtl_8139_tp.chipset = CH_8139B; } /* make sure PCI base addr 0 is PIO */ if (!(pio_flags & IORESOURCE_IO)) { rtl_printf ("region #0 not a PIO resource, aborting\n"); } /* make sure PCI base addr 1 is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { rtl_printf ( "region #1 not an MMIO resource, aborting\n"); } /* check for weird/broken PCI region reporting */ if ((pio_len < RTL_MIN_IO_SIZE) || (mmio_len < RTL_MIN_IO_SIZE)) { rtl_printf ( "Invalid PCI region size(s), aborting\n"); } print_name = dev ? dev->slot_name : "rtl8139"; rc = pci_request_regions (dev, dev->name); if (rc) goto err_out; pci_set_master (dev); /* ioremap MMIO region */ ioaddr = ioremap (mmio_start, mmio_len); if (ioaddr == NULL) { rtl_printf ("cannot remap MMIO, aborting\n"); rc = -EIO; goto err_out; } /* Soft reset the chip. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset); /* Check that the chip has finished the reset. */ for (i = 1000; i > 0; i--) if ((RTL_R8 (ChipCmd) & CmdReset) == 0) break; else udelay (10); /* Bring the chip out of low-power mode. */ if (rtl_8139_tp.chipset == CH_8139B) { RTL_W8 (Config1, RTL_R8 (Config1) & ~(1<<4)); RTL_W8 (Config4, RTL_R8 (Config4) & ~(1<<2)); } else { /* handle RTL8139A and RTL8139 cases */ /* XXX from becker driver. is this right?? */ RTL_W8 (Config1, 0); } /* make sure chip thinks PIO and MMIO are enabled */ tmp8 = RTL_R8 (Config1); if ((tmp8 & Cfg1_PIO) == 0) { rtl_printf ("PIO not enabled, Cfg1=%02X, aborting\n", tmp8); rc = -EIO; goto err_out; } if ((tmp8 & Cfg1_MMIO) == 0) { rtl_printf ("MMIO not enabled, Cfg1=%02X, aborting\n", tmp8); rc = -EIO; goto err_out; } /* identify chip attached to board */ /* tmp = RTL_R8 (ChipVersion); */ tmp = RTL_R32 (TxConfig); tmp = ( (tmp&0x7c000000) + ( (tmp&0x00800000)<<2 ) )>>24; rtl_8139_tp.drv_flags = board_info[0].hw_flags; rtl_8139_tp.pci_dev = dev; rtl_8139_tp.mmio_addr = ioaddr; for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--) if (tmp == rtl_chip_info[i].version) { rtl_8139_tp.chipset = i; } if(rtl_8139_tp.chipset > (ARRAY_SIZE (rtl_chip_info) - 2)) rtl_8139_tp.chipset = ARRAY_SIZE (rtl_chip_info) - 2; /* Find the connected MII xcvrs. Doing this in open() would allow detecting external xcvrs later, but takes too much time. */ if (rtl_8139_tp.drv_flags & HAS_MII_XCVR) { int phy, phy_idx = 0; for (phy = 0; phy < 32 && phy_idx < sizeof(rtl_8139_tp.phys); phy++) { int mii_status = rt_rtl8139_mdio_read(dev, phy, 1); if (mii_status != 0xffff && mii_status != 0x0000) { rtl_8139_tp.phys[phy_idx++] = phy; rtl_8139_tp.advertising = rt_rtl8139_mdio_read(dev, phy, 4); rtl_printf( "%s: MII transceiver %d status 0x%4.4x " "advertising %4.4x.\n", dev->name, phy, mii_status, rtl_8139_tp.advertising); } } if (phy_idx == 0) { rtl_printf( "%s: No MII transceivers found! Assuming SYM " "transceiver.\n", dev->name); rtl_8139_tp.phys[0] = 32; } } else rtl_8139_tp.phys[0] = 32; /* Put the chip into low-power mode. */ RTL_W8_F (Cfg9346, Cfg9346_Unlock); tmp = RTL_R8 (Config1) & Config1Clear; tmp |= (rtl_8139_tp.chipset == CH_8139B) ? 3 : 1; /* Enable PM/VPD */ RTL_W8_F (Config1, tmp); RTL_W8_F (HltClk, 'H'); /* 'R' would leave the clock running. */ /* The lower four bits are the media type. */ option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx]; rtl_8139_tp.AutoNegoAbility = option&0xF; if (option > 0) { rtl_8139_tp.full_duplex = (option & 0x210) ? 1 : 0; rtl_8139_tp.default_port = option & 0xFF; if (rtl_8139_tp.default_port) rtl_8139_tp.medialock = 1; } if (board_idx < MAX_UNITS && full_duplex[board_idx] > 0) rtl_8139_tp.full_duplex = full_duplex[board_idx]; if (rtl_8139_tp.full_duplex) { rtl_printf( "%s: Media type forced to Full Duplex.\n", dev->name); /* Changing the MII-advertised media because might prevent re-connection. */ rtl_8139_tp.duplex_lock = 1; } if (rtl_8139_tp.default_port) { rtl_printf( "%s: Forcing %dMbs %s-duplex operation.\n", dev->name, (option & 0x0C ? 100 : 10), (option & 0x0A ? "full" : "half")); rt_rtl8139_mdio_write(dev, rtl_8139_tp.phys[0], 0, ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ } addr_len = rt_rtl8139_read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) ((u16 *) (rtl_8139_tp.dev_addr))[i] = le16_to_cpu (rt_rtl8139_read_eeprom (ioaddr, i + 7, addr_len)); rtl_printf( "%s: %s at 0x%lx, " "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " "IRQ %d\n", dev->name, board_info[0].name, rtl_8139_tp.mmio_addr, rtl_8139_tp.dev_addr[0], rtl_8139_tp.dev_addr[1], rtl_8139_tp.dev_addr[2], rtl_8139_tp.dev_addr[3], rtl_8139_tp.dev_addr[4], rtl_8139_tp.dev_addr[5], dev->irq); dev_rtl8139_open(dev); return 0;err_out: rtl_printf ("EXIT, returning %d\n", rc); return rc;}static void rt_rtl8139_tx_clear (struct rtl8139_private rtl_8139_tp){ int i; rtl_8139_tp.cur_tx = 0; rtl_8139_tp.dirty_tx = 0; /* Dump the unsent Tx packets. */ for (i = 0; i < NUM_TX_DESC; i++) { struct ring_info *rp = &rtl_8139_tp.tx_info[i]; if (rp->mapping != 0) { pci_unmap_single (rtl_8139_tp.pci_dev, rp->mapping, rp->skb->len, PCI_DMA_TODEVICE); rp->mapping = 0; } if (rp->skb) { dev_kfree_skb (rp->skb); rp->skb = NULL; rtl_8139_tp.stats.tx_dropped++; } }}static int rt_rtl8139_close (struct pci_dev *dev){ void *ioaddr = rtl_8139_tp.mmio_addr; rtl_printf ("%s: Shutting down ethercard, status was 0x%4.4x.\n", dev->name, RTL_R16 (IntrStatus)); /* Stop the chip's Tx and Rx DMA processes. */ RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear)); /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); /* Update the error counts. */ rtl_8139_tp.stats.rx_missed_errors += RTL_R32 (RxMissed); RTL_W32 (RxMissed, 0); if(rtl_8139_tp.must_free_irq) { rtl_free_irq (dev->irq); rtl_8139_tp.must_free_irq = 0; } rt_rtl8139_tx_clear(rtl_8139_tp); pci_free_consistent(rtl_8139_tp.pci_dev, RX_BUF_TOT_LEN,rtl_8139_tp.rx_ring, rtl_8139_tp.rx_ring_dma); pci_free_consistent(rtl_8139_tp.pci_dev, TX_BUF_TOT_LEN,rtl_8139_tp.tx_bufs, rtl_8139_tp.tx_bufs_dma); rtl_8139_tp.rx_ring = NULL; rtl_8139_tp.tx_bufs = NULL; /* Green! Put the chip in low-power mode. */ RTL_W8 (Cfg9346, Cfg9346_Unlock); RTL_W8 (Config1, 0x03); RTL_W8 (HltClk, 'H'); /* 'R' would leave the clock running. */ return 0;}static void rt_rtl8139_remove_one (struct pci_dev *pdev){ long io_addr; io_addr = (long)rtl_8139_tp.mmio_addr; iounmap (rtl_8139_tp.mmio_addr); pci_release_regions (pdev); }/***************************************************************************************/static ssize_t rt_rtl8139_read(struct rtl_file *filp, char *buf, size_t count, loff_t* ppos){ sem_wait(&rtl8139_sem); return rt_rtl8139_policy.extract_frame_of_buffer(&rt_rtl8139_rx_buffer,buf); }/***************************************************************************************/static int rt_rtl8139_ioctl(struct rtl_file * filp, unsigned int request, unsigned long other){ switch(request) { case 1: /* set_ip_filter */ rt_rtl8139_set_ip_filter(other); break; case 2: /* obtain_mac_address */ rt_rtl8139_obtain_mac_address((unsigned char *)other); break; } return 0;}/***************************************************************************************/static int rt_rtl8139_release (struct rtl_file *filp){ rtl_irqstate_t state; rtl_no_interrupts(state); rtl_printf("rtl8139_close\n"); rt_rtl8139_close(rtl8139dev); rtl_printf("rtl8139_remove_one\n"); rt_rtl8139_remove_one (rtl8139dev); if(rt_rtl8139_opened == 0x01){ sem_destroy(&rtl8139_sem); rtl_printf("Deallocating rx_buffer\n"); rt_rtl8139_policy.dealloc_rx_buffer(&rt_rtl8139_rx_buffer); } rtl_printf("After deallocating rx_buffer\n"); rt_rtl8139_opened = 0x00; rtl_restore_interrupts(state); return 0;}/***************************************************************************************/static ssize_t rt_rtl8139_write(struct rtl_file *filp, const char *buf, size_t count, loff_t* ppos){ ssize_t tmp; rtl_irqstate_t state; rtl_no_interrupts(state); tmp=rt_rtl8139_send_packet(buf,count); rtl_restore_interrupts(state); return tmp; }/***************************************************************************************/static int rt_rtl8139_open (struct rtl_file *filp){ if(rt_rtl8139_opened == 0x00){ if((rtl8139dev = init_rtl8139_device())!=NULL){ sem_init(&rtl8139_sem, 0, 0); start_up_rtl8139_device(rtl8139dev); rt_rtl8139_opened = 0x01; rtl_printf("Successfully Opened\n"); return RTL8139_MAJOR; }else{ rtl_printf("ERROR: Couldn't initialize device\n"); return -1; } }else{ rtl_printf("Device is already opened\n"); return -1; }}/***************************************************************************************/struct pci_dev *init_rtl8139_device(void){ struct pci_dev *dev; /* First of all, we must get a pointer to the pci_dev structure */ if((dev = rt_pci_find_device(RTL8139_VENDOR_ID, RTL8139_DEVICE_ID, NULL))== NULL) return NULL; rt_rtl8139_policy.initialize_rx_buffer(&rt_rtl8139_rx_buffer); /* Let's enable the device */ if (rt_pci_enable_device(dev)){ rtl_printf("PCI ERROR: Can't enable device\n"); return NULL; } return dev;}/***************************************************************************************/int init_module(void){ printk("\n\n\nRT-Linux driver for the Ethernet Card rtl8139 being loaded\n\n\n"); if (rtl_register_rtldev (RTL8139_MAJOR, RTL8139_NAME, &rt_rtl8139_fops)) { printk ("RTLinux /dev/%s: unable to get RTLinux major %d\n", RTL8139_NAME, RTL8139_MAJOR); return -EIO; }else{ printk("Registered device /dev/%s major number %d\n",RTL8139_NAME, RTL8139_MAJOR); rt_rtl8139_registered = 0x01; return 0; }}/***************************************************************************************/void cleanup_module(void){ int inside = 1; rtl_irqstate_t state; if((rt_rtl8139_opened == 0x01) || rt_rtl8139_inside_the_interrupt_handler){ rt_rtl8139_trying_to_close = 1; /* Since inside the interrupt handler there's a call to the scheduler, there may */ /* be an execution of the interrupt handler that hasn't been completely executed. */ /* The card cannot be released in that case, so we must be sure that there is no */ /* interrupt handler execution pending. Otherwise, that may crash the system. */ while(inside){ rtl_no_interrupts(state); if(rt_rtl8139_inside_the_interrupt_handler){ rtl_restore_interrupts(state); usleep(10); }else{ rtl_hard_disable_irq(rtl_8139_tp.pci_dev->irq); rtl_restore_interrupts(state); inside = 0; } } } if(rt_rtl8139_registered == 0x01){ printk("Unregistering device /dev/%s\n",RTL8139_NAME); rtl_unregister_rtldev(RTL8139_MAJOR,RTL8139_NAME); } printk("\n\n\nRT-Linux driver for the Ethernet Card rtl8139 being removed\n\n\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -