📄 trioserial.c
字号:
} 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. */void rs_hangup(struct tty_struct *tty){ struct trio_serial * info = (struct trio_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 trio_serial *info){ struct wait_queue wait = { current, NULL }; 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) { cli(); if (!(info->flags & S_CALLOUT_ACTIVE)) trio_rtsdtr(info, 1); sti(); 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 (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; 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 trio_serial *info; int retval, line; line = MINOR(tty->device) - tty->driver.minor_start; if (line != 0) /* we have exactly one */ return -ENODEV; info = &trio_info[0];#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 */ 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;}extern void register_console(void (*proc)(const char *));#if 0static inline voidrs_cons_check(struct trio_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((trio_cons_chanout != channel) && (trio_cons_chanin != channel)) return; trio_conschan = ss->trio_channel; trio_consinfo = ss; /* Register the console output putchar, if necessary */ if((trio_cons_chanout == channel)) { o = 1; /* double whee.. */ if(!consout_registered) { register_console(trio_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(trio_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_usarta = { rs_interrupta, 0, 0, "usarta", NULL, NULL};static struct irqaction irq_usartb = { rs_interruptb, 0, 0, "usartb", NULL, NULL};extern int setup_arm_irq(int, struct irqaction *);void interrupts_init(void){ setup_arm_irq(IRQ_USARTA, &irq_usarta); setup_arm_irq(IRQ_USARTB, &irq_usartb);}/* rs_init inits the driver */int rs_trio_init(void){ int flags,i; struct trio_serial *info; /* Setup base handler, and timer table. */ init_bh(SERIAL_BH, do_serial_bh); timer_table[RS_TIMER].fn = rs_timer; timer_table[RS_TIMER].expires = 0; /* Initialize the tty_driver structure */ 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; serial_driver.num = 1; 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(); i=0; while(i<US_NB){ info = &trio_info[i]; info->magic = SERIAL_MAGIC; info->uart = uarts[i]; info->tty = 0; info->irqmask = (i)?AIC_UB:AIC_UA; info->irq = (i)?IRQ_USARTB:IRQ_USARTA; info->port = i+1; set_ints_mode(0,info); info->custom_divisor = 16; info->close_delay = 50; info->closing_wait = 3000; 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; info->open_wait = 0; info->close_wait = 0; info->line = 0; info->is_cons = (i)?0:1; /* Means shortcuts work */ i++; } interrupts_init(); restore_flags(flags);// hack to do polling serialpoll.routine = serpoll; serialpoll.data = 0; return 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. */int register_serial(struct serial_struct *req){ return -1;}void unregister_serial(int line){ return;}#if 0/* Hooks for running a serial console. con_init() calls this if the * console is being run over one of the ttya/ttyb serial ports. * 'chip' should be zero, as chip 1 drives the mouse/keyboard. * 'channel' is decoded as 0=TTYA 1=TTYB, note that the channels * are addressed backwards, channel B is first, then channel A. */voidrs_cons_hook(int chip, int out, int channel){ if(chip) panic("rs_cons_hook called with chip not zero"); if(!trio_chips[chip]) { trio_chips[chip] = get_zs(chip); /* Two channels per chip */ trio_channels[(chip*2)] = &trio_chips[chip]->channelA; trio_channels[(chip*2)+1] = &trio_chips[chip]->channelB; } trio_info[channel].trio_channel = trio_channels[channel]; trio_info[channel].change_needed = 0; trio_info[channel].clk_divisor = 16; trio_info[channel].trio_baud = get_zsbaud(&trio_info[channel]); rs_cons_check(&trio_info[channel], channel); if(out) trio_cons_chanout = ((chip * 2) + channel); else trio_cons_chanin = ((chip * 2) + channel);}/* This is called at boot time to prime the kgdb serial debugging * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1 * for /dev/ttyb which is determined in setup_arch() from the * boot command line flags. */voidrs_kgdb_hook(int tty_num){ int chip = 0; if(!trio_chips[chip]) { trio_chips[chip] = get_zs(chip); /* Two channels per chip */ trio_channels[(chip*2)] = &trio_chips[chip]->channelA; trio_channels[(chip*2)+1] = &trio_chips[chip]->channelB; } trio_info[tty_num].trio_channel = trio_channels[tty_num]; trio_kgdbchan = trio_info[tty_num].trio_channel; trio_info[tty_num].change_needed = 0; trio_info[tty_num].clk_divisor = 16; trio_info[tty_num].trio_baud = get_zsbaud(&trio_info[tty_num]); trio_info[tty_num].kgdb_channel = 1; /* This runs kgdb */ trio_info[tty_num ^ 1].kgdb_channel = 0; /* This does not */ /* Turn on transmitter/receiver at 8-bits/char */ kgdb_chaninit(&trio_info[tty_num], 0, 9600); ZS_CLEARERR(trio_kgdbchan); udelay(5); ZS_CLEARFIFO(trio_kgdbchan);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -