📄 i82365.c
字号:
status = i365_get(sock, I365_STATUS); *value = ((status & I365_CS_DETECT) == I365_CS_DETECT) ? SS_DETECT : 0; if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) *value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG; else { *value |= (status & I365_CS_BVD1) ? 0 : SS_BATDEAD; *value |= (status & I365_CS_BVD2) ? 0 : SS_BATWARN; } *value |= (status & I365_CS_WRPROT) ? SS_WRPROT : 0; *value |= (status & I365_CS_READY) ? SS_READY : 0; *value |= (status & I365_CS_POWERON) ? SS_POWERON : 0; if (socket[sock].type == IS_VG469) { status = i365_get(sock, VG469_VSENSE); if (socket[sock].psock & 1) { *value |= (status & VG469_VSENSE_B_VS1) ? 0 : SS_3VCARD; *value |= (status & VG469_VSENSE_B_VS2) ? 0 : SS_XVCARD; } else { *value |= (status & VG469_VSENSE_A_VS1) ? 0 : SS_3VCARD; *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD; } } debug(1, "GetStatus(%d) = %#4.4x\n", sock, *value); return 0;} /* i365_get_status *//*====================================================================*/static int i365_set_socket(u_short sock, socket_state_t *state){ struct i82365_socket *t = &socket[sock]; u_char reg; debug(1, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags, state->Vcc, state->Vpp, state->io_irq, state->csc_mask); /* First set global controller options */ set_bridge_state(sock); /* IO card, RESET flag, IO interrupt */ reg = t->intr; reg |= state->io_irq; reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET; reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0; i365_set(sock, I365_INTCTL, reg); reg = I365_PWR_NORESET; if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO; if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT; if (t->flags & IS_CIRRUS) { if (state->Vpp != 0) { if (state->Vpp == 120) reg |= I365_VPP1_12V; else if (state->Vpp == state->Vcc) reg |= I365_VPP1_5V; else return -EINVAL; } if (state->Vcc != 0) { reg |= I365_VCC_5V; if (state->Vcc == 33) i365_bset(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); else if (state->Vcc == 50) i365_bclr(sock, PD67_MISC_CTL_1, PD67_MC1_VCC_3V); else return -EINVAL; } } else if (t->flags & IS_VG_PWR) { if (state->Vpp != 0) { if (state->Vpp == 120) reg |= I365_VPP1_12V; else if (state->Vpp == state->Vcc) reg |= I365_VPP1_5V; else return -EINVAL; } if (state->Vcc != 0) { reg |= I365_VCC_5V; if (state->Vcc == 33) i365_bset(sock, VG469_VSELECT, VG469_VSEL_VCC); else if (state->Vcc == 50) i365_bclr(sock, VG469_VSELECT, VG469_VSEL_VCC); else return -EINVAL; } } else if (t->flags & IS_DF_PWR) { switch (state->Vcc) { case 0: break; case 33: reg |= I365_VCC_3V; break; case 50: reg |= I365_VCC_5V; break; default: return -EINVAL; } switch (state->Vpp) { case 0: break; case 50: reg |= I365_VPP1_5V; break; case 120: reg |= I365_VPP1_12V; break; default: return -EINVAL; } } else { switch (state->Vcc) { case 0: break; case 50: reg |= I365_VCC_5V; break; default: return -EINVAL; } switch (state->Vpp) { case 0: break; case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break; case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break; default: return -EINVAL; } } if (reg != i365_get(sock, I365_POWER)) i365_set(sock, I365_POWER, reg); /* Chipset-specific functions */ if (t->flags & IS_CIRRUS) { /* Speaker control */ i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA, state->flags & SS_SPKR_ENA); } /* Card status change interrupt mask */ reg = t->cs_irq << 4; if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT; if (state->flags & SS_IOCARD) { 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; } i365_set(sock, I365_CSCINT, reg); i365_get(sock, I365_CSC); return 0;} /* i365_set_socket *//*====================================================================*/static int i365_set_io_map(u_short sock, struct pccard_io_map *io){ u_char map, ioctl; debug(1, "SetIOMap(%d, %d, %#2.2x, %d ns, " "%#lx-%#lx)\n", sock, io->map, io->flags, io->speed, io->start, io->stop); map = io->map; if ((map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) || (io->stop < io->start)) return -EINVAL; /* Turn off the window before changing anything */ if (i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(map)) i365_bclr(sock, I365_ADDRWIN, I365_ENA_IO(map)); i365_set_pair(sock, I365_IO(map)+I365_W_START, io->start); i365_set_pair(sock, I365_IO(map)+I365_W_STOP, io->stop); ioctl = i365_get(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map); if (io->speed) ioctl |= I365_IOCTL_WAIT(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); i365_set(sock, I365_IOCTL, ioctl); /* Turn on the window if necessary */ if (io->flags & MAP_ACTIVE) i365_bset(sock, I365_ADDRWIN, I365_ENA_IO(map)); return 0;} /* i365_set_io_map *//*====================================================================*/static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem){ u_short base, i; u_char map; debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, " "%#x)\n", sock, mem->map, mem->flags, mem->speed, (unsigned long long)mem->res->start, (unsigned long long)mem->res->end, mem->card_start); map = mem->map; if ((map > 4) || (mem->card_start > 0x3ffffff) || (mem->res->start > mem->res->end) || (mem->speed > 1000)) return -EINVAL; if ((mem->res->start > 0xffffff) || (mem->res->end > 0xffffff)) return -EINVAL; /* Turn off the window before changing anything */ if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map)) i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map)); 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; i365_set_pair(sock, base+I365_W_START, i); 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; } i365_set_pair(sock, base+I365_W_STOP, i); i = ((mem->card_start - mem->res->start) >> 12) & 0x3fff; if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT; if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG; i365_set_pair(sock, base+I365_W_OFF, i); /* Turn on the window if necessary */ if (mem->flags & MAP_ACTIVE) i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map)); return 0;} /* i365_set_mem_map */#if 0 /* driver model ordering issue *//*====================================================================== Routines for accessing socket information and register dumps via /sys/class/pcmcia_socket/... ======================================================================*/static ssize_t show_info(struct class_device *class_dev, char *buf){ struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev); return sprintf(buf, "type: %s\npsock: %d\n", pcic[s->type].name, s->psock);}static ssize_t show_exca(struct class_device *class_dev, char *buf){ struct i82365_socket *s = container_of(class_dev, struct i82365_socket, socket.dev); unsigned short sock; int i; ssize_t ret = 0; unsigned long flags = 0; sock = s->number; ISA_LOCK(sock, flags); for (i = 0; i < 0x40; i += 4) { ret += sprintf(buf, "%02x %02x %02x %02x%s", i365_get(sock,i), i365_get(sock,i+1), i365_get(sock,i+2), i365_get(sock,i+3), ((i % 16) == 12) ? "\n" : " "); buf += ret; } ISA_UNLOCK(sock, flags); return ret;}static CLASS_DEVICE_ATTR(exca, S_IRUGO, show_exca, NULL);static CLASS_DEVICE_ATTR(info, S_IRUGO, show_info, NULL);#endif/*====================================================================*//* this is horribly ugly... proper locking needs to be done here at * some time... */#define LOCKED(x) do { \ int retval; \ unsigned long flags; \ spin_lock_irqsave(&isa_lock, flags); \ retval = x; \ spin_unlock_irqrestore(&isa_lock, flags); \ return retval; \} while (0) static int pcic_get_status(struct pcmcia_socket *s, u_int *value){ unsigned int sock = container_of(s, struct i82365_socket, socket)->number; if (socket[sock].flags & IS_ALIVE) { *value = 0; return -EINVAL; } LOCKED(i365_get_status(sock, value));}static int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state){ unsigned int sock = container_of(s, struct i82365_socket, socket)->number; if (socket[sock].flags & IS_ALIVE) return -EINVAL; LOCKED(i365_set_socket(sock, state));}static int pcic_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io){ unsigned int sock = container_of(s, struct i82365_socket, socket)->number; if (socket[sock].flags & IS_ALIVE) return -EINVAL; LOCKED(i365_set_io_map(sock, io));}static int pcic_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem){ unsigned int sock = container_of(s, struct i82365_socket, socket)->number; if (socket[sock].flags & IS_ALIVE) return -EINVAL; LOCKED(i365_set_mem_map(sock, mem));}static int pcic_init(struct pcmcia_socket *s){ int i; struct resource res = { .start = 0, .end = 0x1000 }; pccard_io_map io = { 0, 0, 0, 0, 1 }; pccard_mem_map mem = { .res = &res, }; for (i = 0; i < 2; i++) { io.map = i; pcic_set_io_map(s, &io); } for (i = 0; i < 5; i++) { mem.map = i; pcic_set_mem_map(s, &mem); } return 0;}static struct pccard_operations pcic_operations = { .init = pcic_init, .get_status = pcic_get_status, .set_socket = pcic_set_socket, .set_io_map = pcic_set_io_map, .set_mem_map = pcic_set_mem_map,};/*====================================================================*/static struct device_driver i82365_driver = { .name = "i82365", .bus = &platform_bus_type, .suspend = pcmcia_socket_dev_suspend, .resume = pcmcia_socket_dev_resume,};static struct platform_device *i82365_device;static int __init init_i82365(void){ int i, ret; ret = driver_register(&i82365_driver); if (ret) return ret; i82365_device = platform_device_alloc("i82365", 0); if (i82365_device) { ret = platform_device_add(i82365_device); if (ret) platform_device_put(i82365_device); } else ret = -ENOMEM; if (ret) { driver_unregister(&i82365_driver); return ret; } printk(KERN_INFO "Intel ISA PCIC probe: "); sockets = 0; isa_probe(); if (sockets == 0) { printk("not found.\n"); platform_device_unregister(i82365_device); release_region(i365_base, 2); driver_unregister(&i82365_driver); return -ENODEV; } /* Set up interrupt handler(s) */ if (grab_irq != 0) request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); /* register sockets with the pcmcia core */ for (i = 0; i < sockets; i++) { socket[i].socket.dev.parent = &i82365_device->dev; socket[i].socket.ops = &pcic_operations; socket[i].socket.resource_ops = &pccard_nonstatic_ops; socket[i].socket.owner = THIS_MODULE; socket[i].number = i; ret = pcmcia_register_socket(&socket[i].socket); if (!ret) socket[i].flags |= IS_REGISTERED;#if 0 /* driver model ordering issue */ class_device_create_file(&socket[i].socket.dev, &class_device_attr_info); class_device_create_file(&socket[i].socket.dev, &class_device_attr_exca);#endif } /* Finally, schedule a polling interrupt */ if (poll_interval != 0) { poll_timer.function = pcic_interrupt_wrapper; poll_timer.data = 0; init_timer(&poll_timer); poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer); } return 0; } /* init_i82365 */static void __exit exit_i82365(void){ int i; for (i = 0; i < sockets; i++) { if (socket[i].flags & IS_REGISTERED) pcmcia_unregister_socket(&socket[i].socket); } platform_device_unregister(i82365_device); if (poll_interval != 0) del_timer_sync(&poll_timer); if (grab_irq != 0) free_irq(cs_irq, pcic_interrupt); for (i = 0; i < sockets; i++) { /* Turn off all interrupt sources! */ i365_set(i, I365_CSCINT, 0); release_region(socket[i].ioaddr, 2); } release_region(i365_base, 2);#ifdef CONFIG_PNP if (i82365_pnpdev) pnp_disable_dev(i82365_pnpdev);#endif driver_unregister(&i82365_driver);} /* exit_i82365 */module_init(init_i82365);module_exit(exit_i82365);MODULE_LICENSE("Dual MPL/GPL");/*====================================================================*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -