📄 defxx.c
字号:
* will be initialized and a global flag will be set to indicate that * dfx_probe() has already been called. * * However...the OS doesn't know that we've already initialized * devices fddi1 and fddi2 so dfx_probe() gets called again and again * until it reaches the end of the device list for FDDI (presently, * fddi7). It's important that the driver "pretend" to probe for * devices fddi1 and fddi2 and return success. Devices fddi3 * through fddi7 will return failure since they weren't initialized. * * This algorithm seems to work for the time being. As other FDDI * drivers are written for Linux, a more generic approach (perhaps * similar to the Ethernet card approach) may need to be implemented. * * Return Codes: * 0 - This device (fddi0, fddi1, etc) configured successfully * -ENODEV - No devices present, or no Digital FDDI EISA or PCI device * present for this device name * * Assumptions: * For the time being, DEFXX.C is the only FDDI driver under Linux. * As this assumption changes, this routine will likely be impacted. * Also, it is assumed that no more than eight (8) FDDI controllers * will be configured in the system (fddi0 through fddi7). This * routine will not allocate new device structures. If more than * eight FDDI controllers need to be configured, drivers/net/Space.c * should be updated as well as the DFX_MAX_NUM_BOARDS constant in * DEFXX.H. * * Side Effects: * Device structures for FDDI adapters (fddi0, fddi1, etc) are * initialized and the board resources are read and stored in * the device structure. */__initfunc(int dfx_probe( struct device *dev )) { int i; /* used in for loops */ int version_disp; /* was version info string already displayed? */ int port_len; /* length of port address range (in bytes) */ u16 port; /* temporary I/O (port) address */ struct pci_dev * pdev = NULL; /* PCI device record */ u16 command; /* PCI Configuration space Command register val */ u32 slot_id; /* EISA hardware (slot) ID read from adapter */ DFX_board_t *bp; /* board pointer */ DBG_printk("In dfx_probe...\n"); /* * Verify whether we're going through dfx_probe() again * * If so, see if we're going through for a subsequent fddi device that * we've already initialized. If we are, return success (0). If not, * return failure (-ENODEV). */ version_disp = 0; /* default to version string not displayed */ if (already_probed) { DBG_printk("Already entered dfx_probe\n"); if (dev != NULL) if ((strncmp(dev->name, "fddi", 4) == 0) && (dev->base_addr != 0)) { DBG_printk("In dfx_probe for fddi adapter (%s) we've already initialized it, so return success\n", dev->name); return(0); } return(-ENODEV); } already_probed = 1; /* set global flag */ /* Scan for FDDI EISA controllers */ for (i=0; i < DFX_MAX_EISA_SLOTS; i++) /* only scan for up to 16 EISA slots */ { port = (i << 12) + PI_ESIC_K_SLOT_ID; /* port = I/O address for reading slot ID */ slot_id = inl(port); /* read EISA HW (slot) ID */ if ((slot_id & 0xF0FFFFFF) == DEFEA_PRODUCT_ID) { if (!version_disp) /* display version info if adapter is found */ { version_disp = 1; /* set display flag to TRUE so that */ printk(version); /* we only display this string ONCE */ } port = (i << 12); /* recalc base addr */ /* Verify port address range is not already being used */ port_len = PI_ESIC_K_CSR_IO_LEN; if (check_region(port, port_len) == 0) { /* Allocate a new device structure for this adapter */ dev = dfx_alloc_device(dev, port); if (dev != NULL) { /* Initialize board structure with bus-specific info */ bp = (DFX_board_t *) dev->priv; bp->dev = dev; bp->bus_type = DFX_BUS_TYPE_EISA; if (dfx_driver_init(dev) == DFX_K_SUCCESS) num_boards++; /* only increment global board count on success */ else dev->base_addr = 0; /* clear port address field in device structure on failure */ } } else printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1)); } } /* Scan for FDDI PCI controllers */ if (pci_present()) /* is PCI even present? */ while ((pdev = pci_find_device(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, pdev))) { if (!version_disp) /* display version info if adapter is found */ { version_disp = 1; /* set display flag to TRUE so that */ printk(version); /* we only display this string ONCE */ } /* Verify that I/O enable bit is set (PCI slot is enabled) */ pci_read_config_word(pdev, PCI_COMMAND, &command); if ((command & PCI_COMMAND_IO) == 0) printk("I/O enable bit not set! Verify that slot is enabled\n"); else { /* Turn off memory mapped space and enable mastering */ command |= PCI_COMMAND_MASTER; command &= ~PCI_COMMAND_MEMORY; pci_write_config_word(pdev, PCI_COMMAND, command); /* Get I/O base address from PCI Configuration Space */ port = pdev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK; /* Verify port address range is not already being used */ port_len = PFI_K_CSR_IO_LEN; if (check_region(port, port_len) == 0) { /* Allocate a new device structure for this adapter */ dev = dfx_alloc_device(dev, port); if (dev != NULL) { /* Initialize board structure with bus-specific info */ bp = (DFX_board_t *) dev->priv; bp->dev = dev; bp->bus_type = DFX_BUS_TYPE_PCI; bp->pci_dev = pdev; if (dfx_driver_init(dev) == DFX_K_SUCCESS) num_boards++; /* only increment global board count on success */ else dev->base_addr = 0; /* clear port address field in device structure on failure */ } } else printk("I/O range allocated to adapter (0x%X-0x%X) is already being used!\n", port, (port + port_len-1)); } } /* * If we're at this point we're going through dfx_probe() for the first * time. Return success (0) if we've initialized 1 or more boards. * Otherwise, return failure (-ENODEV). */ if (num_boards > 0) return(0); else return(-ENODEV); }/* * ==================== * = dfx_alloc_device = * ==================== * * Overview: * Allocate new device structure for adapter * * Returns: * Pointer to device structure for this adapter or NULL if * none are available or could not allocate memory for * private board structure. * * Arguments: * dev - pointer to device information for last device * iobase - base I/O address of new adapter * * Functional Description: * The algorithm for allocating a new device structure is * fairly simple. Since we're presently the only FDDI driver * under Linux, we'll find the first device structure with an * "fddi*" device name that's free. If we run out of devices, * we'll fail on error. This is simpler than trying to * allocate the memory for a new device structure, determine * the next free number (beyond 7) and link it into the chain * of devices. A user can always modify drivers/net/Space.c * to add new FDDI device structures if necessary. * * Beyond finding a free FDDI device structure, this routine * initializes most of the fields, resource tags, and dispatch * pointers in the device structure and calls the common * fddi_setup() routine to perform the rest of the device * structure initialization. * * Return Codes: * None * * Assumptions: * If additional FDDI drivers are integrated into Linux, * we'll likely need to use a different approach to * allocate a device structure. Perhaps one that is * similar to what the Ethernet drivers use. * * Side Effects: * None */__initfunc(struct device *dfx_alloc_device( struct device *dev, u16 iobase )) { struct device *tmp_dev; /* pointer to a device structure */ DBG_printk("In dfx_alloc_device...\n"); /* Find next free fddi entry */ for (tmp_dev = dev; tmp_dev != NULL; tmp_dev = tmp_dev->next) if ((strncmp(tmp_dev->name, "fddi", 4) == 0) && (tmp_dev->base_addr == 0)) break; if (tmp_dev == NULL) { printk("Could not find free FDDI device structure for this adapter!\n"); return(NULL); } DBG_printk("Device entry free, device name = %s\n", tmp_dev->name); /* Allocate space for private board structure */ tmp_dev->priv = (void *) kmalloc(sizeof(DFX_board_t), GFP_KERNEL); if (tmp_dev->priv == NULL) { printk("Could not allocate memory for private board structure!\n"); return(NULL); } memset(tmp_dev->priv, 0, sizeof(DFX_board_t)); /* clear structure */ /* Initialize new device structure */ tmp_dev->rmem_end = 0; /* shared memory isn't used */ tmp_dev->rmem_start = 0; /* shared memory isn't used */ tmp_dev->mem_end = 0; /* shared memory isn't used */ tmp_dev->mem_start = 0; /* shared memory isn't used */ tmp_dev->base_addr = iobase; /* save port (I/O) base address */ tmp_dev->irq = 0; /* set in dfx_bus_init() */ tmp_dev->if_port = 0; /* not applicable to FDDI adapters */ tmp_dev->dma = 0; /* Bus Master DMA doesn't require channel */ tmp_dev->get_stats = &dfx_ctl_get_stats; tmp_dev->open = &dfx_open; tmp_dev->stop = &dfx_close; tmp_dev->hard_start_xmit = &dfx_xmt_queue_pkt; tmp_dev->hard_header = NULL; /* set in fddi_setup() */ tmp_dev->rebuild_header = NULL; /* set in fddi_setup() */ tmp_dev->set_multicast_list = &dfx_ctl_set_multicast_list; tmp_dev->set_mac_address = &dfx_ctl_set_mac_address; tmp_dev->do_ioctl = NULL; /* not supported for now &&& */ tmp_dev->set_config = NULL; /* not supported for now &&& */ tmp_dev->hard_header_cache = NULL; /* not supported */ tmp_dev->header_cache_update = NULL; /* not supported */ tmp_dev->change_mtu = NULL; /* set in fddi_setup() */ /* Initialize remaining device structure information */ fddi_setup(tmp_dev); return(tmp_dev); }/* * ================ * = dfx_bus_init = * ================ * * Overview: * Initializes EISA and PCI controller bus-specific logic. * * Returns: * None * * Arguments: * dev - pointer to device information * * Functional Description: * Determine and save adapter IRQ in device table, * then perform bus-specific logic initialization. * * Return Codes: * None * * Assumptions: * dev->base_addr has already been set with the proper * base I/O address for this device. * * Side Effects: * Interrupts are enabled at the adapter bus-specific logic. * Note: Interrupts at the DMA engine (PDQ chip) are not * enabled yet. */__initfunc(void dfx_bus_init( struct device *dev )) { DFX_board_t *bp = (DFX_board_t *)dev->priv; u8 val; /* used for I/O read/writes */ DBG_printk("In dfx_bus_init...\n"); /* * Initialize base I/O address field in bp structure * * Note: bp->base_addr is the same as dev->base_addr. * It's useful because often we'll need to read * or write registers where we already have the * bp pointer instead of the dev pointer. Having * the base address in the bp structure will * save a pointer dereference. * * IMPORTANT!! This field must be defined before * any of the dfx_port_* inline functions are * called. */ bp->base_addr = dev->base_addr; /* Initialize adapter based on bus type */ if (bp->bus_type == DFX_BUS_TYPE_EISA) { /* Get the interrupt level from the ESIC chip */ dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); switch ((val & PI_CONFIG_STAT_0_M_IRQ) >> PI_CONFIG_STAT_0_V_IRQ) { case PI_CONFIG_STAT_0_IRQ_K_9: dev->irq = 9; break; case PI_CONFIG_STAT_0_IRQ_K_10: dev->irq = 10; break; case PI_CONFIG_STAT_0_IRQ_K_11: dev->irq = 11; break; case PI_CONFIG_STAT_0_IRQ_K_15: dev->irq = 15; break; } /* Enable access to I/O on the board by writing 0x03 to Function Control Register */ dfx_port_write_byte(bp, PI_ESIC_K_FUNCTION_CNTRL, PI_ESIC_K_FUNCTION_CNTRL_IO_ENB); /* Set the I/O decode range of the board */ val = ((dev->base_addr >> 12) << PI_IO_CMP_V_SLOT); dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_0_1, val); dfx_port_write_byte(bp, PI_ESIC_K_IO_CMP_1_1, val); /* Enable access to rest of module (including PDQ and packet memory) */ dfx_port_write_byte(bp, PI_ESIC_K_SLOT_CNTRL, PI_SLOT_CNTRL_M_ENB); /* * Map PDQ registers into I/O space. This is done by clearing a bit * in Burst Holdoff register. */ dfx_port_read_byte(bp, PI_ESIC_K_BURST_HOLDOFF, &val); dfx_port_write_byte(bp, PI_ESIC_K_BURST_HOLDOFF, (val & ~PI_BURST_HOLDOFF_M_MEM_MAP)); /* Enable interrupts at EISA bus interface chip (ESIC) */ dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &val); dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, (val | PI_CONFIG_STAT_0_M_INT_ENB)); } else { struct pci_dev *pdev = bp->pci_dev; /* Get the interrupt level from the PCI Configuration Table */ dev->irq = pdev->irq;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -