📄 serial_cnxt.c
字号:
static int cnxt_get_hwinst(char *buf, char **start, off_t offset, int length, int *eof, void *data){ struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; if(offset) return 0; if(length > PAGE_SIZE) length = PAGE_SIZE; snprintf(buf, length - 1, "%d-%s\n", inst->devnode->hwInstNum, inst->devnode->hwInstName); buf[length-1] = '\0'; return strlen(buf);}static int cnxt_get_hwprofile(char *buf, char **start, off_t offset, int length, int *eof, void *data){ struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; if(offset) return 0; if(length > PAGE_SIZE) length = PAGE_SIZE; snprintf(buf, length - 1, "%s\n", inst->devnode->hwProfile); buf[length-1] = '\0'; return strlen(buf);}static int cnxt_get_hwrevision(char *buf, char **start, off_t offset, int length, int *eof, void *data){ struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; if(offset) return 0; if(length > PAGE_SIZE) length = PAGE_SIZE; snprintf(buf, length - 1, "%s\n", inst->devnode->hwRevision); buf[length-1] = '\0'; return strlen(buf);}#ifdef COMCTRL_MONITOR_POUND_UG_SUPPORTstatic int cnxt_get_lastcallstatus(char *page, char **start, off_t offset, int length, int *eof, void *data){ struct cnxt_serial_inst *inst = (struct cnxt_serial_inst *)data; PORT_MONITOR_DATA monitorData; int len = PAGE_SIZE; monitorData.dwSize = len; monitorData.pBuf = page; if (cnxt_monitor(inst, COMCTRL_MONITOR_POUND_UG, &monitorData) != COM_STATUS_SUCCESS) { page[0] = '\0'; } else page[len-1] = '\0'; len = strlen(page); if (len <= offset+length) *eof = 1; *start = page + offset; len -= offset; if (len > length) len = length; if (len < 0) len = 0; return len;}#endif /* COMCTRL_MONITOR_POUND_UG_SUPPORT */#endif /* CONFIG_PROC_FS */#ifndef FOUND_UART_REGISTER_PORTstatic DECLARE_MUTEX(cnxt_port_sem);/** * uart_register_port - register a serial port * @drv: UART driver * @port: serial port template * * Configure the serial port specified by the request. * * The port is then probed and if necessary the IRQ is autodetected * If this fails an error is returned. * * On success the port is ready to use and the line number is returned. */static int uart_register_port(struct uart_driver *drv, struct uart_port *port){ int i; struct uart_port *uart_port; int ret = -ENOSPC; down(&cnxt_port_sem); for (i = 0; i < NR_PORTS; i++) { uart_port = &cnxt_ports[i]; if (uart_port->type == PORT_UNKNOWN) break; } if (i < NR_PORTS) { uart_remove_one_port(drv, uart_port); uart_port->iobase = port->iobase; uart_port->membase = port->membase; uart_port->irq = port->irq; uart_port->uartclk = port->uartclk; uart_port->iotype = port->iotype; uart_port->flags = port->flags | UPF_BOOT_AUTOCONF; uart_port->mapbase = port->mapbase; if (port->dev) uart_port->dev = port->dev; ret = uart_add_one_port(drv, uart_port); if (ret == 0) ret = uart_port->line; } up(&cnxt_port_sem); return ret;}/** * uart_unregister_port - remove a serial port at runtime * @drv: UART driver * @line: serial line number * * Remove one serial port. This may not be called from interrupt * context. We hand the port back to the our control. */static void uart_unregister_port(struct uart_driver *drv, int line){ struct uart_port *uart_port = &cnxt_ports[line]; down(&cnxt_port_sem); uart_remove_one_port(drv, uart_port); uart_port->flags = 0; uart_port->type = PORT_UNKNOWN; uart_port->iobase = 0; uart_port->mapbase = 0; uart_port->membase = 0; uart_port->dev = NULL; uart_add_one_port(drv, uart_port); up(&cnxt_port_sem);}#endif /* FOUND_UART_REGISTER_PORT */int cnxt_serial_add(POS_DEVNODE devnode, unsigned int iobase, void *membase, unsigned int irq, struct module *owner){ struct cnxt_serial_inst *inst = NULL; int i, r; struct uart_port port; PORT_EVENT_HANDLER EvtHandler; unsigned long flags; if(!devnode) { return -EINVAL; } for(i = 0; i < NR_PORTS; i++) { spin_lock_irqsave(&cnxt_serial_inst[i].lock, flags); if(!cnxt_serial_inst[i].devnode) { inst = &cnxt_serial_inst[i]; inst->devnode = devnode; spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); break; } spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); } if(!inst) { return -ENOSPC; } devnode->hwInstNum = i; /* instance number, needed by osnvm */ inst->hcomctrl = ComCtrl_Create(); if(!inst->hcomctrl) { printk(KERN_DEBUG "%s: ComCtrlCreate failed!\n", __FUNCTION__); r = -EIO; goto errout; } devnode->hcomctrl = inst->hcomctrl; if ((r=ComCtrl_Configure(inst->hcomctrl, COMCTRL_CONFIG_DEVICE_ID, devnode))) { printk(KERN_DEBUG "%s: ComCtrlConfigure DEVICE_ID failed (%d)\n", __FUNCTION__, r); r = -EIO; goto errout; } inst->port = NULL; inst->owner = owner; inst->mctrl_flags = 0; inst->typestr = kmalloc(strlen(CNXTDRVDSC) + strlen(devnode->hwInstName) + 5, GFP_KERNEL); if(inst->typestr) sprintf(inst->typestr, "%s (%s)", CNXTDRVDSC, devnode->hwInstName); inst->evt_rxchar = 0; inst->evt_rxbreak = 0; inst->evt_rxovrn = 0; inst->evt_txempty = 1; inst->rxenabled = 0; inst->txenabled = 0; inst->readcount = inst->readoffset = 0; OsThreadScheduleInit(&inst->intr_tqueue, cnxt_intr, inst); EvtHandler.pfnCallback = (#if (__GNUC__ == 3 && __GNUC_MINOR__ > 1) || __GNUC__ > 3 __shimcall__#endif void (*) (PVOID pRef, UINT32 dwEventMask)) cnxt_event_handler; EvtHandler.pRef = inst; if ((r=ComCtrl_Configure(inst->hcomctrl, COMCTRL_CONFIG_EVENT_HANDLER, &EvtHandler))) { printk(KERN_DEBUG "%s: ComCtrlConfigure EVENT_HANDLER failed (%d)\n", __FUNCTION__, r); r = -EIO; goto errout; } if((r=ComCtrl_Open(inst->hcomctrl))) { printk(KERN_ERR "%s: ComCtrlOpen failed (%d)\n", __FUNCTION__, r); r = -EIO; goto errout; } inst->mctrl_flags |= TIOCM_DSR; // until comctrl generates events for this memset(&port, 0, sizeof(port)); port.iobase = iobase; port.membase = membase; port.irq = irq; port.iotype = iobase ? SERIAL_IO_PORT : SERIAL_IO_MEM; port.uartclk = BASE_BAUD * 16; port.fifosize = 16; port.ops = &cnxt_pops; port.flags = ASYNC_BOOT_AUTOCONF; if((r=uart_register_port(&cnxt_reg, &port)) < 0) { inst->mctrl_flags &= ~TIOCM_DSR; ComCtrl_Close(inst->hcomctrl); goto errout; } if(r != i) { printk(KERN_WARNING "%s: uart_register_port returned %d, expecting %d\n", __FUNCTION__, r, i); }#ifdef CONFIG_PROC_FS if(cnxt_serial_proc_dir) { char dirname[10]; snprintf(dirname, sizeof(dirname), "%d", i); inst->proc_unit_dir = proc_mkdir(dirname, cnxt_serial_proc_dir); if(inst->proc_unit_dir) { inst->proc_hwinst = create_proc_read_entry("hwinst", 0, inst->proc_unit_dir, cnxt_get_hwinst, inst); inst->proc_hwprofile = create_proc_read_entry("hwprofile", 0, inst->proc_unit_dir, cnxt_get_hwprofile, inst); inst->proc_hwrevision = create_proc_read_entry("hwrevision", 0, inst->proc_unit_dir, cnxt_get_hwrevision, inst);#ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT inst->proc_lastcallstatus = create_proc_read_entry("lastcallstatus", 0, inst->proc_unit_dir, cnxt_get_lastcallstatus, inst); }#endif }#endif /* CONFIG_PROC_FS */ return 0;errout: if(inst->hcomctrl) { ComCtrl_Destroy(inst->hcomctrl); inst->hcomctrl = NULL; } spin_lock_irqsave(&inst->lock, flags); inst->devnode = NULL; spin_unlock_irqrestore(&inst->lock, flags); return r;}int cnxt_serial_remove(POS_DEVNODE devnode){ struct cnxt_serial_inst *inst = NULL; int i; unsigned long flags; if(!devnode) { return -EINVAL; } for(i = 0; i < NR_PORTS; i++) { spin_lock_irqsave(&cnxt_serial_inst[i].lock, flags); if(cnxt_serial_inst[i].devnode == devnode) { inst = &cnxt_serial_inst[i]; spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); break; } spin_unlock_irqrestore(&cnxt_serial_inst[i].lock, flags); } if(!inst) { return -EINVAL; } inst->mctrl_flags &= ~TIOCM_DSR;#ifdef CONFIG_PROC_FS#ifdef COMCTRL_MONITOR_POUND_UG_SUPPORT if(inst->proc_lastcallstatus) remove_proc_entry("lastcallstatus", inst->proc_unit_dir);#endif if(inst->proc_hwrevision) remove_proc_entry("hwrevision", inst->proc_unit_dir); if(inst->proc_hwprofile) remove_proc_entry("hwprofile", inst->proc_unit_dir); if(inst->proc_hwinst) remove_proc_entry("hwinst", inst->proc_unit_dir); if(inst->proc_unit_dir) { char dirname[10]; snprintf(dirname, sizeof(dirname), "%d", i); remove_proc_entry(dirname, cnxt_serial_proc_dir); }#endif /* CONFIG_PROC_FS */ uart_unregister_port(&cnxt_reg, i); if(inst->hcomctrl) { devnode->hcomctrl = NULL; ComCtrl_Close(inst->hcomctrl); ComCtrl_Destroy(inst->hcomctrl); inst->hcomctrl = NULL; } if(inst->typestr) { kfree(inst->typestr); inst->typestr = NULL; } spin_lock_irqsave(&inst->lock, flags); inst->devnode = NULL; spin_unlock_irqrestore(&inst->lock, flags); return 0;}static int __initcnxt_serial_init(void){ int i, ret;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) cnxt_reg.normal_major = serialmajor; cnxt_reg.callout_major = calloutmajor;#else cnxt_reg.major = serialmajor; (void)calloutmajor;#endif if(serialmajor == 0) { printk(KERN_ERR "%s: serialmajor parameter must be non-null\n", __FUNCTION__); return -EINVAL; }#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) if(calloutmajor == 0) { printk(KERN_ERR "%s: calloutmajor parameter must be non-null\n", __FUNCTION__); return -EINVAL; } if(serialmajor == calloutmajor) { printk(KERN_ERR "%s: serialmajor and calloutmajor parameter values must differ\n", __FUNCTION__); return -EINVAL; }#endif if ((ret = uart_init()) != 0) { return ret; } for(i = 0; i < NR_PORTS; i++) { spin_lock_init(&cnxt_serial_inst[i].lock); cnxt_ports[i].ops = &cnxt_pops; /* uart_register_port() might not set ops */ cnxt_ports[i].line = i; }#ifdef CONFIG_PROC_FS cnxt_serial_proc_dir = proc_mkdir(CNXTTARGET, proc_root_driver);#endif ret = uart_register_driver(&cnxt_reg); if(ret) {#ifdef CONFIG_PROC_FS if(cnxt_serial_proc_dir) remove_proc_entry(CNXTTARGET, proc_root_driver);#endif uart_exit(); return ret; }#if !(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) for(i = 0; i < NR_PORTS; i++) { uart_add_one_port(&cnxt_reg, &cnxt_ports[i]); }#endif return ret;}static void __exitcnxt_serial_exit(void){#if !(LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) int i; for(i = 0; i < NR_PORTS; i++) { uart_remove_one_port(&cnxt_reg, &cnxt_ports[i]); }#endif uart_unregister_driver(&cnxt_reg);#ifdef CONFIG_PROC_FS if(cnxt_serial_proc_dir) remove_proc_entry(CNXTTARGET, proc_root_driver);#endif uart_exit();}module_init(cnxt_serial_init);module_exit(cnxt_serial_exit);EXPORT_SYMBOL_NOVERS(cnxt_serial_add);EXPORT_SYMBOL_NOVERS(cnxt_serial_remove);MODULE_AUTHOR("Copyright (C) 2003-2004 Linuxant inc.");MODULE_DESCRIPTION("Virtual serial port driver for Conexant modems");MODULE_LICENSE("GPL\0for files in the \"GPL\" directory; for others, only LICENSE file applies");MODULE_INFO(supported, "yes");#ifdef CNXTSERIAL_INCLUDE_CORE#undef EXPORT_SYMBOL#define EXPORT_SYMBOL(x)#undef MODULE_DESCRIPTION#define MODULE_DESCRIPTION(x)#undef MODULE_LICENSE#define MODULE_LICENSE(x)#undef MODULE_INFO#define MODULE_INFO(x,y)#undef module_init#define module_init(x)#undef module_exit#define module_exit(x)#include "serial_core.c"#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -