vrc4171_card.c

来自「linux 内核源代码」· C语言 代码 · 共 757 行 · 第 1/2 页

C
757
字号
	unsigned int slot;	uint8_t ioctl, addrwin;	u_char map;	if (sock == NULL || sock->sock >= CARD_MAX_SLOTS ||	    io == NULL || io->map >= IO_MAX_MAPS ||	    io->start > 0xffff || io->stop > 0xffff || io->start > io->stop)		return -EINVAL;	slot = sock->sock;	map = io->map;	addrwin = exca_read_byte(slot, I365_ADDRWIN);	if (addrwin & I365_ENA_IO(map)) {		addrwin &= ~I365_ENA_IO(map);		exca_write_byte(slot, I365_ADDRWIN, addrwin);	}	exca_write_word(slot, I365_IO(map)+I365_W_START, io->start);	exca_write_word(slot, I365_IO(map)+I365_W_STOP, io->stop);	ioctl = 0;	if (io->speed > 0)		ioctl |= I365_IOCTL_WAIT(map);	if (io->flags & MAP_16BIT)		ioctl |= I365_IOCTL_16BIT(map);	if (io->flags & MAP_AUTOSZ)		ioctl |= I365_IOCTL_IOCS16(map);	if (io->flags & MAP_0WS)		ioctl |= I365_IOCTL_0WS(map);	exca_write_byte(slot, I365_IOCTL, ioctl);	if (io->flags & MAP_ACTIVE) {		addrwin |= I365_ENA_IO(map);		exca_write_byte(slot, I365_ADDRWIN, addrwin);	}	return 0;}static int pccard_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem){	unsigned int slot;	uint16_t start, stop, offset;	uint8_t addrwin;	u_char map;	if (sock == NULL || sock->sock >= CARD_MAX_SLOTS ||	    mem == NULL || mem->map >= MEM_MAX_MAPS ||	    mem->res->start < CARD_MEM_START || mem->res->start > CARD_MEM_END ||	    mem->res->end < CARD_MEM_START || mem->res->end > CARD_MEM_END ||	    mem->res->start > mem->res->end ||	    mem->card_start > CARD_MAX_MEM_OFFSET ||	    mem->speed > CARD_MAX_MEM_SPEED)		return -EINVAL;	slot = sock->sock;	map = mem->map;	addrwin = exca_read_byte(slot, I365_ADDRWIN);	if (addrwin & I365_ENA_MEM(map)) {		addrwin &= ~I365_ENA_MEM(map);		exca_write_byte(slot, I365_ADDRWIN, addrwin);	}	start = (mem->res->start >> 12) & 0x3fff;	if (mem->flags & MAP_16BIT)		start |= I365_MEM_16BIT;	exca_write_word(slot, I365_MEM(map)+I365_W_START, start);	stop = (mem->res->end >> 12) & 0x3fff;	switch (mem->speed) {	case 0:		break;	case 1:		stop |= I365_MEM_WS0;		break;	case 2:		stop |= I365_MEM_WS1;		break;	default:		stop |= I365_MEM_WS0 | I365_MEM_WS1;		break;	}	exca_write_word(slot, I365_MEM(map)+I365_W_STOP, stop);	offset = (mem->card_start >> 12) & 0x3fff;	if (mem->flags & MAP_ATTRIB)		offset |= I365_MEM_REG;	if (mem->flags & MAP_WRPROT)		offset |= I365_MEM_WRPROT;	exca_write_word(slot, I365_MEM(map)+I365_W_OFF, offset);	if (mem->flags & MAP_ACTIVE) {		addrwin |= I365_ENA_MEM(map);		exca_write_byte(slot, I365_ADDRWIN, addrwin);	}	return 0;}static struct pccard_operations vrc4171_pccard_operations = {	.init			= pccard_init,	.get_status		= pccard_get_status,	.set_socket		= pccard_set_socket,	.set_io_map		= pccard_set_io_map,	.set_mem_map		= pccard_set_mem_map,};static inline unsigned int get_events(int slot){	unsigned int events = 0;	uint8_t status, csc;	status = exca_read_byte(slot, I365_STATUS);	csc = exca_read_byte(slot, I365_CSC);	if (exca_read_byte(slot, I365_INTCTL) & I365_PC_IOCARD) {		if ((csc & I365_CSC_STSCHG) && (status & I365_CS_STSCHG))			events |= SS_STSCHG;	} else {		if (csc & (I365_CSC_BVD1 | I365_CSC_BVD2)) {			if (!(status & I365_CS_BVD1))				events |= SS_BATDEAD;			else if ((status & (I365_CS_BVD1 | I365_CS_BVD2)) == I365_CS_BVD1)				events |= SS_BATWARN;		}	}	if ((csc & I365_CSC_READY) && (status & I365_CS_READY))		events |= SS_READY;	if ((csc & I365_CSC_DETECT) && ((status & I365_CS_DETECT) == I365_CS_DETECT))		events |= SS_DETECT;	return events;}static irqreturn_t pccard_interrupt(int irq, void *dev_id){	vrc4171_socket_t *socket;	unsigned int events;	irqreturn_t retval = IRQ_NONE;	uint16_t status;	status = vrc4171_get_irq_status();	if (status & IRQ_A) {		socket = &vrc4171_sockets[CARD_SLOTA];		if (socket->slot == SLOT_INITIALIZED) {			if (status & (1 << socket->csc_irq)) {				events = get_events(CARD_SLOTA);				if (events != 0) {					pcmcia_parse_events(&socket->pcmcia_socket, events);					retval = IRQ_HANDLED;				}			}		}	}	if (status & IRQ_B) {		socket = &vrc4171_sockets[CARD_SLOTB];		if (socket->slot == SLOT_INITIALIZED) {			if (status & (1 << socket->csc_irq)) {				events = get_events(CARD_SLOTB);				if (events != 0) {					pcmcia_parse_events(&socket->pcmcia_socket, events);					retval = IRQ_HANDLED;				}			}		}	}	return retval;}static inline void reserve_using_irq(int slot){	unsigned int irq;	irq = exca_read_byte(slot, I365_INTCTL);	irq &= 0x0f;	vrc4171_irq_mask &= ~(1 << irq);	irq = exca_read_byte(slot, I365_CSCINT);	irq = (irq & 0xf0) >> 4;	vrc4171_irq_mask &= ~(1 << irq);}static int __devinit vrc4171_add_sockets(void){	vrc4171_socket_t *socket;	int slot, retval;	for (slot = 0; slot < CARD_MAX_SLOTS; slot++) {		if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE)			continue;		socket = &vrc4171_sockets[slot];		if (socket->slot != SLOT_PROBE) {			uint8_t addrwin;			switch (socket->slot) {			case SLOT_NOPROBE_MEM:				addrwin = exca_read_byte(slot, I365_ADDRWIN);				addrwin &= 0x1f;				exca_write_byte(slot, I365_ADDRWIN, addrwin);				break;			case SLOT_NOPROBE_IO:				addrwin = exca_read_byte(slot, I365_ADDRWIN);				addrwin &= 0xc0;				exca_write_byte(slot, I365_ADDRWIN, addrwin);				break;			default:				break;			}			reserve_using_irq(slot);			continue;		}		sprintf(socket->name, "NEC VRC4171 Card Slot %1c", 'A' + slot);		socket->pcmcia_socket.dev.parent = &vrc4171_card_device.dev;		socket->pcmcia_socket.ops = &vrc4171_pccard_operations;		socket->pcmcia_socket.owner = THIS_MODULE;		retval = pcmcia_register_socket(&socket->pcmcia_socket);		if (retval < 0)			return retval;		exca_write_byte(slot, I365_ADDRWIN, 0);		exca_write_byte(slot, GLOBAL_CONTROL, 0);		socket->slot = SLOT_INITIALIZED;	}	return 0;}static void vrc4171_remove_sockets(void){	vrc4171_socket_t *socket;	int slot;	for (slot = 0; slot < CARD_MAX_SLOTS; slot++) {		if (slot == CARD_SLOTB && vrc4171_slotb == SLOTB_IS_NONE)			continue;		socket = &vrc4171_sockets[slot];		if (socket->slot == SLOT_INITIALIZED)			pcmcia_unregister_socket(&socket->pcmcia_socket);		socket->slot = SLOT_PROBE;	}}static int __devinit vrc4171_card_setup(char *options){	if (options == NULL || *options == '\0')		return 1;	if (strncmp(options, "irq:", 4) == 0) {		int irq;		options += 4;		irq = simple_strtoul(options, &options, 0);		if (irq >= 0 && irq < NR_IRQS)			vrc4171_irq = irq;		if (*options != ',')			return 1;		options++;	}	if (strncmp(options, "slota:", 6) == 0) {		options += 6;		if (*options != '\0') {			if (strncmp(options, "memnoprobe", 10) == 0) {				vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_MEM;				options += 10;			} else if (strncmp(options, "ionoprobe", 9) == 0) {				vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_IO;				options += 9;			} else if ( strncmp(options, "noprobe", 7) == 0) {				vrc4171_sockets[CARD_SLOTA].slot = SLOT_NOPROBE_ALL;				options += 7;			}			if (*options != ',')				return 1;			options++;		} else			return 1;	}	if (strncmp(options, "slotb:", 6) == 0) {		options += 6;		if (*options != '\0') {			if (strncmp(options, "pccard", 6) == 0) {				vrc4171_slotb = SLOTB_IS_PCCARD;				options += 6;			} else if (strncmp(options, "cf", 2) == 0) {				vrc4171_slotb = SLOTB_IS_CF;				options += 2;			} else if (strncmp(options, "flashrom", 8) == 0) {				vrc4171_slotb = SLOTB_IS_FLASHROM;				options += 8;			} else if (strncmp(options, "none", 4) == 0) {				vrc4171_slotb = SLOTB_IS_NONE;				options += 4;			}			if (*options != ',')				return 1;			options++;			if (strncmp(options, "memnoprobe", 10) == 0)				vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_MEM;			if (strncmp(options, "ionoprobe", 9) == 0)				vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_IO;			if (strncmp(options, "noprobe", 7) == 0)				vrc4171_sockets[CARD_SLOTB].slot = SLOT_NOPROBE_ALL;		}	}	return 1;}__setup("vrc4171_card=", vrc4171_card_setup);static struct device_driver vrc4171_card_driver = {	.name		= vrc4171_card_name,	.bus		= &platform_bus_type,	.suspend	= pcmcia_socket_dev_suspend,	.resume		= pcmcia_socket_dev_resume,};static int __devinit vrc4171_card_init(void){	int retval;	retval = driver_register(&vrc4171_card_driver);	if (retval < 0)		return retval;	retval = platform_device_register(&vrc4171_card_device);	if (retval < 0) {		driver_unregister(&vrc4171_card_driver);		return retval;	}	vrc4171_set_multifunction_pin(vrc4171_slotb);	retval = vrc4171_add_sockets();	if (retval == 0)		retval = request_irq(vrc4171_irq, pccard_interrupt, IRQF_SHARED,		                     vrc4171_card_name, vrc4171_sockets);	if (retval < 0) {		vrc4171_remove_sockets();		platform_device_unregister(&vrc4171_card_device);		driver_unregister(&vrc4171_card_driver);		return retval;	}	printk(KERN_INFO "%s, connected to IRQ %d\n", vrc4171_card_driver.name, vrc4171_irq);	return 0;}static void __devexit vrc4171_card_exit(void){	free_irq(vrc4171_irq, vrc4171_sockets);	vrc4171_remove_sockets();	platform_device_unregister(&vrc4171_card_device);	driver_unregister(&vrc4171_card_driver);}module_init(vrc4171_card_init);module_exit(vrc4171_card_exit);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?