⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 yam.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	.next = yam_seq_next,	.stop = yam_seq_stop,	.show = yam_seq_show,};static int yam_info_open(struct inode *inode, struct file *file){	return seq_open(file, &yam_seqops);}static struct file_operations yam_info_fops = {	.owner = THIS_MODULE,	.open = yam_info_open,	.read = seq_read,	.llseek = seq_lseek,	.release = seq_release,};#endif/* --------------------------------------------------------------------- */static struct net_device_stats *yam_get_stats(struct net_device *dev){	struct yam_port *yp;	if (!dev)		return NULL;	yp = netdev_priv(dev);	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 = netdev_priv(dev);	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->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++) {		struct net_device *dev = yam_devs[i];		struct yam_port *yp = netdev_priv(dev);		inb(LSR(dev->base_addr));		yp->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 = netdev_priv(dev);	if (!dev)		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 = netdev_priv(dev);	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->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 void yam_setup(struct net_device *dev){	struct yam_port *yp = netdev_priv(dev);	yp->magic = YAM_MAGIC;	yp->bitrate = DEFAULT_BITRATE;	yp->baudrate = DEFAULT_BITRATE * 2;	yp->iobase = 0;	yp->irq = 0;	yp->dupmode = 0;	yp->holdd = DEFAULT_HOLDD;	yp->txd = DEFAULT_TXD;	yp->txtail = DEFAULT_TXTAIL;	yp->slot = DEFAULT_SLOT;	yp->pers = DEFAULT_PERS;	yp->dev = dev;	dev->base_addr = yp->iobase;	dev->irq = yp->irq;	SET_MODULE_OWNER(dev);	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);	dev->hard_header = ax25_hard_header;	dev->rebuild_header = ax25_rebuild_header;	dev->set_mac_address = yam_set_mac_address;	dev->type = ARPHRD_AX25;	dev->hard_header_len = AX25_MAX_HEADER_LEN;	dev->mtu = AX25_MTU;	dev->addr_len = AX25_ADDR_LEN;	memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);	memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);}static int __init yam_init_driver(void){	struct net_device *dev;	int i, err;	char name[IFNAMSIZ];	printk(yam_drvinfo);	for (i = 0; i < NR_PORTS; i++) {		sprintf(name, "yam%d", i);				dev = alloc_netdev(sizeof(struct yam_port), name,				   yam_setup);		if (!dev) {			printk(KERN_ERR "yam: cannot allocate net device %s\n",			       dev->name);			err = -ENOMEM;			goto error;		}				err = register_netdev(dev);		if (err) {			printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name);			goto error;		}		yam_devs[i] = dev;	}	yam_timer.function = yam_dotimer;	yam_timer.expires = jiffies + HZ / 100;	add_timer(&yam_timer);	proc_net_fops_create("yam", S_IRUGO, &yam_info_fops);	return 0; error:	while (--i >= 0) {		unregister_netdev(yam_devs[i]);		free_netdev(yam_devs[i]);	}	return err;}/* --------------------------------------------------------------------- */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_devs[i];		if (dev) {			unregister_netdev(dev);			free_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 + -