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

📄 baycom_ser_fdx.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
	__sti();	if (!bc->modem.ptt && txcount) {		hdlcdrv_arbitrate(dev, &bc->hdrv);		if (hdlcdrv_ptt(&bc->hdrv)) {			ser12_set_divisor(dev, bc->baud_uartdiv);			bc->modem.ser12.txshreg = 1;			bc->modem.ptt = 1;		}	}	hdlcdrv_transmitter(dev, &bc->hdrv);	hdlcdrv_receiver(dev, &bc->hdrv);	__cli();}/* --------------------------------------------------------------------- */enum uart { c_uart_unknown, c_uart_8250,	    c_uart_16450, c_uart_16550, c_uart_16550A};static const char *uart_str[] = { 	"unknown", "8250", "16450", "16550", "16550A" };static enum uart ser12_check_uart(unsigned int iobase){	unsigned char b1,b2,b3;	enum uart u;	enum uart uart_tab[] =		{ c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };	b1 = inb(MCR(iobase));	outb(b1 | 0x10, MCR(iobase));	/* loopback mode */	b2 = inb(MSR(iobase));	outb(0x1a, MCR(iobase));	b3 = inb(MSR(iobase)) & 0xf0;	outb(b1, MCR(iobase));			/* restore old values */	outb(b2, MSR(iobase));	if (b3 != 0x90)		return c_uart_unknown;	inb(RBR(iobase));	inb(RBR(iobase));	outb(0x01, FCR(iobase));		/* enable FIFOs */	u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];	if (u == c_uart_16450) {		outb(0x5a, SCR(iobase));		b1 = inb(SCR(iobase));		outb(0xa5, SCR(iobase));		b2 = inb(SCR(iobase));		if ((b1 != 0x5a) || (b2 != 0xa5))			u = c_uart_8250;	}	return u;}/* --------------------------------------------------------------------- */static int ser12_open(struct device *dev){	struct baycom_state *bc = (struct baycom_state *)dev->priv;	enum uart u;	if (!dev || !bc)		return -ENXIO;	if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT ||	    dev->irq < 2 || dev->irq > 15)		return -ENXIO;	if (bc->baud < 300 || bc->baud > 4800)		return -EINVAL;	if (check_region(dev->base_addr, SER12_EXTENT))		return -EACCES;	memset(&bc->modem, 0, sizeof(bc->modem));	bc->hdrv.par.bitrate = bc->baud;	bc->baud_us = 1000000/bc->baud;	bc->baud_uartdiv = (115200/8)/bc->baud;	if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown)		return -EIO;	outb(0, FCR(dev->base_addr));  /* disable FIFOs */	outb(0x0d, MCR(dev->base_addr));	outb(0, IER(dev->base_addr));	if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT | SA_SHIRQ,			"baycom_ser_fdx", dev))		return -EBUSY;	request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx");	/*	 * set the SIO to 6 Bits/character; during receive,	 * the baud rate is set to produce 100 ints/sec	 * to feed the channel arbitration process,	 * during transmit to baud ints/sec to run	 * the transmitter	 */	ser12_set_divisor(dev, 115200/100/8);	/*	 * enable transmitter empty interrupt and modem status interrupt	 */	outb(0x0a, IER(dev->base_addr));	/*	 * make sure the next interrupt is generated;	 * 0 must be used to power the modem; the modem draws its	 * power from the TxD line	 */	outb(0x00, THR(dev->base_addr));	hdlcdrv_setdcd(&bc->hdrv, 0);	printk(KERN_INFO "%s: ser_fdx at iobase 0x%lx irq %u options "	       "0x%x baud %u uart %s\n", bc_drvname, dev->base_addr, dev->irq,	       bc->options, bc->baud, uart_str[u]);	MOD_INC_USE_COUNT;	return 0;}/* --------------------------------------------------------------------- */static int ser12_close(struct device *dev){	struct baycom_state *bc = (struct baycom_state *)dev->priv;	if (!dev || !bc)		return -EINVAL;	/*	 * disable interrupts	 */	outb(0, IER(dev->base_addr));	outb(1, MCR(dev->base_addr));	free_irq(dev->irq, dev);	release_region(dev->base_addr, SER12_EXTENT);	printk(KERN_INFO "%s: close ser_fdx at iobase 0x%lx irq %u\n",	       bc_drvname, dev->base_addr, dev->irq);	MOD_DEC_USE_COUNT;	return 0;}/* --------------------------------------------------------------------- *//* * ===================== hdlcdrv driver interface ========================= *//* --------------------------------------------------------------------- */static int baycom_ioctl(struct device *dev, struct ifreq *ifr,			struct hdlcdrv_ioctl *hi, int cmd);/* --------------------------------------------------------------------- */static struct hdlcdrv_ops ser12_ops = {	bc_drvname,	bc_drvinfo,	ser12_open,	ser12_close,	baycom_ioctl};/* --------------------------------------------------------------------- */static int baycom_setmode(struct baycom_state *bc, const char *modestr){	unsigned int baud;	if (!strncmp(modestr, "ser", 3)) {		baud = simple_strtoul(modestr+3, NULL, 10);		if (baud >= 3 && baud <= 48)			bc->baud = baud*100;	}	bc->options = !!strchr(modestr, '*');	return 0;}/* --------------------------------------------------------------------- */static int baycom_ioctl(struct device *dev, struct ifreq *ifr,			struct hdlcdrv_ioctl *hi, int cmd){	struct baycom_state *bc;	struct baycom_ioctl bi;	int cmd2;	if (!dev || !dev->priv ||	    ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) {		printk(KERN_ERR "bc_ioctl: invalid device struct\n");		return -EINVAL;	}	bc = (struct baycom_state *)dev->priv;	if (cmd != SIOCDEVPRIVATE)		return -ENOIOCTLCMD;	if (get_user(cmd2, (int *)ifr->ifr_data))		return -EFAULT;	switch (hi->cmd) {	default:		break;	case HDLCDRVCTL_GETMODE:		sprintf(hi->data.modename, "ser%u", bc->baud / 100);		if (bc->options & 1)			strcat(hi->data.modename, "*");		if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))			return -EFAULT;		return 0;	case HDLCDRVCTL_SETMODE:		if (dev->start || !suser())			return -EACCES;		hi->data.modename[sizeof(hi->data.modename)-1] = '\0';		return baycom_setmode(bc, hi->data.modename);	case HDLCDRVCTL_MODELIST:		strcpy(hi->data.modename, "ser12,ser3,ser24");		if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))			return -EFAULT;		return 0;	case HDLCDRVCTL_MODEMPARMASK:		return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ;	}	if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi)))		return -EFAULT;	switch (bi.cmd) {	default:		return -ENOIOCTLCMD;#ifdef BAYCOM_DEBUG	case BAYCOMCTL_GETDEBUG:		bi.data.dbg.debug1 = bc->hdrv.ptt_keyed;		bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;		bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;		break;#endif /* BAYCOM_DEBUG */	}	if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))		return -EFAULT;	return 0;}/* --------------------------------------------------------------------- */__initfunc(int baycom_ser_fdx_init(void)){	int i, j, found = 0;	char set_hw = 1;	struct baycom_state *bc;	char ifname[HDLCDRV_IFNAMELEN];	printk(bc_drvinfo);	/*	 * register net devices	 */	for (i = 0; i < NR_PORTS; i++) {		struct device *dev = baycom_device+i;		sprintf(ifname, "bcsf%d", i);		if (!baycom_ports[i].mode)			set_hw = 0;		if (!set_hw)			baycom_ports[i].iobase = baycom_ports[i].irq = 0;		j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops,					     sizeof(struct baycom_state),					     ifname, baycom_ports[i].iobase,					     baycom_ports[i].irq, 0);		if (!j) {			bc = (struct baycom_state *)dev->priv;			if (set_hw && baycom_setmode(bc, baycom_ports[i].mode))				set_hw = 0;			bc->baud = baycom_ports[i].baud;			found++;		} else {			printk(KERN_WARNING "%s: cannot register net device\n",			       bc_drvname);		}	}	if (!found)		return -ENXIO;	return 0;}/* --------------------------------------------------------------------- */#ifdef MODULE/* * command line settable parameters */static char *mode[NR_PORTS] = { "ser12*", };static int iobase[NR_PORTS] = { 0x3f8, };static int irq[NR_PORTS] = { 4, };static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 };#if LINUX_VERSION_CODE >= 0x20115MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s");MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i");MODULE_PARM_DESC(iobase, "baycom io base address");MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i");MODULE_PARM_DESC(irq, "baycom irq number");MODULE_PARM(baud, "1-" __MODULE_STRING(NR_PORTS) "i");MODULE_PARM_DESC(baud, "baycom baud rate (300 to 4800)");MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver");#endif__initfunc(int init_module(void)){	int i;	for (i = 0; (i < NR_PORTS) && (mode[i]); i++) {		baycom_ports[i].mode = mode[i];		baycom_ports[i].iobase = iobase[i];		baycom_ports[i].irq = irq[i];		baycom_ports[i].baud = baud[i];	}	if (i < NR_PORTS-1)		baycom_ports[i+1].mode = NULL;	return baycom_ser_fdx_init();}/* --------------------------------------------------------------------- */void cleanup_module(void){	int i;	for(i = 0; i < NR_PORTS; i++) {		struct device *dev = baycom_device+i;		struct baycom_state *bc = (struct baycom_state *)dev->priv;		if (bc) {			if (bc->hdrv.magic != HDLCDRV_MAGIC)				printk(KERN_ERR "baycom: invalid magic in "				       "cleanup_module\n");			else				hdlcdrv_unregister_hdlcdrv(dev);		}	}}#else /* MODULE *//* --------------------------------------------------------------------- *//* * format: baycom_ser_fdx=io,irq,mode * mode: [*] * * indicates sofware DCD */__initfunc(void baycom_ser_fdx_setup(char *str, int *ints)){	int i;	for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++);	if ((i >= NR_PORTS) || (ints[0] < 2)) {		printk(KERN_INFO "%s: too many or invalid interface "		       "specifications\n", bc_drvname);		return;	}	baycom_ports[i].mode = str;	baycom_ports[i].iobase = ints[1];	baycom_ports[i].irq = ints[2];	if (ints[0] >= 3)		baycom_ports[i].baud = ints[3];	else		baycom_ports[i].baud = 1200;	if (i < NR_PORTS-1)		baycom_ports[i+1].mode = NULL;}#endif /* MODULE *//* --------------------------------------------------------------------- */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -