📄 plx9052-24.c
字号:
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 + -