📄 plx9052-26.c
字号:
}static int plx9052_suspend(struct pcmcia_socket *sock){ plx9052_set_socket(sock, &dead_socket); return 0;}static int plx9052_get_status(struct pcmcia_socket *sock, u_int *value){ struct plx9052_socket *socket = container_of(sock, struct plx9052_socket, socket); *value = 0; if (plx9052_card_present(socket)) *value |= SS_READY | SS_POWERON | SS_IOCARD | SS_DETECT; return 0;}static int plx9052_get_socket(struct pcmcia_socket *sock, socket_state_t *state){ struct plx9052_socket *socket = container_of(sock, struct plx9052_socket, socket); *state = socket->state; return 0;}static int plx9052_set_socket(struct pcmcia_socket *sock, socket_state_t *state){ u32 reg; struct plx9052_socket *socket = container_of(sock, struct plx9052_socket, socket); 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(struct pcmcia_socket *sock, struct pccard_io_map *io){ struct plx9052_socket *socket = container_of(sock, struct plx9052_socket, socket); 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(struct pcmcia_socket *sock, struct pccard_mem_map *mem){ struct plx9052_socket *socket = container_of(sock, struct plx9052_socket, socket); 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 irqreturn_t plx9052_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct plx9052_socket *socket = (struct plx9052_socket *) dev_id; if (!plx9052_irq_active(socket)) return IRQ_NONE; if (!(socket->state.csc_mask & SS_DETECT)) return IRQ_HANDLED; if (!plx9052_card_present(socket)) { socket->event |= SS_DETECT; plx9052_disable_irq(socket); schedule_work(&socket->event_work); } return IRQ_HANDLED;}static struct pccard_operations plx9052_operations = { .init = plx9052_init, .suspend = plx9052_suspend, .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,};static int plx9052_probe(struct pci_dev *pdev, const struct pci_device_id *ent){ int err = 0; struct plx9052_socket *socket = NULL; socket = kmalloc(sizeof(struct plx9052_socket), GFP_KERNEL); if (!socket) return -ENOMEM; memset(socket, 0, sizeof(struct plx9052_socket)); socket->pdev = pdev; pci_set_drvdata(pdev, socket); spin_lock_init(&socket->event_lock); INIT_WORK(&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; } socket->socket.ops = &plx9052_operations; socket->socket.dev.dev = &pdev->dev; socket->socket.driver_data = socket; socket->socket.owner = THIS_MODULE; socket->socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_PAGE_REGS; socket->socket.map_size = PLX_MEMWIN_MIN; /* minimum window size */ socket->socket.pci_irq = pdev->irq; pcmcia_register_socket(&socket->socket); printk(KERN_INFO "plx9052: socket enabled, IRQ %d\n", socket->pdev->irq); return 0; /* succeeded */ fail: plx9052_close(pdev); return err;}static void plx9052_close(struct pci_dev *pdev){ struct plx9052_socket *socket = pci_get_drvdata(pdev); pcmcia_unregister_socket(&socket->socket); if (pdev->irq) free_irq(pdev->irq, socket); 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); socket->pdev = NULL; pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); kfree(socket);}/* 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 int plx9052_socket_suspend(struct pci_dev *pdev, u32 state){ return pcmcia_socket_dev_suspend(&pdev->dev, state);}static int plx9052_socket_resume(struct pci_dev *pdev){ return pcmcia_socket_dev_resume(&pdev->dev);}static struct pci_driver plx9052_driver = { .name = DEVICE_NAME, .id_table = plx9052_pci_id_table, .probe = plx9052_probe, .remove = plx9052_close, .suspend = plx9052_socket_suspend, .resume = plx9052_socket_resume,};static int __init init_plx9052(void){ pci_module_init(&plx9052_driver); return 0;}extern void __exit exit_plx9052(void){ pci_unregister_driver(&plx9052_driver);}module_init(init_plx9052);module_exit(exit_plx9052);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -