serial167.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,382 行 · 第 1/5 页
C
2,382 行
tmp.baud_base = 0; /*!!!*/ tmp.close_delay = info->close_delay; tmp.custom_divisor = 0; /*!!!*/ tmp.hub6 = 0; /*!!!*/ return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;} /* get_serial_info */static intset_serial_info(struct cyclades_port * info, struct serial_struct * new_info){ struct serial_struct new_serial; struct cyclades_port old_info;/* CP('s'); */ if (!new_info) return -EFAULT; if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; old_info = *info; if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.close_delay != info->close_delay) || ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))) return -EPERM; info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); goto check_and_exit; } /* * OK, past this point, all the error checking has been done. * At this point, we start making changes..... */ info->flags = ((info->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); info->close_delay = new_serial.close_delay;check_and_exit: if (info->flags & ASYNC_INITIALIZED){ config_setup(info); return 0; }else{ return startup(info); }} /* set_serial_info */static intcy_tiocmget(struct tty_struct *tty, struct file *file){ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int channel; volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long flags; unsigned char status; unsigned int result; channel = info->line; local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; status = base_addr[CyMSVR1] | base_addr[CyMSVR2]; local_irq_restore(flags); return ((status & CyRTS) ? TIOCM_RTS : 0) | ((status & CyDTR) ? TIOCM_DTR : 0) | ((status & CyDCD) ? TIOCM_CAR : 0) | ((status & CyDSR) ? TIOCM_DSR : 0) | ((status & CyCTS) ? TIOCM_CTS : 0);} /* cy_tiocmget */static intcy_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear){ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int channel; volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long flags; unsigned int arg; channel = info->line; if (set & TIOCM_RTS){ local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = CyRTS; local_irq_restore(flags); } if (set & TIOCM_DTR){ local_irq_save(flags); base_addr[CyCAR] = (u_char)channel;/* CP('S');CP('2'); */ base_addr[CyMSVR2] = CyDTR;#ifdef SERIAL_DEBUG_DTR printk("cyc: %d: raising DTR\n", __LINE__); printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);#endif local_irq_restore(flags); } if (clear & TIOCM_RTS){ local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = 0; local_irq_restore(flags); } if (clear & TIOCM_DTR){ local_irq_save(flags); base_addr[CyCAR] = (u_char)channel;/* CP('C');CP('2'); */ base_addr[CyMSVR2] = 0;#ifdef SERIAL_DEBUG_DTR printk("cyc: %d: dropping DTR\n", __LINE__); printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);#endif local_irq_restore(flags); } return 0;} /* set_modem_info */static voidsend_break( struct cyclades_port * info, int duration){ /* Let the transmit ISR take care of this (since it requires stuffing characters into the output stream). */ info->x_break = duration; if (!info->xmit_cnt ) { start_xmit(info); }} /* send_break */static intget_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon){ if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor))) return -EFAULT; info->mon.int_count = 0; info->mon.char_count = 0; info->mon.char_max = 0; info->mon.char_last = 0; return 0;}static intset_threshold(struct cyclades_port * info, unsigned long *arg){ volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long value; int channel; if (get_user(value, arg)) return -EFAULT; channel = info->line; info->cor4 &= ~CyREC_FIFO; info->cor4 |= value & CyREC_FIFO; base_addr[CyCOR4] = info->cor4; return 0;}static intget_threshold(struct cyclades_port * info, unsigned long *value){ volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; unsigned long tmp; channel = info->line; tmp = base_addr[CyCOR4] & CyREC_FIFO; return put_user(tmp,value);}static intset_default_threshold(struct cyclades_port * info, unsigned long *arg){ unsigned long value; if (get_user(value, arg)) return -EFAULT; info->default_threshold = value & 0x0f; return 0;}static intget_default_threshold(struct cyclades_port * info, unsigned long *value){ return put_user(info->default_threshold,value);}static intset_timeout(struct cyclades_port * info, unsigned long *arg){ volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; unsigned long value; if (get_user(value, arg)) return -EFAULT; channel = info->line; base_addr[CyRTPRL] = value & 0xff; base_addr[CyRTPRH] = (value >> 8) & 0xff; return 0;}static intget_timeout(struct cyclades_port * info, unsigned long *value){ volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; unsigned long tmp; channel = info->line; tmp = base_addr[CyRTPRL]; return put_user(tmp,value);}static intset_default_timeout(struct cyclades_port * info, unsigned long value){ info->default_timeout = value & 0xff; return 0;}static intget_default_timeout(struct cyclades_port * info, unsigned long *value){ return put_user(info->default_timeout,value);}static intcy_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){ unsigned long val; struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int ret_val = 0;#ifdef SERIAL_DEBUG_OTHER printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */#endif switch (cmd) { case CYGETMON: ret_val = get_mon_info(info, (struct cyclades_monitor *)arg); break; case CYGETTHRESH: ret_val = get_threshold(info, (unsigned long *)arg); break; case CYSETTHRESH: ret_val = set_threshold(info, (unsigned long *)arg); break; case CYGETDEFTHRESH: ret_val = get_default_threshold(info, (unsigned long *)arg); break; case CYSETDEFTHRESH: ret_val = set_default_threshold(info, (unsigned long *)arg); break; case CYGETTIMEOUT: ret_val = get_timeout(info, (unsigned long *)arg); break; case CYSETTIMEOUT: ret_val = set_timeout(info, (unsigned long *)arg); break; case CYGETDEFTIMEOUT: ret_val = get_default_timeout(info, (unsigned long *)arg); break; case CYSETDEFTIMEOUT: ret_val = set_default_timeout(info, (unsigned long)arg); break; case TCSBRK: /* SVID version: non-zero arg --> no break */ ret_val = tty_check_change(tty); if (ret_val) break; tty_wait_until_sent(tty,0); if (!arg) send_break(info, HZ/4); /* 1/4 second */ break; case TCSBRKP: /* support for POSIX tcsendbreak() */ ret_val = tty_check_change(tty); if (ret_val) break; tty_wait_until_sent(tty,0); send_break(info, arg ? arg*(HZ/10) : HZ/4); break;/* The following commands are incompletely implemented!!! */ case TIOCGSOFTCAR: ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); break; case TIOCSSOFTCAR: ret_val = get_user(val, (unsigned long *) arg); if (ret_val) break; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0)); break; case TIOCGSERIAL: ret_val = get_serial_info(info, (struct serial_struct *) arg); break; case TIOCSSERIAL: ret_val = set_serial_info(info, (struct serial_struct *) arg); break; default: ret_val = -ENOIOCTLCMD; }#ifdef SERIAL_DEBUG_OTHER printk("cy_ioctl done\n");#endif return ret_val;} /* cy_ioctl */static voidcy_set_termios(struct tty_struct *tty, struct termios * old_termios){ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;#ifdef SERIAL_DEBUG_OTHER printk("cy_set_termios %s\n", tty->name);#endif if (tty->termios->c_cflag == old_termios->c_cflag) return; config_setup(info); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->stopped = 0; cy_start(tty); }#ifdef tytso_patch_94Nov25_1726 if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) wake_up_interruptible(&info->open_wait);#endif return;} /* cy_set_termios */static voidcy_close(struct tty_struct * tty, struct file * filp){ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;/* CP('C'); */#ifdef SERIAL_DEBUG_OTHER printk("cy_close %s\n", tty->name);#endif if (!info || serial_paranoia_check(info, tty->name, "cy_close")){ return; }#ifdef SERIAL_DEBUG_OPEN printk("cy_close %s, count = %d\n", tty->name, info->count);#endif if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk("cy_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; }#ifdef SERIAL_DEBUG_COUNT printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count - 1);#endif if (--info->count < 0) { printk("cy_close: bad serial port count for ttys%d: %d\n", info->line, info->count);#ifdef SERIAL_DEBUG_COUNT printk("cyc: %d: setting count to 0\n", __LINE__);#endif info->count = 0; } if (info->count) return; info->flags |= ASYNC_CLOSING; if (info->flags & ASYNC_INITIALIZED) tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); info->event = 0; info->tty = 0; if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait);#ifdef SERIAL_DEBUG_OTHER printk("cy_close done\n");#endif return;} /* cy_close *//* * cy_hangup() --- called by tty_hangup() when a hangup is signaled. */voidcy_hangup(struct tty_struct *tty){ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; #ifdef SERIAL_DEBUG_OTHER printk("cy_hangup %s\n", tty->name); /* */#endif if (serial_paranoia_check(info, tty->name, "cy_hangup")) return; shutdown(info);#if 0 info->event = 0; info->count = 0;#ifdef SERIAL_DEBUG_COUNT printk("cyc: %d: setting count to 0\n", __LINE__);#endif info->tty = 0;#endif info->flags &= ~ASYNC_NORMAL_ACTIVE; wake_up_interruptible(&info->open_wait);} /* cy_hangup *//* * ------------------------------------------------------------ * cy_open() and friends * ------------------------------------------------------------ */static intblock_til_ready(struct tty_struct *tty, struct file * filp, struct cyclades_port *info){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; int channel; int retval; volatile u_char *base_addr = (u_char *)BASE_ADDR; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ if (info->flags & ASYNC_CLOSING) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?