📄 sdla.c
字号:
return(-EINVAL); if (data.config.flags & ~FRAD_VALID_FLAGS) return(-EINVAL); if ((data.config.kbaud < 0) || ((data.config.kbaud > 128) && (flp->type != SDLA_S508))) return(-EINVAL); if (data.config.clocking & ~(FRAD_CLOCK_INT | SDLA_S508_PORT_RS232)) return(-EINVAL); if ((data.config.mtu < 0) || (data.config.mtu > SDLA_MAX_MTU)) return(-EINVAL); if ((data.config.T391 < 5) || (data.config.T391 > 30)) return(-EINVAL); if ((data.config.T392 < 5) || (data.config.T392 > 30)) return(-EINVAL); if ((data.config.N391 < 1) || (data.config.N391 > 255)) return(-EINVAL); if ((data.config.N392 < 1) || (data.config.N392 > 10)) return(-EINVAL); if ((data.config.N393 < 1) || (data.config.N393 > 10)) return(-EINVAL); memcpy(&flp->config, &data.config, sizeof(struct frad_conf)); flp->config.flags |= SDLA_DIRECT_RECV; if (flp->type == SDLA_S508) flp->config.flags |= SDLA_TX70_RX30; if (dev->mtu != flp->config.mtu) { /* this is required to change the MTU */ dev->mtu = flp->config.mtu; for(i=0;i<CONFIG_DLCI_MAX;i++) if (flp->master[i]) flp->master[i]->mtu = flp->config.mtu; } flp->config.mtu += sizeof(struct frhdr); /* off to the races! */ if (!flp->configured) sdla_start(dev); flp->configured = 1; } else { /* no sense reading if the CPU isn't started */ if (netif_running(dev)) { size = sizeof(data); if (sdla_cmd(dev, SDLA_READ_DLCI_CONFIGURATION, 0, 0, NULL, 0, &data, &size) != SDLA_RET_OK) return(-EIO); } else if (flp->configured) memcpy(&data.config, &flp->config, sizeof(struct frad_conf)); else memset(&data.config, 0, sizeof(struct frad_conf)); memcpy(&flp->config, &data.config, sizeof(struct frad_conf)); data.config.flags &= FRAD_VALID_FLAGS; data.config.mtu -= data.config.mtu > sizeof(struct frhdr) ? sizeof(struct frhdr) : data.config.mtu; return copy_to_user(conf, &data.config, sizeof(struct frad_conf))?-EFAULT:0; } return(0);}static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int read){ struct sdla_mem mem; char *temp; if(copy_from_user(&mem, info, sizeof(mem))) return -EFAULT; if (read) { temp = kmalloc(mem.len, GFP_KERNEL); if (!temp) return(-ENOMEM); memset(temp, 0, mem.len); sdla_read(dev, mem.addr, temp, mem.len); if(copy_to_user(mem.data, temp, mem.len)) { kfree(temp); return -EFAULT; } kfree(temp); } else { temp = kmalloc(mem.len, GFP_KERNEL); if (!temp) return(-ENOMEM); if(copy_from_user(temp, mem.data, mem.len)) { kfree(temp); return -EFAULT; } sdla_write(dev, mem.addr, temp, mem.len); kfree(temp); } return(0);}static int sdla_reconfig(struct net_device *dev){ struct frad_local *flp; struct conf_data data; int i, len; flp = dev->priv; len = 0; for(i=0;i<CONFIG_DLCI_MAX;i++) if (flp->dlci[i]) data.dlci[len++] = flp->dlci[i]; len *= 2; memcpy(&data, &flp->config, sizeof(struct frad_conf)); len += sizeof(struct frad_conf); sdla_cmd(dev, SDLA_DISABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL); sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, 0, 0, &data, len, NULL, NULL); sdla_cmd(dev, SDLA_ENABLE_COMMUNICATIONS, 0, 0, NULL, 0, NULL, NULL); return(0);}static int sdla_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ struct frad_local *flp; if(!capable(CAP_NET_ADMIN)) return -EPERM; flp = dev->priv; if (!flp->initialized) return(-EINVAL); switch (cmd) { case FRAD_GET_CONF: case FRAD_SET_CONF: return(sdla_config(dev, ifr->ifr_data, cmd == FRAD_GET_CONF)); case SDLA_IDENTIFY: ifr->ifr_flags = flp->type; break; case SDLA_CPUSPEED: return(sdla_cpuspeed(dev, ifr)); /* ==========================================================NOTE: This is rather a useless action right now, as the current driver does not support protocols other than FR. However, Sangoma has modules for a number of other protocols in the works.============================================================*/ case SDLA_PROTOCOL: if (flp->configured) return(-EALREADY); switch (ifr->ifr_flags) { case ARPHRD_FRAD: dev->type = ifr->ifr_flags; break; default: return(-ENOPROTOOPT); } break; case SDLA_CLEARMEM: sdla_clear(dev); break; case SDLA_WRITEMEM: case SDLA_READMEM: return(sdla_xfer(dev, ifr->ifr_data, cmd == SDLA_READMEM)); case SDLA_START: sdla_start(dev); break; case SDLA_STOP: sdla_stop(dev); break; default: return(-EOPNOTSUPP); } return(0);}int sdla_change_mtu(struct net_device *dev, int new_mtu){ struct frad_local *flp; flp = dev->priv; if (netif_running(dev)) return(-EBUSY); /* for now, you can't change the MTU! */ return(-EOPNOTSUPP);}int sdla_set_config(struct net_device *dev, struct ifmap *map){ struct frad_local *flp; int i; char byte; unsigned base; int err = -EINVAL; flp = dev->priv; if (flp->initialized) return(-EINVAL); for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++) if (valid_port[i] == map->base_addr) break; if (i == sizeof(valid_port) / sizeof(int)) return(-EINVAL); if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){ printk(KERN_WARNING "SDLA: io-port 0x%04lx in use \n", dev->base_addr); return(-EINVAL); } base = map->base_addr; /* test for card types, S502A, S502E, S507, S508 */ /* these tests shut down the card completely, so clear the state */ flp->type = SDLA_UNKNOWN; flp->state = 0; for(i=1;i<SDLA_IO_EXTENTS;i++) if (inb(base + i) != 0xFF) break; if (i == SDLA_IO_EXTENTS) { outb(SDLA_HALT, base + SDLA_REG_Z80_CONTROL); if ((inb(base + SDLA_S502_STS) & 0x0F) == 0x08) { outb(SDLA_S502E_INTACK, base + SDLA_REG_CONTROL); if ((inb(base + SDLA_S502_STS) & 0x0F) == 0x0C) { outb(SDLA_HALT, base + SDLA_REG_CONTROL); flp->type = SDLA_S502E; goto got_type; } } } for(byte=inb(base),i=0;i<SDLA_IO_EXTENTS;i++) if (inb(base + i) != byte) break; if (i == SDLA_IO_EXTENTS) { outb(SDLA_HALT, base + SDLA_REG_CONTROL); if ((inb(base + SDLA_S502_STS) & 0x7E) == 0x30) { outb(SDLA_S507_ENABLE, base + SDLA_REG_CONTROL); if ((inb(base + SDLA_S502_STS) & 0x7E) == 0x32) { outb(SDLA_HALT, base + SDLA_REG_CONTROL); flp->type = SDLA_S507; goto got_type; } } } outb(SDLA_HALT, base + SDLA_REG_CONTROL); if ((inb(base + SDLA_S508_STS) & 0x3F) == 0x00) { outb(SDLA_S508_INTEN, base + SDLA_REG_CONTROL); if ((inb(base + SDLA_S508_STS) & 0x3F) == 0x10) { outb(SDLA_HALT, base + SDLA_REG_CONTROL); flp->type = SDLA_S508; goto got_type; } } outb(SDLA_S502A_HALT, base + SDLA_REG_CONTROL); if (inb(base + SDLA_S502_STS) == 0x40) { outb(SDLA_S502A_START, base + SDLA_REG_CONTROL); if (inb(base + SDLA_S502_STS) == 0x40) { outb(SDLA_S502A_INTEN, base + SDLA_REG_CONTROL); if (inb(base + SDLA_S502_STS) == 0x44) { outb(SDLA_S502A_START, base + SDLA_REG_CONTROL); flp->type = SDLA_S502A; goto got_type; } } } printk(KERN_NOTICE "%s: Unknown card type\n", dev->name); err = -ENODEV; goto fail;got_type: switch(base) { case 0x270: case 0x280: case 0x380: case 0x390: if (flp->type != SDLA_S508 && flp->type != SDLA_S507) goto fail; } switch (map->irq) { case 2: if (flp->type != SDLA_S502E) goto fail; break; case 10: case 11: case 12: case 15: case 4: if (flp->type != SDLA_S508 && flp->type != SDLA_S507) goto fail; break; case 3: case 5: case 7: if (flp->type == SDLA_S502A) goto fail; break; default: goto fail; } err = -EAGAIN; if (request_irq(dev->irq, &sdla_isr, 0, dev->name, dev)) goto fail; if (flp->type == SDLA_S507) { switch(dev->irq) { case 3: flp->state = SDLA_S507_IRQ3; break; case 4: flp->state = SDLA_S507_IRQ4; break; case 5: flp->state = SDLA_S507_IRQ5; break; case 7: flp->state = SDLA_S507_IRQ7; break; case 10: flp->state = SDLA_S507_IRQ10; break; case 11: flp->state = SDLA_S507_IRQ11; break; case 12: flp->state = SDLA_S507_IRQ12; break; case 15: flp->state = SDLA_S507_IRQ15; break; } } for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++) if (valid_mem[i] == map->mem_start) break; err = -EINVAL; if (i == sizeof(valid_mem) / sizeof(int)) goto fail2; if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E) goto fail2; if (flp->type != SDLA_S507 && map->mem_start >> 16 == 0x0B) goto fail2; if (flp->type == SDLA_S507 && map->mem_start >> 16 == 0x0D) goto fail2; byte = flp->type != SDLA_S508 ? SDLA_8K_WINDOW : 0; byte |= (map->mem_start & 0xF000) >> (12 + (flp->type == SDLA_S508 ? 1 : 0)); switch(flp->type) { case SDLA_S502A: case SDLA_S502E: switch (map->mem_start >> 16) { case 0x0A: byte |= SDLA_S502_SEG_A; break; case 0x0C: byte |= SDLA_S502_SEG_C; break; case 0x0D: byte |= SDLA_S502_SEG_D; break; case 0x0E: byte |= SDLA_S502_SEG_E; break; } break; case SDLA_S507: switch (map->mem_start >> 16) { case 0x0A: byte |= SDLA_S507_SEG_A; break; case 0x0B: byte |= SDLA_S507_SEG_B; break; case 0x0C: byte |= SDLA_S507_SEG_C; break; case 0x0E: byte |= SDLA_S507_SEG_E; break; } break; case SDLA_S508: switch (map->mem_start >> 16) { case 0x0A: byte |= SDLA_S508_SEG_A; break; case 0x0C: byte |= SDLA_S508_SEG_C; break; case 0x0D: byte |= SDLA_S508_SEG_D; break; case 0x0E: byte |= SDLA_S508_SEG_E; break; } break; } /* set the memory bits, and enable access */ outb(byte, base + SDLA_REG_PC_WINDOW); switch(flp->type) { case SDLA_S502E: flp->state = SDLA_S502E_ENABLE; break; case SDLA_S507: flp->state |= SDLA_MEMEN; break; case SDLA_S508: flp->state = SDLA_MEMEN; break; } outb(flp->state, base + SDLA_REG_CONTROL); dev->irq = map->irq; dev->base_addr = base; dev->mem_start = map->mem_start; dev->mem_end = dev->mem_start + 0x2000; flp->initialized = 1; return 0;fail2: free_irq(map->irq, dev);fail: release_region(base, SDLA_IO_EXTENTS); return err;} static struct net_device_stats *sdla_stats(struct net_device *dev){ struct frad_local *flp; flp = dev->priv; return(&flp->stats);}static void setup_sdla(struct net_device *dev){ struct frad_local *flp = dev->priv; netdev_boot_setup_check(dev); SET_MODULE_OWNER(dev); dev->flags = 0; dev->type = 0xFFFF; dev->hard_header_len = 0; dev->addr_len = 0; dev->mtu = SDLA_MAX_MTU; dev->open = sdla_open; dev->stop = sdla_close; dev->do_ioctl = sdla_ioctl; dev->set_config = sdla_set_config; dev->get_stats = sdla_stats; dev->hard_start_xmit = sdla_transmit; dev->change_mtu = sdla_change_mtu; flp->activate = sdla_activate; flp->deactivate = sdla_deactivate; flp->assoc = sdla_assoc; flp->deassoc = sdla_deassoc; flp->dlci_conf = sdla_dlci_conf; init_timer(&flp->timer); flp->timer.expires = 1; flp->timer.data = (unsigned long) dev; flp->timer.function = sdla_poll;}static struct net_device *sdla;static int __init init_sdla(void){ int err; printk("%s.\n", version); sdla = alloc_netdev(sizeof(struct frad_local), "sdla0", setup_sdla); if (!sdla) return -ENOMEM; err = register_netdev(sdla); if (err) free_netdev(sdla); return err;}static void __exit exit_sdla(void){ struct frad_local *flp = sdla->priv; unregister_netdev(sdla); if (flp->initialized) { free_irq(sdla->irq, sdla); release_region(sdla->base_addr, SDLA_IO_EXTENTS); } del_timer_sync(&flp->timer); free_netdev(sdla);}MODULE_LICENSE("GPL");module_init(init_sdla);module_exit(exit_sdla);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -