⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdladrv.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* 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 + -