pd6729.c

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

C
804
字号
		if (state->csc_mask & SS_STSCHG)			reg |= I365_CSC_STSCHG;	} else {		if (state->csc_mask & SS_BATDEAD)			reg |= I365_CSC_BVD1;		if (state->csc_mask & SS_BATWARN)			reg |= I365_CSC_BVD2;		if (state->csc_mask & SS_READY)			reg |= I365_CSC_READY;	}	if (irq_mode == 1)		reg |= 0x30;	/* management IRQ: PCI INTA# = "irq 3" */	indirect_write(socket, I365_CSCINT, reg);	reg = indirect_read(socket, I365_INTCTL);	if (irq_mode == 1)		reg |= 0x03;	/* card IRQ: PCI INTA# = "irq 3" */	else		reg |= socket->card_irq;	indirect_write(socket, I365_INTCTL, reg);	/* now clear the (probably bogus) pending stuff by doing a dummy read */	(void)indirect_read(socket, I365_CSC);	return 0;}static int pd6729_set_io_map(struct pcmcia_socket *sock,			     struct pccard_io_map *io){	struct pd6729_socket *socket			= container_of(sock, struct pd6729_socket, socket);	unsigned char map, ioctl;	map = io->map;	/* Check error conditions */	if (map > 1) {		dprintk("pd6729_set_io_map with invalid map");		return -EINVAL;	}	/* Turn off the window before changing anything */	if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_IO(map))		indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_IO(map));	/* dprintk("set_io_map: Setting range to %x - %x\n",	   io->start, io->stop);*/	/* write the new values */	indirect_write16(socket, I365_IO(map)+I365_W_START, io->start);	indirect_write16(socket, I365_IO(map)+I365_W_STOP, io->stop);	ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map);	if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);	if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);	if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);	indirect_write(socket, I365_IOCTL, ioctl);	/* Turn the window back on if needed */	if (io->flags & MAP_ACTIVE)		indirect_setbit(socket, I365_ADDRWIN, I365_ENA_IO(map));	return 0;}static int pd6729_set_mem_map(struct pcmcia_socket *sock,			      struct pccard_mem_map *mem){	struct pd6729_socket *socket			 = container_of(sock, struct pd6729_socket, socket);	unsigned short base, i;	unsigned char map;	map = mem->map;	if (map > 4) {		printk("pd6729_set_mem_map: invalid map");		return -EINVAL;	}	if ((mem->res->start > mem->res->end) || (mem->speed > 1000)) {		printk("pd6729_set_mem_map: invalid address / speed");		return -EINVAL;	}	/* Turn off the window before changing anything */	if (indirect_read(socket, I365_ADDRWIN) & I365_ENA_MEM(map))		indirect_resetbit(socket, I365_ADDRWIN, I365_ENA_MEM(map));	/* write the start address */	base = I365_MEM(map);	i = (mem->res->start >> 12) & 0x0fff;	if (mem->flags & MAP_16BIT)		i |= I365_MEM_16BIT;	if (mem->flags & MAP_0WS)		i |= I365_MEM_0WS;	indirect_write16(socket, base + I365_W_START, i);	/* write the stop address */	i= (mem->res->end >> 12) & 0x0fff;	switch (to_cycles(mem->speed)) {	case 0:		break;	case 1:		i |= I365_MEM_WS0;		break;	case 2:		i |= I365_MEM_WS1;		break;	default:		i |= I365_MEM_WS1 | I365_MEM_WS0;		break;	}	indirect_write16(socket, base + I365_W_STOP, i);	/* Take care of high byte */	indirect_write(socket, PD67_EXT_INDEX, PD67_MEM_PAGE(map));	indirect_write(socket, PD67_EXT_DATA, mem->res->start >> 24);	/* card start */	i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff;	if (mem->flags & MAP_WRPROT)		i |= I365_MEM_WRPROT;	if (mem->flags & MAP_ATTRIB) {		/* dprintk("requesting attribute memory for socket %i\n",			socket->number);*/		i |= I365_MEM_REG;	} else {		/* dprintk("requesting normal memory for socket %i\n",			socket->number);*/	}	indirect_write16(socket, base + I365_W_OFF, i);	/* Enable the window if necessary */	if (mem->flags & MAP_ACTIVE)		indirect_setbit(socket, I365_ADDRWIN, I365_ENA_MEM(map));	return 0;}static int pd6729_init(struct pcmcia_socket *sock){	int i;	struct resource res = { .end = 0x0fff };	pccard_io_map io = { 0, 0, 0, 0, 1 };	pccard_mem_map mem = { .res = &res, };	pd6729_set_socket(sock, &dead_socket);	for (i = 0; i < 2; i++) {		io.map = i;		pd6729_set_io_map(sock, &io);	}	for (i = 0; i < 5; i++) {		mem.map = i;		pd6729_set_mem_map(sock, &mem);	}	return 0;}/* the pccard structure and its functions */static struct pccard_operations pd6729_operations = {	.init 			= pd6729_init,	.get_status		= pd6729_get_status,	.set_socket		= pd6729_set_socket,	.set_io_map		= pd6729_set_io_map,	.set_mem_map		= pd6729_set_mem_map,};static irqreturn_t pd6729_test(int irq, void *dev){	dprintk("-> hit on irq %d\n", irq);	return IRQ_HANDLED;}static int pd6729_check_irq(int irq){	if (request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x", pd6729_test)		!= 0) return -1;	free_irq(irq, pd6729_test);	return 0;}static u_int __devinit pd6729_isa_scan(void){	u_int mask0, mask = 0;	int i;	if (irq_mode == 1) {		printk(KERN_INFO "pd6729: PCI card interrupts, "						"PCI status changes\n");		return 0;	}	if (irq_list_count == 0)		mask0 = 0xffff;	else		for (i = mask0 = 0; i < irq_list_count; i++)			mask0 |= (1<<irq_list[i]);	mask0 &= PD67_MASK;	/* just find interrupts that aren't in use */	for (i = 0; i < 16; i++)		if ((mask0 & (1 << i)) && (pd6729_check_irq(i) == 0))			mask |= (1 << i);	printk(KERN_INFO "pd6729: ISA irqs = ");	for (i = 0; i < 16; i++)		if (mask & (1<<i))			printk("%s%d", ((mask & ((1<<i)-1)) ? "," : ""), i);	if (mask == 0) printk("none!");	printk("  polling status changes.\n");	return mask;}static int __devinit pd6729_pci_probe(struct pci_dev *dev,				      const struct pci_device_id *id){	int i, j, ret;	u_int mask;	char configbyte;	struct pd6729_socket *socket;	socket = kzalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS,			 GFP_KERNEL);	if (!socket)		return -ENOMEM;	if ((ret = pci_enable_device(dev)))		goto err_out_free_mem;	printk(KERN_INFO "pd6729: Cirrus PD6729 PCI to PCMCIA Bridge "		"at 0x%llx on irq %d\n",		(unsigned long long)pci_resource_start(dev, 0), dev->irq); 	/*	 * Since we have no memory BARs some firmware may not	 * have had PCI_COMMAND_MEMORY enabled, yet the device needs it.	 */	pci_read_config_byte(dev, PCI_COMMAND, &configbyte);	if (!(configbyte & PCI_COMMAND_MEMORY)) {		printk(KERN_DEBUG "pd6729: Enabling PCI_COMMAND_MEMORY.\n");		configbyte |= PCI_COMMAND_MEMORY;		pci_write_config_byte(dev, PCI_COMMAND, configbyte);	}	ret = pci_request_regions(dev, "pd6729");	if (ret) {		printk(KERN_INFO "pd6729: pci request region failed.\n");		goto err_out_disable;	}	if (dev->irq == NO_IRQ)		irq_mode = 0;	/* fall back to ISA interrupt mode */	mask = pd6729_isa_scan();	if (irq_mode == 0 && mask == 0) {		printk(KERN_INFO "pd6729: no ISA interrupt is available.\n");		goto err_out_free_res;	}	for (i = 0; i < MAX_SOCKETS; i++) {		socket[i].io_base = pci_resource_start(dev, 0);		socket[i].socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD;		socket[i].socket.map_size = 0x1000;		socket[i].socket.irq_mask = mask;		socket[i].socket.pci_irq  = dev->irq;		socket[i].socket.owner = THIS_MODULE;		socket[i].number = i;		socket[i].socket.ops = &pd6729_operations;		socket[i].socket.resource_ops = &pccard_nonstatic_ops;		socket[i].socket.dev.parent = &dev->dev;		socket[i].socket.driver_data = &socket[i];	}	pci_set_drvdata(dev, socket);	if (irq_mode == 1) {		/* Register the interrupt handler */		if ((ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED,							"pd6729", socket))) {			printk(KERN_ERR "pd6729: Failed to register irq %d, "							"aborting\n", dev->irq);			goto err_out_free_res;		}	} else {		/* poll Card status change */		init_timer(&socket->poll_timer);		socket->poll_timer.function = pd6729_interrupt_wrapper;		socket->poll_timer.data = (unsigned long)socket;		socket->poll_timer.expires = jiffies + HZ;		add_timer(&socket->poll_timer);	}	for (i = 0; i < MAX_SOCKETS; i++) {		ret = pcmcia_register_socket(&socket[i].socket);		if (ret) {			printk(KERN_INFO "pd6729: pcmcia_register_socket "					       "failed.\n");			for (j = 0; j < i ; j++)				pcmcia_unregister_socket(&socket[j].socket);			goto err_out_free_res2;		}	}	return 0; err_out_free_res2:	if (irq_mode == 1)		free_irq(dev->irq, socket);	else		del_timer_sync(&socket->poll_timer); err_out_free_res:	pci_release_regions(dev); err_out_disable:	pci_disable_device(dev); err_out_free_mem:	kfree(socket);	return ret;}static void __devexit pd6729_pci_remove(struct pci_dev *dev){	int i;	struct pd6729_socket *socket = pci_get_drvdata(dev);	for (i = 0; i < MAX_SOCKETS; i++) {		/* Turn off all interrupt sources */		indirect_write(&socket[i], I365_CSCINT, 0);		indirect_write(&socket[i], I365_INTCTL, 0);		pcmcia_unregister_socket(&socket[i].socket);	}	if (irq_mode == 1)		free_irq(dev->irq, socket);	else		del_timer_sync(&socket->poll_timer);	pci_release_regions(dev);	pci_disable_device(dev);	kfree(socket);}#ifdef CONFIG_PMstatic int pd6729_socket_suspend(struct pci_dev *dev, pm_message_t state){	return pcmcia_socket_dev_suspend(&dev->dev, state);}static int pd6729_socket_resume(struct pci_dev *dev){	return pcmcia_socket_dev_resume(&dev->dev);}#endifstatic struct pci_device_id pd6729_pci_ids[] = {	{		.vendor		= PCI_VENDOR_ID_CIRRUS,		.device		= PCI_DEVICE_ID_CIRRUS_6729,		.subvendor	= PCI_ANY_ID,		.subdevice	= PCI_ANY_ID,	},	{ }};MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);static struct pci_driver pd6729_pci_drv = {	.name		= "pd6729",	.id_table	= pd6729_pci_ids,	.probe		= pd6729_pci_probe,	.remove		= __devexit_p(pd6729_pci_remove),#ifdef CONFIG_PM	.suspend	= pd6729_socket_suspend,	.resume		= pd6729_socket_resume,#endif};static int pd6729_module_init(void){	return pci_register_driver(&pd6729_pci_drv);}static void pd6729_module_exit(void){	pci_unregister_driver(&pd6729_pci_drv);}module_init(pd6729_module_init);module_exit(pd6729_module_exit);

⌨️ 快捷键说明

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