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 + -
显示快捷键?