📄 yam.c
字号:
begin = pos; } if (pos > offset + length) break; } sti(); *start = buffer + (offset - begin); len -= (offset - begin); if (len > length) len = length; return len;}/* --------------------------------------------------------------------- */static struct net_device_stats *yam_get_stats(struct net_device *dev){ struct yam_port *yp; if (!dev || !dev->priv) return NULL; yp = (struct yam_port *) dev->priv; if (yp->magic != YAM_MAGIC) return NULL; /* * Get the current statistics. This may be called with the * card open or closed. */ return &yp->stats;}/* --------------------------------------------------------------------- */static int yam_open(struct net_device *dev){ struct yam_port *yp = (struct yam_port *) dev->priv; enum uart u; int i; int ret=0; printk(KERN_INFO "Trying %s at iobase 0x%lx irq %u\n", dev->name, dev->base_addr, dev->irq); if (!dev || !yp || !yp->bitrate) return -ENXIO; if (!dev->base_addr || dev->base_addr > 0x1000 - YAM_EXTENT || dev->irq < 2 || dev->irq > 15) { return -ENXIO; } if (!request_region(dev->base_addr, YAM_EXTENT, dev->name)) { printk(KERN_ERR "%s: cannot 0x%lx busy\n", dev->name, dev->base_addr); return -EACCES; } if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) { printk(KERN_ERR "%s: cannot find uart type\n", dev->name); ret = -EIO; goto out_release_base; } if (fpga_download(dev->base_addr, yp->bitrate)) { printk(KERN_ERR "%s: cannot init FPGA\n", dev->name); ret = -EIO; goto out_release_base; } outb(0, IER(dev->base_addr)); if (request_irq(dev->irq, yam_interrupt, SA_INTERRUPT | SA_SHIRQ, dev->name, dev)) { printk(KERN_ERR "%s: irq %d busy\n", dev->name, dev->irq); ret = -EBUSY; goto out_release_base; } yam_set_uart(dev); netif_start_queue(dev); yp->slotcnt = yp->slot / 10; /* Reset overruns for all ports - FPGA programming makes overruns */ for (i = 0; i < NR_PORTS; i++) { inb(LSR(yam_ports[i].dev.base_addr)); yam_ports[i].stats.rx_fifo_errors = 0; } printk(KERN_INFO "%s at iobase 0x%lx irq %u uart %s\n", dev->name, dev->base_addr, dev->irq, uart_str[u]); return 0;out_release_base: release_region(dev->base_addr, YAM_EXTENT); return ret;}/* --------------------------------------------------------------------- */static int yam_close(struct net_device *dev){ struct sk_buff *skb; struct yam_port *yp = (struct yam_port *) dev->priv; if (!dev || !yp) return -EINVAL; /* * disable interrupts */ outb(0, IER(dev->base_addr)); outb(1, MCR(dev->base_addr)); /* Remove IRQ handler if last */ free_irq(dev->irq,dev); release_region(dev->base_addr, YAM_EXTENT); netif_stop_queue(dev); while ((skb = skb_dequeue(&yp->send_queue))) dev_kfree_skb(skb); printk(KERN_INFO "%s: close yam at iobase 0x%lx irq %u\n", yam_drvname, dev->base_addr, dev->irq); return 0;}/* --------------------------------------------------------------------- */static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ struct yam_port *yp = (struct yam_port *) dev->priv; struct yamdrv_ioctl_cfg yi; struct yamdrv_ioctl_mcs *ym; int ioctl_cmd; if (copy_from_user(&ioctl_cmd, ifr->ifr_data, sizeof(int))) return -EFAULT; if (yp == NULL || yp->magic != YAM_MAGIC) return -EINVAL; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (cmd != SIOCDEVPRIVATE) return -EINVAL; switch (ioctl_cmd) { case SIOCYAMRESERVED: return -EINVAL; /* unused */ case SIOCYAMSMCS: if (netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ if ((ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_KERNEL)) == NULL) return -ENOBUFS; ym->bitrate = 9600; if (copy_from_user(ym, ifr->ifr_data, sizeof(struct yamdrv_ioctl_mcs))) { kfree(ym); return -EFAULT; } if (ym->bitrate > YAM_MAXBITRATE) { kfree(ym); return -EINVAL; } add_mcs(ym->bits, ym->bitrate); kfree(ym); break; case SIOCYAMSCFG: if (!capable(CAP_SYS_RAWIO)) return -EPERM; if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg))) return -EFAULT; if ((yi.cfg.mask & YAM_IOBASE) && netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ if ((yi.cfg.mask & YAM_IRQ) && netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ if ((yi.cfg.mask & YAM_BITRATE) && netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ if ((yi.cfg.mask & YAM_BAUDRATE) && netif_running(dev)) return -EINVAL; /* Cannot change this parameter when up */ if (yi.cfg.mask & YAM_IOBASE) { yp->iobase = yi.cfg.iobase; dev->base_addr = yi.cfg.iobase; } if (yi.cfg.mask & YAM_IRQ) { if (yi.cfg.irq > 15) return -EINVAL; yp->irq = yi.cfg.irq; dev->irq = yi.cfg.irq; } if (yi.cfg.mask & YAM_BITRATE) { if (yi.cfg.bitrate > YAM_MAXBITRATE) return -EINVAL; yp->bitrate = yi.cfg.bitrate; } if (yi.cfg.mask & YAM_BAUDRATE) { if (yi.cfg.baudrate > YAM_MAXBAUDRATE) return -EINVAL; yp->baudrate = yi.cfg.baudrate; } if (yi.cfg.mask & YAM_MODE) { if (yi.cfg.mode > YAM_MAXMODE) return -EINVAL; yp->dupmode = yi.cfg.mode; } if (yi.cfg.mask & YAM_HOLDDLY) { if (yi.cfg.holddly > YAM_MAXHOLDDLY) return -EINVAL; yp->holdd = yi.cfg.holddly; } if (yi.cfg.mask & YAM_TXDELAY) { if (yi.cfg.txdelay > YAM_MAXTXDELAY) return -EINVAL; yp->txd = yi.cfg.txdelay; } if (yi.cfg.mask & YAM_TXTAIL) { if (yi.cfg.txtail > YAM_MAXTXTAIL) return -EINVAL; yp->txtail = yi.cfg.txtail; } if (yi.cfg.mask & YAM_PERSIST) { if (yi.cfg.persist > YAM_MAXPERSIST) return -EINVAL; yp->pers = yi.cfg.persist; } if (yi.cfg.mask & YAM_SLOTTIME) { if (yi.cfg.slottime > YAM_MAXSLOTTIME) return -EINVAL; yp->slot = yi.cfg.slottime; yp->slotcnt = yp->slot / 10; } break; case SIOCYAMGCFG: yi.cfg.mask = 0xffffffff; yi.cfg.iobase = yp->iobase; yi.cfg.irq = yp->irq; yi.cfg.bitrate = yp->bitrate; yi.cfg.baudrate = yp->baudrate; yi.cfg.mode = yp->dupmode; yi.cfg.txdelay = yp->txd; yi.cfg.holddly = yp->holdd; yi.cfg.txtail = yp->txtail; yi.cfg.persist = yp->pers; yi.cfg.slottime = yp->slot; if (copy_to_user(ifr->ifr_data, &yi, sizeof(struct yamdrv_ioctl_cfg))) return -EFAULT; break; default: return -EINVAL; } return 0;}/* --------------------------------------------------------------------- */static int yam_set_mac_address(struct net_device *dev, void *addr){ struct sockaddr *sa = (struct sockaddr *) addr; /* addr is an AX.25 shifted ASCII mac address */ memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); return 0;}/* --------------------------------------------------------------------- */static int yam_probe(struct net_device *dev){ struct yam_port *yp; if (!dev) return -ENXIO; yp = (struct yam_port *) dev->priv; dev->open = yam_open; dev->stop = yam_close; dev->do_ioctl = yam_ioctl; dev->hard_start_xmit = yam_send_packet; dev->get_stats = yam_get_stats; skb_queue_head_init(&yp->send_queue);#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) dev->hard_header = ax25_encapsulate; dev->rebuild_header = ax25_rebuild_header;#else /* CONFIG_AX25 || CONFIG_AX25_MODULE */ dev->hard_header = NULL; dev->rebuild_header = NULL;#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */ dev->set_mac_address = yam_set_mac_address; dev->type = ARPHRD_AX25; /* AF_AX25 device */ dev->hard_header_len = 73; /* We do digipeaters now */ dev->mtu = 256; /* AX25 is the default */ dev->addr_len = 7; /* sizeof an ax.25 address */ memcpy(dev->broadcast, ax25_bcast, 7); memcpy(dev->dev_addr, ax25_test, 7); /* New style flags */ dev->flags = 0; return 0;}/* --------------------------------------------------------------------- */static int __init yam_init_driver(void){ struct net_device *dev; int i; printk(yam_drvinfo); for (i = 0; i < NR_PORTS; i++) { sprintf(yam_ports[i].dev.name, "yam%d", i); yam_ports[i].magic = YAM_MAGIC; yam_ports[i].bitrate = DEFAULT_BITRATE; yam_ports[i].baudrate = DEFAULT_BITRATE * 2; yam_ports[i].iobase = 0; yam_ports[i].irq = 0; yam_ports[i].dupmode = 0; yam_ports[i].holdd = DEFAULT_HOLDD; yam_ports[i].txd = DEFAULT_TXD; yam_ports[i].txtail = DEFAULT_TXTAIL; yam_ports[i].slot = DEFAULT_SLOT; yam_ports[i].pers = DEFAULT_PERS; dev = &yam_ports[i].dev; dev->priv = &yam_ports[i]; dev->base_addr = yam_ports[i].iobase; dev->irq = yam_ports[i].irq; dev->init = yam_probe; dev->if_port = 0; if (register_netdev(dev)) { printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name); dev->priv = NULL; return -ENXIO; } SET_MODULE_OWNER(dev); } yam_timer.function = yam_dotimer; yam_timer.expires = jiffies + HZ / 100; add_timer(&yam_timer); proc_net_create("yam", 0, yam_net_get_info); return 0;}/* --------------------------------------------------------------------- */static void __exit yam_cleanup_driver(void){ struct yam_mcs *p; int i; del_timer(&yam_timer); for (i = 0; i < NR_PORTS; i++) { struct net_device *dev = &yam_ports[i].dev; if (!dev->priv) continue; if (netif_running(dev)) yam_close(dev); unregister_netdev(dev); } while (yam_data) { p = yam_data; yam_data = yam_data->next; kfree(p); } proc_net_remove("yam");}/* --------------------------------------------------------------------- */MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr");MODULE_DESCRIPTION("Yam amateur radio modem driver");MODULE_LICENSE("GPL");module_init(yam_init_driver);module_exit(yam_cleanup_driver);/* --------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -