icom.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,703 行 · 第 1/3 页

C
1,703
字号
		bits = 7;		break;	case CS6:		/* 6 bits/char */		new_config2 |= ICOM_ACFG_6BPC;		bits = 8;		break;	case CS7:		/* 7 bits/char */		new_config2 |= ICOM_ACFG_7BPC;		bits = 9;		break;	case CS8:		/* 8 bits/char */		new_config2 |= ICOM_ACFG_8BPC;		bits = 10;		break;	default:		bits = 10;		break;	}	if (cflag & CSTOPB) {		/* 2 stop bits */		new_config2 |= ICOM_ACFG_2STOP_BIT;		bits++;	}	if (cflag & PARENB) {		/* parity bit enabled */		new_config2 |= ICOM_ACFG_PARITY_ENAB;		trace(ICOM_PORT, "PARENB", 0);		bits++;	}	if (cflag & PARODD) {		/* odd parity */		new_config2 |= ICOM_ACFG_PARITY_ODD;		trace(ICOM_PORT, "PARODD", 0);	}	/* Determine divisor based on baud rate */	baud = uart_get_baud_rate(port, termios, old_termios,				  icom_acfg_baud[0],				  icom_acfg_baud[BAUD_TABLE_LIMIT]);	if (!baud)		baud = 9600;	/* B0 transition handled in rs_set_termios */	for (index = 0; index < BAUD_TABLE_LIMIT; index++) {		if (icom_acfg_baud[index] == baud) {			new_config3 = index;			break;		}	}	uart_update_timeout(port, cflag, baud);	/* CTS flow control flag and modem status interrupts */	tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));	if (cflag & CRTSCTS)		tmp_byte |= HDLC_HDW_FLOW;	else		tmp_byte &= ~HDLC_HDW_FLOW;	writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));	/*	 * Set up parity check flag	 */	ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;	if (iflag & INPCK)		ICOM_PORT->read_status_mask |=		    SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR;	if ((iflag & BRKINT) || (iflag & PARMRK))		ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET;	/*	 * Characters to ignore	 */	ICOM_PORT->ignore_status_mask = 0;	if (iflag & IGNPAR)		ICOM_PORT->ignore_status_mask |=		    SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR;	if (iflag & IGNBRK) {		ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET;		/*		 * If we're ignore parity and break indicators, ignore		 * overruns too.  (For real raw support).		 */		if (iflag & IGNPAR)			ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN;	}	/*	 * !!! ignore all characters if CREAD is not set	 */	if ((cflag & CREAD) == 0)		ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE;	/* Turn off Receiver to prepare for reset */	writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg);	for (index = 0; index < 10; index++) {		if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) {			break;		}	}	/* clear all current buffers of data */	for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) {		ICOM_PORT->statStg->rcv[rcv_buff].flags = 0;		ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0;		ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength =		    (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);	}	for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) {		ICOM_PORT->statStg->xmit[xmit_buff].flags = 0;	}	/* activate changes and start xmit and receiver here */	/* Enable the receiver */	writeb(new_config3, &(ICOM_PORT->dram->async_config3));	writeb(new_config2, &(ICOM_PORT->dram->async_config2));	tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));	tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL;	writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));	writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer));	/* 0.5 seconds */	writeb(0xFF, &(ICOM_PORT->dram->ier));	/* enable modem signal interrupts */	/* reset processor */	writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg);	for (index = 0; index < 10; index++) {		if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) {			break;		}	}	/* Enable Transmitter and Reciever */	offset =	    (unsigned long) &ICOM_PORT->statStg->rcv[0] -	    (unsigned long) ICOM_PORT->statStg;	writel(ICOM_PORT->statStg_pci + offset,	       &ICOM_PORT->dram->RcvStatusAddr);	ICOM_PORT->next_rcv = 0;	ICOM_PORT->put_length = 0;	*ICOM_PORT->xmitRestart = 0;	writel(ICOM_PORT->xmitRestart_pci,	       &ICOM_PORT->dram->XmitStatusAddr);	trace(ICOM_PORT, "XR_ENAB", 0);	writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);	spin_unlock_irqrestore(&port->lock, flags);}static const char *icom_type(struct uart_port *port){	return "icom";}static void icom_release_port(struct uart_port *port){}static int icom_request_port(struct uart_port *port){	return 0;}static void icom_config_port(struct uart_port *port, int flags){	port->type = PORT_ICOM;}static struct uart_ops icom_ops = {	.tx_empty = icom_tx_empty,	.set_mctrl = icom_set_mctrl,	.get_mctrl = icom_get_mctrl,	.stop_tx = icom_stop_tx,	.start_tx = icom_start_tx,	.send_xchar = icom_send_xchar,	.stop_rx = icom_stop_rx,	.enable_ms = icom_enable_ms,	.break_ctl = icom_break,	.startup = icom_open,	.shutdown = icom_close,	.set_termios = icom_set_termios,	.type = icom_type,	.release_port = icom_release_port,	.request_port = icom_request_port,	.config_port = icom_config_port,};#define ICOM_CONSOLE NULLstatic struct uart_driver icom_uart_driver = {	.owner = THIS_MODULE,	.driver_name = ICOM_DRIVER_NAME,	.dev_name = "ttyA",	.major = ICOM_MAJOR,	.minor = ICOM_MINOR_START,	.nr = NR_PORTS,	.cons = ICOM_CONSOLE,};static int __devinit icom_init_ports(struct icom_adapter *icom_adapter){	u32 subsystem_id = icom_adapter->subsystem_id;	int retval = 0;	int i;	struct icom_port *icom_port;	if (icom_adapter->version == ADAPTER_V1) {		icom_adapter->numb_ports = 2;		for (i = 0; i < 2; i++) {			icom_port = &icom_adapter->port_info[i];			icom_port->port = i;			icom_port->status = ICOM_PORT_ACTIVE;			icom_port->imbed_modem = ICOM_UNKNOWN;		}	} else {		if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) {			icom_adapter->numb_ports = 4;			for (i = 0; i < 4; i++) {				icom_port = &icom_adapter->port_info[i];				icom_port->port = i;				icom_port->status = ICOM_PORT_ACTIVE;				icom_port->imbed_modem = ICOM_IMBED_MODEM;			}		} else {			icom_adapter->numb_ports = 4;			icom_adapter->port_info[0].port = 0;			icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE;			if (subsystem_id ==			    PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) {				icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM;			} else {				icom_adapter->port_info[0].imbed_modem = ICOM_RVX;			}			icom_adapter->port_info[1].status = ICOM_PORT_OFF;			icom_adapter->port_info[2].port = 2;			icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE;			icom_adapter->port_info[2].imbed_modem = ICOM_RVX;			icom_adapter->port_info[3].status = ICOM_PORT_OFF;		}	}	return retval;}static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num){	if (icom_adapter->version == ADAPTER_V1) {		icom_port->global_reg = (struct icom_regs *) ((char *)			icom_adapter->base_addr + 0x4000);		icom_port->int_reg = (unsigned long) icom_adapter->base_addr +		    0x4004 + 2 - 2 * port_num;	} else {		icom_port->global_reg = (struct icom_regs *) ((char *)			icom_adapter->base_addr + 0x8000);		if (icom_port->port < 2)			icom_port->int_reg = (unsigned long) icom_adapter->base_addr +			    0x8004 + 2 - 2 * icom_port->port;		else			icom_port->int_reg = (unsigned long) icom_adapter->base_addr +			    0x8024 + 2 - 2 * (icom_port->port - 2);	}}static int __init icom_load_ports(struct icom_adapter *icom_adapter){	struct icom_port *icom_port;	int port_num;	int retval;	for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) {		icom_port = &icom_adapter->port_info[port_num];		if (icom_port->status == ICOM_PORT_ACTIVE) {			icom_port_active(icom_port, icom_adapter, port_num);			icom_port->dram = (struct func_dram *) ((char *)					icom_adapter->base_addr +					0x2000 * icom_port->port);			icom_port->adapter = icom_adapter;			/* get port memory */			if ((retval = get_port_memory(icom_port)) != 0) {				dev_err(&icom_port->adapter->pci_dev->dev,					"Memory allocation for port FAILED\n");			}		}	}	return 0;}static int __devinit icom_alloc_adapter(struct icom_adapter					**icom_adapter_ref){	int adapter_count = 0;	struct icom_adapter *icom_adapter;	struct icom_adapter *cur_adapter_entry;	struct list_head *tmp;	icom_adapter = (struct icom_adapter *)	    kmalloc(sizeof(struct icom_adapter), GFP_KERNEL);	if (!icom_adapter) {		return -ENOMEM;	}	memset(icom_adapter, 0, sizeof(struct icom_adapter));	list_for_each(tmp, &icom_adapter_head) {		cur_adapter_entry =		    list_entry(tmp, struct icom_adapter,			       icom_adapter_entry);		if (cur_adapter_entry->index != adapter_count) {			break;		}		adapter_count++;	}	icom_adapter->index = adapter_count;	list_add_tail(&icom_adapter->icom_adapter_entry, tmp);	*icom_adapter_ref = icom_adapter;	return 0;}static void icom_free_adapter(struct icom_adapter *icom_adapter){	list_del(&icom_adapter->icom_adapter_entry);	kfree(icom_adapter);}static void icom_remove_adapter(struct icom_adapter *icom_adapter){	struct icom_port *icom_port;	int index;	for (index = 0; index < icom_adapter->numb_ports; index++) {		icom_port = &icom_adapter->port_info[index];		if (icom_port->status == ICOM_PORT_ACTIVE) {			dev_info(&icom_adapter->pci_dev->dev,				 "Device removed\n");			uart_remove_one_port(&icom_uart_driver,					     &icom_port->uart_port);			/* be sure that DTR and RTS are dropped */			writeb(0x00, &icom_port->dram->osr);			/* Wait 0.1 Sec for simple Init to complete */			msleep(100);			/* Stop proccessor */			stop_processor(icom_port);			free_port_memory(icom_port);		}	}	free_irq(icom_adapter->irq_number, (void *) icom_adapter);	iounmap((void *) icom_adapter->base_addr);	icom_free_adapter(icom_adapter);	pci_release_regions(icom_adapter->pci_dev);}static void icom_kobj_release(struct kobject *kobj){	struct icom_adapter *icom_adapter;	icom_adapter = to_icom_adapter(kobj);	icom_remove_adapter(icom_adapter);}static struct kobj_type icom_kobj_type = {	.release = icom_kobj_release,};static int __devinit icom_probe(struct pci_dev *dev,				const struct pci_device_id *ent){	int index;        unsigned int command_reg;        int retval;        struct icom_adapter *icom_adapter;        struct icom_port *icom_port;        retval = pci_enable_device(dev);        if (retval) {		dev_err(&dev->dev, "Device enable FAILED\n");                return retval;	}	if ( (retval = pci_request_regions(dev, "icom"))) {		 dev_err(&dev->dev, "pci_request_region FAILED\n");		 pci_disable_device(dev);		 return retval;	 }        pci_set_master(dev);        if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) {		dev_err(&dev->dev, "PCI Config read FAILED\n");                return retval;        }	pci_write_config_dword(dev, PCI_COMMAND,		command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER 		| PCI_COMMAND_PARITY | PCI_COMMAND_SERR);        if (ent->driver_data == ADAPTER_V1) {		pci_write_config_dword(dev, 0x44, 0x8300830A);	 } else {		pci_write_config_dword(dev, 0x44, 0x42004200);		pci_write_config_dword(dev, 0x48, 0x42004200);         }	retval = icom_alloc_adapter(&icom_adapter);	if (retval) {		 dev_err(&dev->dev, "icom_alloc_adapter FAILED\n");		 retval = -EIO;		 goto probe_exit0;	}	 icom_adapter->base_addr_pci = pci_resource_start(dev, 0);	 icom_adapter->irq_number = dev->irq;	 icom_adapter->pci_dev = dev;	 icom_adapter->version = ent->driver_data;	 icom_adapter->subsystem_id = ent->subdevice;	retval = icom_init_ports(icom_adapter);	if (retval) {		dev_err(&dev->dev, "Port configuration failed\n");		goto probe_exit1;	}	 icom_adapter->base_addr =	     (unsigned long) ioremap(icom_adapter->base_addr_pci,						pci_resource_len(dev, 0));	if (!icom_adapter->base_addr)		goto probe_exit1;	 /* save off irq and request irq line */	 if ( (retval = request_irq(dev->irq, icom_interrupt,				   SA_INTERRUPT | SA_SHIRQ, ICOM_DRIVER_NAME,				   (void *) icom_adapter))) {		  goto probe_exit2;	 }	retval = icom_load_ports(icom_adapter);        for (index = 0; index < icom_adapter->numb_ports; index++) {		icom_port = &icom_adapter->port_info[index];		if (icom_port->status == ICOM_PORT_ACTIVE) {			icom_port->uart_port.irq = icom_port->adapter->irq_number;			icom_port->uart_port.type = PORT_ICOM;			icom_port->uart_port.iotype = UPIO_MEM;			icom_port->uart_port.membase =					       (char *) icom_adapter->base_addr_pci;			icom_port->uart_port.fifosize = 16;			icom_port->uart_port.ops = &icom_ops;			icom_port->uart_port.line =		        icom_port->port + icom_adapter->index * 4;			if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) {				icom_port->status = ICOM_PORT_OFF;				dev_err(&dev->dev, "Device add failed\n");			 } else			        dev_info(&dev->dev, "Device added\n");		}	}	kobject_init(&icom_adapter->kobj);	icom_adapter->kobj.ktype = &icom_kobj_type;	return 0;probe_exit2:	iounmap((void *) icom_adapter->base_addr);probe_exit1:	icom_free_adapter(icom_adapter);probe_exit0:	pci_release_regions(dev);	pci_disable_device(dev);        return retval;}static void __devexit icom_remove(struct pci_dev *dev){	struct icom_adapter *icom_adapter;	struct list_head *tmp;	list_for_each(tmp, &icom_adapter_head) {		icom_adapter = list_entry(tmp, struct icom_adapter,					  icom_adapter_entry);		if (icom_adapter->pci_dev == dev) {			kobject_put(&icom_adapter->kobj);			return;		}	}	dev_err(&dev->dev, "Unable to find device to remove\n");}static struct pci_driver icom_pci_driver = {	.name = ICOM_DRIVER_NAME,	.id_table = icom_pci_table,	.probe = icom_probe,	.remove = __devexit_p(icom_remove),};static int __init icom_init(void){	int ret;	spin_lock_init(&icom_lock);	icom_lock = (spinlock_t) SPIN_LOCK_UNLOCKED;	ret = uart_register_driver(&icom_uart_driver);	if (ret)		return ret;	ret = pci_register_driver(&icom_pci_driver);	if (ret < 0)		uart_unregister_driver(&icom_uart_driver);	return ret;}static void __exit icom_exit(void){	pci_unregister_driver(&icom_pci_driver);	uart_unregister_driver(&icom_uart_driver);}module_init(icom_init);module_exit(icom_exit);#ifdef ICOM_TRACEstatic inline void trace(struct icom_port *icom_port, char *trace_pt,		  unsigned long trace_data){	dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",		 icom_port->port, trace_pt, trace_data);}#endifMODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");MODULE_SUPPORTED_DEVICE    ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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