📄 sdladrv.c
字号:
/* Setup dual-port memory window */ _OUTB(port + 1, tmp); hw->regs[1] = tmp; /* Enable memory access */ tmp = hw->regs[0] | 0x04; if (hw->irq) { i = get_option_index(s508_irq_options, hw->irq); if (i) tmp |= s507_irqmask[i - 1]; } _OUTB(port, tmp); hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ return (_INB(port) & 0x08) ? 0 : -EIO;}/*============================================================================ * Initialize S508 adapter. */static int init_s508 (sdlahw_t* hw){ unsigned port = hw->port; int tmp, i; if (!detect_s508(port)) return -ENODEV; /* Verify configuration options */ i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) return -EINVAL; /* Setup memory configuration */ tmp = s508_hmcr[i - 1]; _OUTB(port + 1, tmp); hw->regs[1] = tmp; /* Enable memory access */ _OUTB(port, 0x04); hw->regs[0] = 0x04; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ return (_INB(port + 1) & 0x04) ? 0 : -EIO;}/*============================================================================ * Detect S502A adapter. * Following tests are used to detect S502A adapter: * 1. All registers other than status (BASE) should read 0xFF * 2. After writing 00001000b to control register, status register should * read 01000000b. * 3. After writing 0 to control register, status register should still * read 01000000b. * 4. After writing 00000100b to control register, status register should * read 01000100b. * Return 1 if detected o.k. or 0 if failed. * Note: This test is destructive! Adapter will be left in shutdown * state after the test. */static int detect_s502a (int port){ int i, j; if (!get_option_index(s502_port_options, port)) return 0; for (j = 1; j < SDLA_MAXIORANGE; ++j) { if (_INB(port + j) != 0xFF) return 0; for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ } _OUTB(port, 0x08); /* halt CPU */ _OUTB(port, 0x08); _OUTB(port, 0x08); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0x40) return 0; _OUTB(port, 0x00); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0x40) return 0; _OUTB(port, 0x04); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0x44) return 0; /* Reset adapter */ _OUTB(port, 0x08); _OUTB(port, 0x08); _OUTB(port, 0x08); _OUTB(port + 1, 0xFF); return 1;}/*============================================================================ * Detect S502E adapter. * Following tests are used to verify adapter presence: * 1. All registers other than status (BASE) should read 0xFF. * 2. After writing 0 to CPU control register (BASE+3), status register * (BASE) should read 11111000b. * 3. After writing 00000100b to port BASE (set bit 2), status register * (BASE) should read 11111100b. * Return 1 if detected o.k. or 0 if failed. * Note: This test is destructive! Adapter will be left in shutdown * state after the test. */static int detect_s502e (int port){ int i, j; if (!get_option_index(s502_port_options, port)) return 0; for (j = 1; j < SDLA_MAXIORANGE; ++j) { if (_INB(port + j) != 0xFF) return 0; for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ } _OUTB(port + 3, 0); /* CPU control reg. */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0xF8) /* read status */ return 0; _OUTB(port, 0x04); /* set bit 2 */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0xFC) /* verify */ return 0; /* Reset adapter */ _OUTB(port, 0); return 1;}/*============================================================================ * Detect s503 adapter. * Following tests are used to verify adapter presence: * 1. All registers other than status (BASE) should read 0xFF. * 2. After writing 0 to control register (BASE), status register (BASE) * should read 11110000b. * 3. After writing 00000100b (set bit 2) to control register (BASE), * status register should read 11110010b. * Return 1 if detected o.k. or 0 if failed. * Note: This test is destructive! Adapter will be left in shutdown * state after the test. */static int detect_s503 (int port){ int i, j; if (!get_option_index(s503_port_options, port)) return 0; for (j = 1; j < SDLA_MAXIORANGE; ++j) { if (_INB(port + j) != 0xFF) return 0; for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ } _OUTB(port, 0); /* reset control reg.*/ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0xF0) /* read status */ return 0; _OUTB(port, 0x04); /* set bit 2 */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0xF2) /* verify */ return 0; /* Reset adapter */ _OUTB(port, 0); return 1;}/*============================================================================ * Detect s507 adapter. * Following tests are used to detect s507 adapter: * 1. All ports should read the same value. * 2. After writing 0x00 to control register, status register should read * ?011000?b. * 3. After writing 0x01 to control register, status register should read * ?011001?b. * Return 1 if detected o.k. or 0 if failed. * Note: This test is destructive! Adapter will be left in shutdown * state after the test. */static int detect_s507 (int port){ int tmp, i, j; if (!get_option_index(s508_port_options, port)) return 0; tmp = _INB(port); for (j = 1; j < S507_IORANGE; ++j) { if (_INB(port + j) != tmp) return 0; for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ } _OUTB(port, 0x00); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if ((_INB(port) & 0x7E) != 0x30) return 0; _OUTB(port, 0x01); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if ((_INB(port) & 0x7E) != 0x32) return 0; /* Reset adapter */ _OUTB(port, 0x00); return 1;}/*============================================================================ * Detect s508 adapter. * Following tests are used to detect s508 adapter: * 1. After writing 0x00 to control register, status register should read * ??000000b. * 2. After writing 0x10 to control register, status register should read * ??010000b * Return 1 if detected o.k. or 0 if failed. * Note: This test is destructive! Adapter will be left in shutdown * state after the test. */static int detect_s508 (int port){ int i; if (!get_option_index(s508_port_options, port)) return 0; _OUTB(port, 0x00); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if ((_INB(port + 1) & 0x3F) != 0x00) return 0; _OUTB(port, 0x10); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if ((_INB(port + 1) & 0x3F) != 0x10) return 0; /* Reset adapter */ _OUTB(port, 0x00); return 1;}/*============================================================================ * Detect s514 PCI adapter. * Return 1 if detected o.k. or 0 if failed. * Note: This test is destructive! Adapter will be left in shutdown * state after the test. */static int detect_s514 (sdlahw_t* hw){ unsigned char CPU_no, slot_no; int number_S514_cards = 0; u32 S514_mem_base_addr = 0; u32 ut_u32; struct pci_dev *pci_dev;#ifdef CONFIG_PCI if(!pci_present()) { printk(KERN_ERR "%s: PCI BIOS not present!\n", modname); return 0; }#else printk(KERN_ERR "%s: Linux not compiled for PCI usage!\n", modname); return 0;#endif /* The 'setup()' procedure in 'sdlamain.c' passes the CPU number and the slot number defined in 'router.conf' via the 'port' definition. */ CPU_no = hw->S514_cpu_no[0]; slot_no = hw->S514_slot_no; printk(KERN_INFO "%s: detecting S514 card, CPU %c, slot #%d\n", modname, CPU_no, slot_no); /* check to see that CPU A or B has been selected in 'router.conf' */ switch(CPU_no) { case S514_CPU_A: case S514_CPU_B: break; default: printk(KERN_ERR "%s: S514 CPU definition invalid.\n", modname); printk(KERN_ERR "Must be 'A' or 'B'\n"); return 0; } number_S514_cards = find_s514_adapter(hw, 0); if(!number_S514_cards) return 0; /* we are using a single S514 adapter with a slot of 0 so re-read the */ /* location of this adapter */ if((number_S514_cards == 1) && !slot_no) { number_S514_cards = find_s514_adapter(hw, 1); if(!number_S514_cards) { printk(KERN_ERR "%s: Error finding PCI card\n", modname); return 0; } } pci_dev = hw->pci_dev; /* read the physical memory base address */ S514_mem_base_addr = (CPU_no == S514_CPU_A) ? (pci_dev->resource[1].start) : (pci_dev->resource[2].start); printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n", modname, S514_mem_base_addr); if(!S514_mem_base_addr) { if(CPU_no == S514_CPU_B) printk(KERN_ERR "%s: CPU #B not present on the card\n", modname); else printk(KERN_ERR "%s: No PCI memory allocated to card\n", modname); return 0; } /* enable the PCI memory */ pci_read_config_dword(pci_dev, (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, &ut_u32); pci_write_config_dword(pci_dev, (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, (ut_u32 | PCI_MEMORY_ENABLE)); /* check the IRQ allocated and enable IRQ usage */ if(!(hw->irq = pci_dev->irq)) { printk(KERN_ERR "%s: IRQ not allocated to S514 adapter\n", modname); return 0; } pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32); ut_u32 |= (CPU_no == S514_CPU_A) ? PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32); printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n", modname, hw->irq); /* map the physical PCI memory to virtual memory */ (void *)hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr, (unsigned long)MAX_SIZEOF_S514_MEMORY); /* map the physical control register memory to virtual memory */ (void *)hw->vector = ioremap( (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE), (unsigned long)16); if(!hw->dpmbase || !hw->vector) { printk(KERN_ERR "%s: PCI virtual memory allocation failed\n", modname); return 0; } /* halt the adapter */ writeb (S514_CPU_HALT, hw->vector); return 1;}/*============================================================================ * Find the S514 PCI adapter in the PCI bus. * Return the number of S514 adapters found (0 if no adapter found). */static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card){ unsigned char slot_no; int number_S514_cards = 0; char S514_found_in_slot = 0; u16 PCI_subsys_vendor; struct pci_dev *pci_dev = NULL; slot_no = hw->S514_slot_no; while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) != NULL) { if (pci_enable_device(pci_dev)) continue; PCI_subsys_vendor = pci_dev->subsystem_vendor; if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) continue; hw->pci_dev = pci_dev; if(find_first_S514_card) return(1); number_S514_cards ++; printk(KERN_INFO "%s: S514 card found, slot #%d (devfn 0x%X)\n", modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), pci_dev->devfn); if(slot_no && (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no)) { S514_found_in_slot = 1; break; } } /* if no S514 adapter has been found, then exit */ if(!number_S514_cards) { printk(KERN_ERR "%s: no S514 adapters found\n", modname); return 0; } /* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */ else if((number_S514_cards > 1) && !slot_no) { printk(KERN_ERR "%s: More than one S514 adapter found\n", modname); printk(KERN_ERR "Define a PCI slot number for this adapter\n"); return 0; } /* if the user has specified a slot number and the S514 adapter has */ /* not been found in that slot, then exit */ else if (slot_no && !S514_found_in_slot) { printk(KERN_ERR "%s: S514 card not found in specified slot #%d\n", modname, slot_no); return 0; } return (number_S514_cards);}/******* Miscellaneous ******************************************************//*============================================================================ * Calibrate SDLA memory access delay. * Count number of idle loops made within 1 second and then calculate the * number of loops that should be made to achive desired delay. */static int calibrate_delay (int mks){ unsigned int delay; unsigned long stop; for (delay = 0, stop = SYSTEM_TICK + HZ; SYSTEM_TICK < stop; ++delay); return (delay/(1000000L/mks) + 1);}/*============================================================================ * Get option's index into the options list. * Return option's index (1 .. N) or zero if option is invalid. */static int get_option_index (unsigned* optlist, unsigned optval){ int i; for (i = 1; i <= optlist[0]; ++i) if ( optlist[i] == optval) return i; return 0;}/*============================================================================ * Check memory region to see if it's available. * Return: 0 ok. */static unsigned check_memregion (void* ptr, unsigned len){ volatile unsigned char* p = ptr; for (; len && (readb (p) == 0xFF); --len, ++p) { writeb (0, p); /* attempt to write 0 */ if (readb(p) != 0xFF) { /* still has to read 0xFF */ writeb (0xFF, p);/* restore original value */ break; /* not good */ } } return len;}/*============================================================================ * Test memory region. * Return: size of the region that passed the test. * Note: Region size must be multiple of 2 ! */static unsigned test_memregion (void* ptr, unsigned len){ volatile unsigned short* w_ptr; unsigned len_w = len >> 1; /* region len in words */ unsigned i; for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) writew (0xAA55, w_ptr); for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) if (readw (w_ptr) != 0xAA55) { len_w = i; break; } for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) writew (0x55AA, w_ptr); for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) if (readw(w_ptr) != 0x55AA) { len_w = i; break; } for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) writew (0, w_ptr); return len_w << 1;}/*============================================================================ * Calculate 16-bit CRC using CCITT polynomial. */static unsigned short checksum (unsigned char* buf, unsigned len){ unsigned short crc = 0; unsigned mask, flag; for (; len; --len, ++buf) { for (mask = 0x80; mask; mask >>= 1) { flag = (crc & 0x8000); crc <<= 1; crc |= ((*buf & mask) ? 1 : 0); if (flag) crc ^= 0x1021; } } return crc;}/****** End *****************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -