synclinkmp.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,458 行 · 第 1/5 页
C
2,458 行
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s write() count=%d\n", __FILE__,__LINE__,info->device_name,count); if (sanity_check(info, tty->name, "write")) goto cleanup; if (!tty || !info->tx_buf) goto cleanup; if (info->params.mode == MGSL_MODE_HDLC) { if (count > info->max_frame_size) { ret = -EIO; goto cleanup; } if (info->tx_active) goto cleanup; if (info->tx_count) { /* send accumulated data from send_char() calls */ /* as frame and wait before accepting more data. */ tx_load_dma_buffer(info, info->tx_buf, info->tx_count); goto start; } if (!from_user) { ret = info->tx_count = count; tx_load_dma_buffer(info, buf, count); goto start; } } for (;;) { c = min_t(int, count, min(info->max_frame_size - info->tx_count - 1, info->max_frame_size - info->tx_put)); if (c <= 0) break; if (from_user) { COPY_FROM_USER(err, info->tx_buf + info->tx_put, buf, c); if (err) { if (!ret) ret = -EFAULT; break; } } else memcpy(info->tx_buf + info->tx_put, buf, c); spin_lock_irqsave(&info->lock,flags); info->tx_put += c; if (info->tx_put >= info->max_frame_size) info->tx_put -= info->max_frame_size; info->tx_count += c; spin_unlock_irqrestore(&info->lock,flags); buf += c; count -= c; ret += c; } if (info->params.mode == MGSL_MODE_HDLC) { if (count) { ret = info->tx_count = 0; goto cleanup; } tx_load_dma_buffer(info, info->tx_buf, info->tx_count); }start: if (info->tx_count && !tty->stopped && !tty->hw_stopped) { spin_lock_irqsave(&info->lock,flags); if (!info->tx_active) tx_start(info); spin_unlock_irqrestore(&info->lock,flags); }cleanup: if (debug_level >= DEBUG_LEVEL_INFO) printk( "%s(%d):%s write() returning=%d\n", __FILE__,__LINE__,info->device_name,ret); return ret;}/* Add a character to the transmit buffer. */static void put_char(struct tty_struct *tty, unsigned char ch){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if ( debug_level >= DEBUG_LEVEL_INFO ) { printk( "%s(%d):%s put_char(%d)\n", __FILE__,__LINE__,info->device_name,ch); } if (sanity_check(info, tty->name, "put_char")) return; if (!tty || !info->tx_buf) return; spin_lock_irqsave(&info->lock,flags); if ( (info->params.mode != MGSL_MODE_HDLC) || !info->tx_active ) { if (info->tx_count < info->max_frame_size - 1) { info->tx_buf[info->tx_put++] = ch; if (info->tx_put >= info->max_frame_size) info->tx_put -= info->max_frame_size; info->tx_count++; } } spin_unlock_irqrestore(&info->lock,flags);}/* Send a high-priority XON/XOFF character */static void send_xchar(struct tty_struct *tty, char ch){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s send_xchar(%d)\n", __FILE__,__LINE__, info->device_name, ch ); if (sanity_check(info, tty->name, "send_xchar")) return; info->x_char = ch; if (ch) { /* Make sure transmit interrupts are on */ spin_lock_irqsave(&info->lock,flags); if (!info->tx_enabled) tx_start(info); spin_unlock_irqrestore(&info->lock,flags); }}/* Wait until the transmitter is empty. */static void wait_until_sent(struct tty_struct *tty, int timeout){ SLMP_INFO * info = (SLMP_INFO *)tty->driver_data; unsigned long orig_jiffies, char_time; if (!info ) return; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s wait_until_sent() entry\n", __FILE__,__LINE__, info->device_name ); if (sanity_check(info, tty->name, "wait_until_sent")) return; if (!(info->flags & ASYNC_INITIALIZED)) goto exit; orig_jiffies = jiffies; /* Set check interval to 1/5 of estimated time to * send a character, and make it at least 1. The check * interval should also be less than the timeout. * Note: use tight timings here to satisfy the NIST-PCTS. */ if ( info->params.data_rate ) { char_time = info->timeout/(32 * 5); if (!char_time) char_time++; } else char_time = 1; if (timeout) char_time = min_t(unsigned long, char_time, timeout); if ( info->params.mode == MGSL_MODE_HDLC ) { while (info->tx_active) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } } else { //TODO: determine if there is something similar to USC16C32 // TXSTATUS_ALL_SENT status while ( info->tx_active && info->tx_enabled) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } }exit: if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s wait_until_sent() exit\n", __FILE__,__LINE__, info->device_name );}/* Return the count of free bytes in transmit buffer */static int write_room(struct tty_struct *tty){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; int ret; if (sanity_check(info, tty->name, "write_room")) return 0; if (info->params.mode == MGSL_MODE_HDLC) { ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; } else { ret = info->max_frame_size - info->tx_count - 1; if (ret < 0) ret = 0; } if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s write_room()=%d\n", __FILE__, __LINE__, info->device_name, ret); return ret;}/* enable transmitter and send remaining buffered characters */static void flush_chars(struct tty_struct *tty){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):%s flush_chars() entry tx_count=%d\n", __FILE__,__LINE__,info->device_name,info->tx_count); if (sanity_check(info, tty->name, "flush_chars")) return; if (info->tx_count <= 0 || tty->stopped || tty->hw_stopped || !info->tx_buf) return; if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):%s flush_chars() entry, starting transmitter\n", __FILE__,__LINE__,info->device_name ); spin_lock_irqsave(&info->lock,flags); if (!info->tx_active) { if ( (info->params.mode == MGSL_MODE_HDLC) && info->tx_count ) { /* operating in synchronous (frame oriented) mode */ /* copy data from circular tx_buf to */ /* transmit DMA buffer. */ tx_load_dma_buffer(info, info->tx_buf,info->tx_count); } tx_start(info); } spin_unlock_irqrestore(&info->lock,flags);}/* Discard all data in the send buffer */static void flush_buffer(struct tty_struct *tty){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s flush_buffer() entry\n", __FILE__,__LINE__, info->device_name ); if (sanity_check(info, tty->name, "flush_buffer")) return; spin_lock_irqsave(&info->lock,flags); info->tx_count = info->tx_put = info->tx_get = 0; del_timer(&info->tx_timer); spin_unlock_irqrestore(&info->lock,flags); wake_up_interruptible(&tty->write_wait); tty_wakeup(tty);}/* throttle (stop) transmitter */static void tx_hold(struct tty_struct *tty){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (sanity_check(info, tty->name, "tx_hold")) return; if ( debug_level >= DEBUG_LEVEL_INFO ) printk("%s(%d):%s tx_hold()\n", __FILE__,__LINE__,info->device_name); spin_lock_irqsave(&info->lock,flags); if (info->tx_enabled) tx_stop(info); spin_unlock_irqrestore(&info->lock,flags);}/* release (start) transmitter */static void tx_release(struct tty_struct *tty){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; if (sanity_check(info, tty->name, "tx_release")) return; if ( debug_level >= DEBUG_LEVEL_INFO ) printk("%s(%d):%s tx_release()\n", __FILE__,__LINE__,info->device_name); spin_lock_irqsave(&info->lock,flags); if (!info->tx_enabled) tx_start(info); spin_unlock_irqrestore(&info->lock,flags);}/* Service an IOCTL request * * Arguments: * * tty pointer to tty instance data * file pointer to associated file object for device * cmd IOCTL command code * arg command argument/context * * Return Value: 0 if success, otherwise error code */static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; int error; struct mgsl_icount cnow; /* kernel counter temps */ struct serial_icounter_struct __user *p_cuser; /* user space */ unsigned long flags; void __user *argp = (void __user *)arg; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s ioctl() cmd=%08X\n", __FILE__,__LINE__, info->device_name, cmd ); if (sanity_check(info, tty->name, "ioctl")) return -ENODEV; if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } switch (cmd) { case MGSL_IOCGPARAMS: return get_params(info, argp); case MGSL_IOCSPARAMS: return set_params(info, argp); case MGSL_IOCGTXIDLE: return get_txidle(info, argp); case MGSL_IOCSTXIDLE: return set_txidle(info, (int)arg); case MGSL_IOCTXENABLE: return tx_enable(info, (int)arg); case MGSL_IOCRXENABLE: return rx_enable(info, (int)arg); case MGSL_IOCTXABORT: return tx_abort(info); case MGSL_IOCGSTATS: return get_stats(info, argp); case MGSL_IOCWAITEVENT: return wait_mgsl_event(info, argp); case MGSL_IOCLOOPTXDONE: return 0; // TODO: Not supported, need to document /* Wait for modem input (DCD,RI,DSR,CTS) change * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS) */ case TIOCMIWAIT: return modem_input_wait(info,(int)arg); /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) * Return: write counters to the user passed counter struct * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted. */ case TIOCGICOUNT: spin_lock_irqsave(&info->lock,flags); cnow = info->icount; spin_unlock_irqrestore(&info->lock,flags); p_cuser = argp; PUT_USER(error,cnow.cts, &p_cuser->cts); if (error) return error; PUT_USER(error,cnow.dsr, &p_cuser->dsr); if (error) return error; PUT_USER(error,cnow.rng, &p_cuser->rng); if (error) return error; PUT_USER(error,cnow.dcd, &p_cuser->dcd); if (error) return error; PUT_USER(error,cnow.rx, &p_cuser->rx); if (error) return error; PUT_USER(error,cnow.tx, &p_cuser->tx); if (error) return error; PUT_USER(error,cnow.frame, &p_cuser->frame); if (error) return error; PUT_USER(error,cnow.overrun, &p_cuser->overrun); if (error) return error; PUT_USER(error,cnow.parity, &p_cuser->parity); if (error) return error; PUT_USER(error,cnow.brk, &p_cuser->brk); if (error) return error; PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun); if (error) return error; return 0; default: return -ENOIOCTLCMD; } return 0;}/* * /proc fs routines.... */static inline int line_info(char *buf, SLMP_INFO *info){ char stat_buf[30]; int ret; unsigned long flags; ret = sprintf(buf, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n" "\tIRQ=%d MaxFrameSize=%u\n", info->device_name, info->phys_sca_base, info->phys_memory_base, info->phys_statctrl_base, info->phys_lcr_base, info->irq_level, info->max_frame_size ); /* output current serial signal states */ spin_lock_irqsave(&info->lock,flags); get_signals(info); spin_unlock_irqrestore(&info->lock,flags); stat_buf[0] = 0; stat_buf[1] = 0; if (info->serial_signals & SerialSignal_RTS) strcat(stat_buf, "|RTS"); if (info->serial_signals & SerialSignal_CTS) strcat(stat_buf, "|CTS"); if (info->serial_signals & SerialSignal_DTR) strcat(stat_buf, "|DTR"); if (info->serial_signals & SerialSignal_DSR) strcat(stat_buf, "|DSR"); if (info->serial_signals & SerialSignal_DCD) strcat(stat_buf, "|CD"); if (info->serial_signals & SerialSignal_RI) strcat(stat_buf, "|RI"); if (info->params.mode == MGSL_MODE_HDLC) { ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d", info->icount.txok, info->icount.rxok); if (info->icount.txunder) ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder); if (info->icount.txabort) ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort); if (info->icount.rxshort) ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort); if (info->icount.rxlong) ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong); if (info->icount.rxover) ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); if (info->icount.rxcrc) ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc); } else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?