📄 serial_atmel.c
字号:
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) {#ifdef US_RTS save_flags(flags); cli(); if (!(info->flags & S_CALLOUT_ACTIVE)) atmel_rtsdtr(info, 1); restore_flags(flags);#endif 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)) { 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; if (!info->use_ints) { serialpoll.data = (void *) info; queue_task(&serialpoll, &tq_timer); } 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 atmel_serial *info; int retval, line; line = MINOR(tty->device) - tty->driver.minor_start; // check if line is sane if (line < 0 || line >= AT91_USART_CNT) return -ENODEV; info = &atmel_info[line];#if 0 /* Is the kgdb running over this line? */ if (info->kgdb_channel) return -ENODEV;#endif 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 */ set_ints_mode(1, info); retval = startup(info); if (retval) return retval; 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;}#if 0static inline void rs_cons_check(struct atmel_serial *ss, int channel){ int i, o, io; static consout_registered = 0; static msg_printed = 0; i = o = io = 0; /* Is this one of the serial console lines? */ if ((atmel_cons_chanout != channel) && (atmel_cons_chanin != channel)) return; atmel_conschan = ss->atmel_channel; atmel_consinfo = ss; /* Register the console output putchar, if necessary */ if ((atmel_cons_chanout == channel)) { o = 1; /* double whee.. */ if (!consout_registered) { register_console(atmel_console_print); consout_registered = 1; } } /* If this is console input, we handle the break received * status interrupt on this line to mean prom_halt(). */ if (atmel_cons_chanin == channel) { ss->break_abort = 1; i = 1; } if (o && i) io = 1; if (ss->baud != 9600) panic("Console baud rate weirdness"); /* Set flag variable for this port so that it cannot be * opened for other uses by accident. */ ss->is_cons = 1; if (io) { if (!msg_printed) { printk("zs%d: console I/O\n", ((channel >> 1) & 1)); msg_printed = 1; } } else { printk("zs%d: console %s\n", ((channel >> 1) & 1), (i == 1 ? "input" : (o == 1 ? "output" : "WEIRD"))); }}#endifstatic struct irqaction irq_usart0 = { rs_interrupta, 0, 0, "usart0", NULL, NULL };static struct irqaction irq_usart1 = { rs_interruptb, 0, 0, "usart1", NULL, NULL };extern int setup_arm_irq(int, struct irqaction *);static void interrupts_init(void){ setup_arm_irq(IRQ_USART0, &irq_usart0); setup_arm_irq(IRQ_USART1, &irq_usart1);}static void show_serial_version(void){ printk("Atmel USART driver version 0.99\n");}/* rs_init inits the driver */static int __init rs_atmel_init(void){ int flags, i; struct atmel_serial *info; /* initialise PIO for serial port */ HW_AT91_USART_INIT /* Setup base handler, and timer table. */ init_bh(SERIAL_BH, do_serial_bh); //xxx timer_table[RS_TIMER].fn = rs_timer; //xxx timer_table[RS_TIMER].expires = 0; // FIXME - do this right rx_buf_table[0] = rx_buf1; rx_buf_table[1] = rx_buf2; 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 < AT91_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.major = TTY_MAJOR; serial_driver.minor_start = 64;#ifdef CONFIG_CONSOLE_ON_SC28L91 serial_driver.minor_start += 1;#endif serial_driver.num = 2; 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 = B9600 | CS8 | CREAD | HUPCL | CLOCAL; 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; serial_driver.set_ldisc = rs_set_ldisc; /* * 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 < 2; i++) { info = &atmel_info[i]; info->magic = SERIAL_MAGIC; info->usart = usarts[i]; info->tty = 0; info->irqmask = (i) ? (1<<IRQ_USART1) : (1<<IRQ_USART0); info->irq = (i) ? IRQ_USART1 : IRQ_USART0;#ifdef CONFIG_SWAP_ATMEL_PORTS info->port = (i) ? 2 : 1; info->line = !i;#ifdef CONFIG_CONSOLE_ON_ATMEL info->is_cons = i;#else info->is_cons = 0;#endif #else info->port = (i) ? 1 : 2; info->line = i;#ifdef CONFIG_CONSOLE_ON_ATMEL info->is_cons = !i;#else info->is_cons = 0;#endif #endif#ifdef CONFIG_CONSOLE_ON_SC28L91 info->line += 1;#endif set_ints_mode(0, info); info->custom_divisor = 16; 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; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); info->rx_buf = rx_buf_table[i]; printk("%s%d at 0x%p (irq = %d)", serial_driver.name, info->line, info->usart, info->irq); printk(" is a builtin Atmel APB USART\n"); } // FIXME info->usart->cr = 0x1ac; // reset, disable info->usart->idr = 0xffffffff; // disable all interrupts info->usart->tcr = 0; // stop transmit info->usart->rcr = 0; // stop receive interrupts_init(); restore_flags(flags); // hack to do polling serialpoll.routine = serpoll; serialpoll.data = 0; return 0;}module_init(rs_atmel_init);#if 0/* * register_serial and unregister_serial allows for serial ports to be * configured at run-time, to support PCMCIA modems. *//* SPARC: Unused at this time, just here to make things link. */static int register_serial(struct serial_struct *req){ return -1;}static void unregister_serial(int line){ return;}static void dbg_putc(int ch){ static char tmp[2];#define US_TPR (0x38) /* Transmit Pointer Register */#define US_TCR (0x3C) /* Transmit Counter Register */ tmp[0] = ch; outl_t((unsigned long) tmp, (USART0_BASE + US_TPR) ); outl_t(1, (USART0_BASE + US_TCR) ); while (inl_t((USART0_BASE + US_TCR) )) { }}static void dbg_print(const char *str){ const char *p; for (p = str; *p; p++) { if (*p == '\n') { dbg_putc('\r'); } dbg_putc(*p); }}static void dbg_printk(const char *fmt, ...){ char tmp[256]; va_list args; va_start(args, fmt); vsprintf(tmp, fmt, args); va_end(args); dbg_print(tmp);}static void rs_atmel_print(const char *str){ dbg_printk(str);}static void dump_a(unsigned long a, unsigned int s){ unsigned long q; for (q = 0; q < s; q++) { if (q % 16 == 0) { dbg_printk("%08X: ", q + a); } if (q % 16 == 7) { dbg_printk("%02X-", *(unsigned char *) (q + a)); } else { dbg_printk("%02X ", *(unsigned char *) (q + a)); } if (q % 16 == 15) { dbg_printk(" :\n"); } } if (q % 16) { dbg_printk(" :\n"); }}#endifstatic kdev_t atmel_console_device(struct console *c){ return MKDEV(TTY_MAJOR, 64 + c->index);}int atmel_console_setup(void){ HW_AT91_USART_INIT return 0;}void atmel_console_write (struct console *co, const char *str, unsigned int count){ char c; struct atmel_serial *info;#ifdef CONFIG_SWAP_ATMEL_PORTS info = &atmel_info[1];#else info = &atmel_info[0];#endif if (!atmel_console_initialized) { init_console(info); uart_init(info); info->baud = 9600; tx_stop(info->usart); rx_stop(info->usart); uart_speed(info, 0xffff); tx_start(info->usart, info->use_ints); rx_start(info->usart, info->use_ints); } while (count--) { if (*str == '\n') rs_put_char(info,'\r'); rs_put_char(info, *str++ ); }}static struct console atmel_driver = { name: "ttyS", write: atmel_console_write, read: NULL, device: atmel_console_device, wait_key: NULL, unblank: NULL, setup: atmel_console_setup, flags: CON_PRINTBUFFER, index: -1, cflag: 0, next: NULL};void atmel_console_init(void){ register_console(&atmel_driver);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -