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

📄 plx9052-24.c

📁 关于linux中pci驱动的一些代码,实现了一些功能
💻 C
📖 第 1 页 / 共 2 页
字号:
		MOD_INC_USE_COUNT;	}	return 0;}static int plx9052_suspend(unsigned int sock){	plx9052_set_socket(sock, &dead_socket);	return 0;}#endifstatic int plx9052_inquire_socket(unsigned int sock, socket_cap_t *cap){	socket_info_t *socket = &socket_table[sock];	memset(cap, 0, sizeof(socket_cap_t));	/* only 16-bit cards, size-aligned */	cap->features |=	    SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_PAGE_REGS;	cap->map_size = PLX_MEMWIN_MIN;	/* minimum window size */	cap->pci_irq = socket->pdev->irq;	return 0;}static int plx9052_get_status(unsigned int sock, u_int *value){	socket_info_t *socket = &socket_table[sock];	*value = 0;	if (plx9052_card_present(socket))		*value |= SS_READY | SS_POWERON | SS_IOCARD | SS_DETECT;	return 0;}static int plx9052_get_socket(unsigned int sock, socket_state_t *state){	*state = socket_table[sock].state;	return 0;}static int plx9052_set_socket(unsigned int sock, socket_state_t *state){	u32 reg;	socket_info_t *socket = &socket_table[sock];	if (state->flags & SS_RESET) {		plx9052_disable_irq(socket);		reg = plx9052_inl(socket, PLX_CNTRL);		reg |= PLX_CNTRL_RESET;		plx9052_outl(socket, PLX_CNTRL, reg);	} else {		reg = plx9052_inl(socket, PLX_CNTRL);		reg &= ~PLX_CNTRL_RESET;		plx9052_outl(socket, PLX_CNTRL, reg);		plx9052_enable_irq(socket);	}	socket->state = *state;	return 0;}static int plx9052_set_io_map(unsigned int sock, struct pccard_io_map *io){	socket_info_t *socket = &socket_table[sock];	unsigned int len;	/* requested length */	unsigned int len2;	/* length adjusted to power of two */	unsigned int start2;	/* start adjusted to power of two */	unsigned int split;	/* split point for unaligned windows */	unsigned int tmp;	int err;	/* Disable mapping before changing it */	plx9052_disable_areas(socket, 1, io->map);	if (!(io->flags & MAP_ACTIVE))		return 0;	len = io->stop + 1 - io->start;	if (len > PLX_IOWIN_MAX) {		printk(KERN_ERR		       "Requested I/O area 0x%x-0x%x is too long\n",		       io->start, io->stop);		return -EINVAL;	}	/* Simplest case - size aligned window */	if (!plx9052_align_check(io->start, len)) {		err =		    plx9052_program_area(socket, 1, io->map, io->start,					 len, 0, io->flags);		return err;	}	/* Find the highest address line that needs to be opened */	tmp = io->stop ^ io->start;	for (len2 = PLX_IOWIN_MIN; len2 <= PLX_IOWIN_MAX; len2 <<= 1) {		if (len2 > tmp)			break;	}	/* Split the requested window into at most two size-aligned windows */	start2 = ~(len2 - 1) & io->start;	split = start2 + (len2 >> 1);	if (plx9052_align_check(io->start, split - io->start) ||	    plx9052_align_check(split, io->stop + 1 - split)) {		printk(KERN_ERR		       "I/O area 0x%x-0x%x is too badly unaligned\n",		       io->start, io->stop);		return -ENOTSUPP;	}	err = plx9052_program_area(socket, 1, io->map, io->start,				   split - io->start, 0, io->flags);	if (err)		return err;	err = plx9052_program_area(socket, 1, io->map, split,				   io->stop + 1 - split, 0, io->flags);	return err;}static int plx9052_set_mem_map(unsigned int sock,			       struct pccard_mem_map *mem){	socket_info_t *socket = &socket_table[sock];	unsigned long len;	/* requested length */	int err;	/* Disable mapping before changing it */	plx9052_disable_areas(socket, 0, mem->map);	if (!(mem->flags & MAP_ACTIVE))		return 0;	/* Memory allocation in the first megabyte is problematic on	 * some machines with Intel chipset.  */	if (mem->sys_start < 0x100000)		return -EINVAL;	len = mem->sys_stop + 1 - mem->sys_start;	if (len > PLX_MEMWIN_MAX) {		printk(KERN_ERR "Memory map 0x%lx-0x%lx is too long\n",		       mem->sys_start, mem->sys_stop);		return -EINVAL;	}	if (plx9052_align_check(mem->sys_start, len)) {		printk(KERN_ERR		       "Memory map 0x%lx-0x%lx is not size-aligned\n",		       mem->sys_start, mem->sys_stop);		return -EINVAL;	}	err =	    plx9052_program_area(socket, 0, mem->map, mem->sys_start, len,				 mem->card_start | PLX_CIS_START,				 mem->flags);	return err;}static void plx9052_proc_setup(unsigned int sock,			       struct proc_dir_entry *base){	return;}static void plx9052_interrupt(int irq, void *dev_id, struct pt_regs *regs){	socket_info_t *socket = (socket_info_t *) dev_id;	if (!plx9052_irq_active(socket))		return;	if (!(socket->state.csc_mask & SS_DETECT))		return;	if (!plx9052_card_present(socket)) {		socket->event |= SS_DETECT;		plx9052_disable_irq(socket);		schedule_task(&socket->event_work);	}	return;}#ifdef __IN_PCMCIA_PACKAGE__typedef int (*subfn_t) (unsigned int, void *);static subfn_t service_table[] = {	(subfn_t) & plx9052_register_callback,	(subfn_t) & plx9052_inquire_socket,	(subfn_t) & plx9052_get_status,	(subfn_t) & plx9052_get_socket,	(subfn_t) & plx9052_set_socket,	NULL,	(subfn_t) & plx9052_set_io_map,	NULL,	(subfn_t) & plx9052_set_mem_map,};#define NFUNC (sizeof(service_table)/sizeof(subfn_t))static int plx9052_operations(u_int lsock, u_int cmd, void *arg){	subfn_t func;	if (cmd >= sizeof(service_table) / sizeof(subfn_t))		return -EINVAL;	func = service_table[cmd];	if (!func)		return -EINVAL;	return func(lsock, arg);}#elsestatic struct pccard_operations plx9052_operations = {	.init = plx9052_init,	.suspend = plx9052_suspend,	.register_callback = plx9052_register_callback,	.inquire_socket = plx9052_inquire_socket,	.get_status = plx9052_get_status,	.get_socket = plx9052_get_socket,	.set_socket = plx9052_set_socket,	.set_io_map = plx9052_set_io_map,	.set_mem_map = plx9052_set_mem_map,	.proc_setup = plx9052_proc_setup,};#endifstatic int plx9052_probe(struct pci_dev *pdev,			 const struct pci_device_id *ent){	int err = 0;	socket_info_t *socket = NULL;	if (socket_count >= PCMCIA_SOCKETS_NO) {		printk(KERN_ERR		       "plx9052: at most %d sockets are supported\n",		       PCMCIA_SOCKETS_NO);		return -ENODEV;	}	socket = &socket_table[socket_count];	socket_count++;	memset(socket, 0, sizeof(socket_info_t));	socket->pdev = pdev;	pci_set_drvdata(pdev, socket);	spin_lock_init(&socket->event_lock);	INIT_TQUEUE(&socket->event_work, (void (*)(void *)) plx9052_event,		    socket);	err = pci_enable_device(pdev);	if (err)		return -EIO;	/* Resource 1 is control registers of PLX9052 */	socket->plxctl_addr = pci_resource_start(pdev, 1);	socket->plxctl_len = pci_resource_len(pdev, 1);	if (!request_region	    (socket->plxctl_addr, socket->plxctl_len, DEVICE_NAME)) {		printk(KERN_ERR "plx9052: I/O at 0x%x-0x%x busy\n",		       socket->plxctl_addr,		       socket->plxctl_addr + socket->plxctl_len - 1);		socket->plxctl_addr = 0;		err = -EBUSY;		goto fail;	}	/* Resource 2 is mapped to the PCMCIA memory space, starting with CIS */	socket->mem_phys = pci_resource_start(pdev, 2);	socket->mem_len = pci_resource_len(pdev, 2);	if (!request_mem_region	    (socket->mem_phys, socket->mem_len, DEVICE_NAME)) {		printk(KERN_ERR "plx9052: memory at 0x%lx-0x%lx busy\n",		       socket->mem_phys,		       socket->mem_phys + socket->mem_len - 1);		socket->mem_phys = 0;		err = -EBUSY;		goto fail;	}	socket->mem_virt = ioremap(socket->mem_phys, socket->mem_len);	if (!socket->mem_virt) {		printk(KERN_ERR		       "plx9052: cannot map memory at 0x%lx-0x%lx\n",		       socket->mem_phys,		       socket->mem_phys + socket->mem_len - 1);		err = -ENOMEM;		goto fail;	}	err =	    request_irq(pdev->irq, plx9052_interrupt, SA_SHIRQ,			DEVICE_NAME, socket);	if (err) {		printk(KERN_ERR "plx9052: cannot allocate IRQ %d.\n",		       pdev->irq);		err = -EBUSY;		goto fail;	}	printk(KERN_INFO "plx9052: Socket %d enabled, IRQ %d\n",	       socket_count, socket->pdev->irq);	return 0;		/* succeeded */      fail:	plx9052_close(pdev);	return err;}static void plx9052_close(struct pci_dev *pdev){	socket_info_t *socket = pci_get_drvdata(pdev);	if (pdev->irq)		free_irq(pdev->irq, socket);	pci_set_drvdata(pdev, NULL);	socket->pdev = NULL;	if (socket->plxctl_addr)		release_region(socket->plxctl_addr, socket->plxctl_len);	if (socket->mem_virt)		iounmap(socket->mem_virt);	if (socket->mem_phys)		release_mem_region(socket->mem_phys, socket->mem_len);	pci_disable_device(pdev);}/* PCI ID table, from orinoco_plx.c */static struct pci_device_id plx9052_pci_id_table[] __devinitdata = {	{0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,},	/* Siemens SpeedStream SS1023 */	{0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},	/* Netgear MA301 */	{0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},	/* Correga  - does this work? */	{0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},	/* SMC EZConnect SMC2602W,							   Eumitcom PCI WL11000,							   Addtron AWA-100 */	{0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},	/* Global Sun Tech GL24110P */	{0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,},	/* Reported working, but unknown */	{0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,},	/* Linksys WDT11 */	{0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,},	/* USR 2415 */	{0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,},	/* Belkin F5D6000 tested by							   Brendan W. McAdams <rit@jacked-in.org> */	{0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,},	/* 3Com AirConnect PCI tested by							   Damien Persohn <damien@persohn.net> */	{0,},};MODULE_DEVICE_TABLE(pci, plx9052_pci_id_table);static struct pci_driver plx9052_driver = {	.name = DEVICE_NAME,	.id_table = plx9052_pci_id_table,	.probe = plx9052_probe,	.remove = plx9052_close,};static int __init init_plx9052(void){	pci_module_init(&plx9052_driver);	if (register_ss_entry(socket_count, &plx9052_operations) != 0) {		printk(KERN_NOTICE		       "plx9052: Unable to register sockets\n");		return -ENODEV;	}	return 0;}extern void __exit exit_plx9052(void){	unregister_ss_entry(&plx9052_operations);	pci_unregister_driver(&plx9052_driver);}module_init(init_plx9052);module_exit(exit_plx9052);

⌨️ 快捷键说明

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