📄 serial_s3c44b0x.c
字号:
if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE;/* current->timeout = jiffies + info->close_delay; */ schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(S_NORMAL_ACTIVE | S_CALLOUT_ACTIVE | S_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags);}/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */static void rs_hangup(struct tty_struct *tty){ struct s3c44b0x_serial *info = (struct s3c44b0x_serial *) tty->driver_data; if (serial_paranoia_check(info, tty->device, "rs_hangup")) return; rs_flush_buffer(tty); shutdown(info); info->event = 0; info->count = 0; info->flags &= ~(S_NORMAL_ACTIVE | S_CALLOUT_ACTIVE); info->tty = 0; wake_up_interruptible(&info->open_wait);}/* * ------------------------------------------------------------ * rs_open() and friends * ------------------------------------------------------------ */static int block_til_ready(struct tty_struct *tty, struct file *filp, struct s3c44b0x_serial *info){ unsigned long flags; DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ if (info->flags & S_CLOSING) { interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART if (info->flags & S_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS;#else return -EAGAIN;#endif } /* * If this is a callout device, then just make sure the normal * device isn't being used. */ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (info->flags & S_NORMAL_ACTIVE) return -EBUSY; if ((info->flags & S_CALLOUT_ACTIVE) && (info->flags & S_SESSION_LOCKOUT) && (info->session != current->session)) return -EBUSY; if ((info->flags & S_CALLOUT_ACTIVE) && (info->flags & S_PGRP_LOCKOUT) && (info->pgrp != current->pgrp)) return -EBUSY; info->flags |= S_CALLOUT_ACTIVE; return 0; } /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { if (info->flags & S_CALLOUT_ACTIVE) return -EBUSY; info->flags |= S_NORMAL_ACTIVE; return 0; } if (info->flags & S_CALLOUT_ACTIVE) { if (info->normal_termios.c_cflag & CLOCAL) do_clocal = 1; } else { if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; } /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in * this loop, info->count is dropped by one, so that * rs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait);#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready before block: ttyS%d, count = %d\n", info->line, info->count);#endif info->count--; info->blocked_open++; while (1) { save_flags(flags); cli(); if (!(info->flags & S_CALLOUT_ACTIVE)) set_dtr(info, 1); restore_flags(flags); current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || !(info->flags & S_INITIALIZED)) {#ifdef SERIAL_DO_RESTART if (info->flags & S_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS;#else retval = -EAGAIN;#endif break; } if (!(info->flags & S_CALLOUT_ACTIVE) && !(info->flags & S_CLOSING) && do_clocal) break; if (signal_pending(current)) {/* if (current->signal & ~current->blocked) { */ retval = -ERESTARTSYS; break; }#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready blocking: ttyS%d, count = %d\n", info->line, info->count);#endif schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--;#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready after blocking: ttyS%d, count = %d\n", info->line, info->count);#endif if (retval) return retval; info->flags |= S_NORMAL_ACTIVE; return 0;}/* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its S structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */int rs_open(struct tty_struct *tty, struct file *filp){ struct s3c44b0x_serial *info; int retval, line; line = MINOR(tty->device) - tty->driver.minor_start; /* check if line is sane */ if (line < 0 || line >= USART_CNT) return -ENODEV; info = &s3c44b0x_info[line]; if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV;#ifdef SERIAL_DEBUG_OPEN printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, info->count);#endif info->count++; tty->driver_data = info; info->tty = tty; /* * Start up serial port */ retval = startup(info); if (retval) return retval; /* enable interrupts */ set_ints_mode(info, 1); retval = block_til_ready(tty, filp, info); if (retval) {#ifdef SERIAL_DEBUG_OPEN printk("rs_open returning after block_til_ready with %d\n", retval);#endif return retval; } if ((info->count == 1) && (info->flags & S_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; change_speed(info); } info->session = current->session; info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN printk("rs_open ttyS%d successful...\n", info->line);#endif return 0;}static struct irqaction irq_uartTx0 = { rs_s3c44b0x_interruptTxa, 0, 0, "S3C44B0X_UART_TX0", NULL, NULL };static struct irqaction irq_uartTx1 = { rs_s3c44b0x_interruptTxb, 0, 0, "S3C44B0X_UART_TX1", NULL, NULL };static struct irqaction irq_uartRx0 = { rs_s3c44b0x_interruptRxa, 0, 0, "S3C44B0X_UART_RX0", NULL, NULL };static struct irqaction irq_uartRx1 = { rs_s3c44b0x_interruptRxb, 0, 0, "S3C44B0X_UART_RX1", NULL, NULL };static struct irqaction irq_uartErr = { rs_s3c44b0x_interruptErr, 0, 0, "S3C44B0X_UART_ERR", NULL, NULL }; extern int setup_arm_irq(int, struct irqaction *);static void interrupts_init(void){ setup_arm_irq(S3C44B0X_INTERRUPT_UTX0, &irq_uartTx0); setup_arm_irq(S3C44B0X_INTERRUPT_UTX1, &irq_uartTx1); setup_arm_irq(S3C44B0X_INTERRUPT_URX0, &irq_uartRx0); setup_arm_irq(S3C44B0X_INTERRUPT_URX1, &irq_uartRx1); setup_arm_irq(S3C44B0X_INTERRUPT_UERR, &irq_uartErr);}static void show_serial_version(void){ printk("Samsung S3C44B0X UART driver version 0.6 \ <michael.frommberger@sympat.de>\n");}/* rs_init inits the driver */static int __init rs_s3c44b0x_init(void){ int flags, i, pconf; struct s3c44b0x_serial *info; /* Configurate the port as uart */ pconf = inl(S3C44B0X_PCONF); pconf &= ~(0x3f << 13); pconf |= (0x12 << 13); /* enable TxD1 */ outl(pconf, S3C44B0X_PCONF); /* Setup base handler, and timer table. */ init_bh(SERIAL_BH, do_serial_bh); show_serial_version(); /* Initialize the tty_driver structure */ /* set the tty_struct pointers to NULL to let the layer */ /* above allocate the structs. */ for (i=0; i < USART_CNT; i++) serial_table[i] = NULL; memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.name = "ttyS"; serial_driver.driver_name = "S3C44B0X"; serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = USART_CNT; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; serial_driver.init_termios.c_cflag = CS8 | CREAD | HUPCL | CLOCAL; serial_driver.init_termios.c_cflag |= B115200; /* set the tty-layer to raw-mode */ serial_driver.init_termios.c_cflag &= ~(CSIZE|PARENB); serial_driver.init_termios.c_cflag |= CS8; serial_driver.init_termios.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); serial_driver.init_termios.c_oflag &= ~OPOST; serial_driver.init_termios.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); serial_driver.flags = TTY_DRIVER_REAL_RAW; serial_driver.refcount = &serial_refcount; serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; serial_driver.flush_chars = rs_flush_chars; serial_driver.write_room = rs_write_room; serial_driver.chars_in_buffer = rs_chars_in_buffer; serial_driver.flush_buffer = rs_flush_buffer; serial_driver.ioctl = rs_ioctl; serial_driver.throttle = rs_throttle; serial_driver.unthrottle = rs_unthrottle; serial_driver.set_termios = rs_set_termios; serial_driver.stop = rs_stop; serial_driver.start = rs_start; serial_driver.hangup = rs_hangup; /* * The callout device is just like normal device except for * major number and the subtype code. */ callout_driver = serial_driver; callout_driver.name = "cua"; callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); if (tty_register_driver(&callout_driver)) panic("Couldn't register callout driver\n"); save_flags(flags); cli(); for (i = 0; i < USART_CNT; i++) { info = &s3c44b0x_info[i]; info->uart_offset = (i) ? 0 : S3C44B0X_UART1_OFFSET; info->magic = SERIAL_MAGIC; info->tty = 0; info->irqmask = (i) ? (S3C44B0X_INTERRUPT_UTX0 || S3C44B0X_INTERRUPT_URX0 || S3C44B0X_INTERRUPT_UERR) : (S3C44B0X_INTERRUPT_UTX1 || S3C44B0X_INTERRUPT_URX1 || S3C44B0X_INTERRUPT_UERR); info->irq = (i) ? S3C44B0X_INTERRUPT_UTX0 : S3C44B0X_INTERRUPT_UTX1; info->irq_rx = (i) ? S3C44B0X_INTERRUPT_URX0 : S3C44B0X_INTERRUPT_URX1; info->port = (i) ? 1 : 2; info->line = i;#if defined(CONFIG_CONSOLE_NULL) || !defined(CONFIG_SERIAL_S3C44B0X_CONSOLE) info->is_cons = 0;#elif !defined(CONFIG_CONSOLE_NULL) && defined(CONFIG_SERIAL_S3C44B0X_CONSOLE) if (i == console_number) info->is_cons = 1;#endif set_ints_mode(info, 0); /* info->custom_divisor = 16; */ /* unused? */ info->custom_divisor = 0; info->close_delay = 50; info->closing_wait = 3000; info->cts_state = 1; info->x_char = 0; info->event = 0; info->count = 0; info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; info->tqueue_hangup.routine = do_serial_hangup; info->tqueue_hangup.data = info; info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; /* set default modes */ info->ser_mode = SERIAL_MODE_DEFAULT; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); printk("%s%d (irq = %d)", serial_driver.name, info->line, info->irq); printk(" is a builtin Samsung S3C44B0X UART\n"); } interrupts_init(); restore_flags(flags); return 0;}module_init(rs_s3c44b0x_init);/* * ------------------------------------------------------------ * Serial console driver * ------------------------------------------------------------ */#ifdef CONFIG_SERIAL_S3C44B0X_CONSOLEstatic kdev_t s3c44b0x_console_device(struct console *);static int s3c44b0x_console_setup(struct console *, char *);static void s3c44b0x_console_write (struct console *, const char *, unsigned int );static int s3c44b0x_console_initialized = 0;static struct console s3c44b0x_driver = { name: "ttyS", write: s3c44b0x_console_write, device: s3c44b0x_console_device, setup: s3c44b0x_console_setup, flags: CON_PRINTBUFFER, index: -1,};/* static void init_console(struct s3c44b0x_serial *info) */static int s3c44b0x_console_setup(struct console *c, char *p){ struct s3c44b0x_serial *info = &s3c44b0x_info[console_number]; char ucon = 0; char ulcon = 0; int pconf; unsigned cflag = 0; memset(info, 0, sizeof(struct s3c44b0x_serial)); info->use_ints = 0; info->cts_state = 1; info->is_cons = 1;/* info->usart->cr = 0; *//* info->usart->cr = (U_IRQ_TMODE | U_IRQ_RMODE | U_WL8); */ info->line = console_number; info->baud = 115200; info->port = (console_number) ? 1 : 2; info->uart_offset = (console_number) ? 0 : S3C44B0X_UART1_OFFSET; info->ser_mode = SERIAL_MODE_DEFAULT; fifo_init(info); /* set initial baudrate */ uart_speed(info, cflag); /* Configurate the port as uart */ pconf = inl(S3C44B0X_PCONF); pconf &= ~(0x3f << 13); pconf |= (0x12 << 13); /* enable TxD1 */ outl(pconf, S3C44B0X_PCONF); /* rx/tx setup */ ucon |= S3C44B0X_UCON_RX_MODE_INT_POLL; /* receive mode: IRQ or polling */ ucon |= S3C44B0X_UCON_TX_MODE_INT_POLL; /* transmit mode: IRQ or polling */ outb(ucon, S3C44B0X_UCON0 + info->uart_offset); /* set line control register */ ulcon |= S3C44B0X_ULCON_WORDLN_8; ulcon |= S3C44B0X_ULCON_STOPB_1; ulcon |= S3C44B0X_ULCON_PAR_NO; outb(ulcon, S3C44B0X_ULCON0 + info->uart_offset); rx_enable(info); tx_enable(info); s3c44b0x_console_initialized = 1; return 0;}static kdev_t s3c44b0x_console_device(struct console *c){ return MKDEV(TTY_MAJOR, 64 + c->index);}static void s3c44b0x_console_write (struct console *co, const char *str, unsigned int count){#if defined(CONFIG_CONSOLE_NULL) return;#else struct s3c44b0x_serial *info = &s3c44b0x_info[console_number]; if (!s3c44b0x_console_initialized) printk ("WARNING: Console used unintialized\n"); while (count--) { if (*str == '\n') rs_put_char(info,'\r'); rs_put_char(info, *str++ ); }#endif}void __init s3c44b0x_console_init(void){ register_console(&s3c44b0x_driver);}#endif /* CONFIG_SERIAL_S3C44B0X_CONSOLE *//* * Local variables: * c-indent-level: 8 * c-basic-offset: 8 * tab-width: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -