📄 macserial.c
字号:
/* * rs_wait_until_sent() --- wait until the transmitter is empty */static void rs_wait_until_sent(struct tty_struct *tty, int timeout){ struct mac_serial *info = (struct mac_serial *) tty->driver_data; unsigned long orig_jiffies, char_time; if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) return;/* printk("rs_wait_until_sent, timeout:%d, tty_stopped:%d, tx_stopped:%d\n", timeout, tty->stopped, info->tx_stopped);*/ orig_jiffies = jiffies; /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check * interval should also be less than the timeout. */ if (info->timeout <= HZ/50) { printk("macserial: invalid info->timeout=%d\n", info->timeout); info->timeout = HZ/50+1; } char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; char_time = char_time / 5; if (char_time > HZ) { printk("macserial: char_time %ld >HZ !!!\n", char_time); char_time = 1; } else if (char_time == 0) char_time = 1; if (timeout) char_time = MIN(char_time, timeout); while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } current->state = TASK_RUNNING;}/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */static void rs_hangup(struct tty_struct *tty){ struct mac_serial * info = (struct mac_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 &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_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 mac_serial *info){ 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 & ZILOG_CLOSING) { interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART return ((info->flags & ZILOG_HUP_NOTIFY) ? -EAGAIN : -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 & ZILOG_NORMAL_ACTIVE) return -EBUSY; if ((info->flags & ZILOG_CALLOUT_ACTIVE) && (info->flags & ZILOG_SESSION_LOCKOUT) && (info->session != current->session)) return -EBUSY; if ((info->flags & ZILOG_CALLOUT_ACTIVE) && (info->flags & ZILOG_PGRP_LOCKOUT) && (info->pgrp != current->pgrp)) return -EBUSY; info->flags |= ZILOG_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 & ZILOG_CALLOUT_ACTIVE) return -EBUSY; info->flags |= ZILOG_NORMAL_ACTIVE; return 0; } if (info->flags & ZILOG_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); OPNDBG("block_til_ready before block: ttys%d, count = %d\n", info->line, info->count); cli(); if (!tty_hung_up_p(filp)) info->count--; sti(); info->blocked_open++; while (1) { cli(); if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && (tty->termios->c_cflag & CBAUD) && !info->is_irda) zs_rtsdtr(info, 1); sti(); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ZILOG_INITIALIZED)) {#ifdef SERIAL_DO_RESTART if (info->flags & ZILOG_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS;#else retval = -EAGAIN;#endif break; } if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && !(info->flags & ZILOG_CLOSING) && (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; } OPNDBG("block_til_ready blocking: ttys%d, count = %d\n", info->line, info->count); schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--; OPNDBG("block_til_ready after blocking: ttys%d, count = %d\n", info->line, info->count); if (retval) return retval; info->flags |= ZILOG_NORMAL_ACTIVE; return 0;}/* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its ZILOG structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */static int rs_open(struct tty_struct *tty, struct file * filp){ struct mac_serial *info; int retval, line; unsigned long page; MOD_INC_USE_COUNT; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= zs_channels_found)) { MOD_DEC_USE_COUNT; return -ENODEV; } info = zs_soft + line;#ifdef CONFIG_KGDB if (info->kgdb_channel) { MOD_DEC_USE_COUNT; return -ENODEV; }#endif if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV; OPNDBG("rs_open %s%d, count = %d\n", tty->driver.name, info->line, info->count); info->count++; tty->driver_data = info; info->tty = tty; if (!tmp_buf) { page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; if (tmp_buf) free_page(page); else tmp_buf = (unsigned char *) page; } /* * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->flags & ZILOG_CLOSING)) { if (info->flags & ZILOG_CLOSING) interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART return ((info->flags & ZILOG_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);#else return -EAGAIN;#endif } /* * Start up serial port */ retval = startup(info, 1); if (retval) return retval; retval = block_til_ready(tty, filp, info); if (retval) { OPNDBG("rs_open returning after block_til_ready with %d\n", retval); return retval; } if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; change_speed(info, 0); }#ifdef CONFIG_SERIAL_CONSOLE if (sercons.cflag && sercons.index == line) { tty->termios->c_cflag = sercons.cflag; sercons.cflag = 0; change_speed(info, 0); }#endif info->session = current->session; info->pgrp = current->pgrp; OPNDBG("rs_open ttys%d successful...\n", info->line); return 0;}/* Finally, routines used to initialize the serial driver. */static void show_serial_version(void){ printk("PowerMac Z8530 serial driver version 2.0\n");}/* * Initialize one channel, both the mac_serial and mac_zschannel * structs. We use the dev_node field of the mac_serial struct. */static voidchan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan, struct mac_zschannel *zs_chan_a){ struct device_node *ch = zss->dev_node; char *conn; int len; struct slot_names_prop { int count; char name[1]; } *slots; zss->irq = ch->intrs[0].line; zss->has_dma = 0;#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA) if (ch->n_addrs >= 3 && ch->n_intrs == 3) zss->has_dma = 1;#endif zss->dma_initted = 0; zs_chan->control = (volatile unsigned char *) ioremap(ch->addrs[0].address, 0x1000); zs_chan->data = zs_chan->control + 0x10; spin_lock_init(&zs_chan->lock); zs_chan->parent = zss; zss->zs_channel = zs_chan; zss->zs_chan_a = zs_chan_a; /* setup misc varariables */ zss->kgdb_channel = 0; zss->is_cobalt_modem = device_is_compatible(ch, "cobalt"); /* XXX tested only with wallstreet PowerBook, should do no harm anyway */ conn = get_property(ch, "AAPL,connector", &len); zss->is_irda = conn && (strcmp(conn, "infrared") == 0); /* 1999 Powerbook G3 has slot-names property instead */ slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len); if (slots && slots->count > 0 && strcmp(slots->name, "IrDA") == 0) zss->is_irda = 1; if (zss->has_dma) { zss->dma_priv = NULL; /* it seems that the last two addresses are the DMA controllers */ zss->tx_dma = (volatile struct dbdma_regs *) ioremap(ch->addrs[ch->n_addrs - 2].address, 0x100); zss->rx = (volatile struct mac_dma *) ioremap(ch->addrs[ch->n_addrs - 1].address, 0x100); zss->tx_dma_irq = ch->intrs[1].line; zss->rx_dma_irq = ch->intrs[2].line; spin_lock_init(&zss->rx_dma_lock); }}/* Ask the PROM how many Z8530s we have and initialize their zs_channels */static voidprobe_sccs(){ struct device_node *dev, *ch; struct mac_serial **pp; int n, chip, nchan; struct mac_zschannel *zs_chan; int chan_a_index; n = 0; pp = &zs_chain; zs_chan = zs_channels; for (dev = find_devices("escc"); dev != 0; dev = dev->next) { nchan = 0; chip = n; if (n >= NUM_CHANNELS) { printk("Sorry, can't use %s: no more channels\n", dev->full_name); continue; } chan_a_index = 0; for (ch = dev->child; ch != 0; ch = ch->sibling) { if (nchan >= 2) { printk(KERN_WARNING "SCC: Only 2 channels per " "chip are supported\n"); break; } if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) { printk("Can't use %s: %d addrs %d intrs\n", ch->full_name, ch->n_addrs, ch->n_intrs); continue; } /* The channel with the higher address will be the A side. */ if (nchan > 0 && ch->addrs[0].address > zs_soft[n-1].dev_node->addrs[0].address) chan_a_index = 1; /* minimal initialization for now */ zs_soft[n].dev_node = ch; *pp = &zs_soft[n]; pp = &zs_soft[n].zs_next; ++nchan; ++n; } if (nchan == 0) continue; /* set up A side */ chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan); ++zs_chan; /* set up B side, if it exists */ if (nchan > 1) chan_init(&zs_soft[chip + 1 - chan_a_index], zs_chan, zs_chan - 1); ++zs_chan; } *pp = 0; zs_channels_found = n;#ifdef CONFIG_PMAC_PBOOK if (n) pmu_register_sleep_notifier(&serial_sleep_notifier);#endif /* CONFIG_PMAC_PBOOK */}/* rs_init inits the driver */int macserial_init(void){ int channel, i; unsigned long flags; struct mac_serial *info; /* Setup base handler, and timer table. */ init_bh(MACSERIAL_BH, do_serial_bh); /* Find out how many Z8530 SCCs we have */ if (zs_chain == 0) probe_sccs(); /* XXX assume it's a powerbook if we have a via-pmu */ is_powerbook = find_devices("via-pmu") != 0; /* Register the interrupt handler for each one */ save_flags(flags); cli(); for (i = 0; i < zs_channels_found; ++i) { if (zs_soft[i].has_dma) { if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0, "SCC-txdma", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", zs_soft[i].tx_dma_irq); disable_irq(zs_soft[i].tx_dma_irq); if (request_irq(zs_soft[i].rx_dma_irq, rs_rxdma_irq, 0, "SCC-rxdma", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", zs_soft[i].rx_dma_irq); disable_irq(zs_soft[i].rx_dma_irq); } if (request_irq(zs_soft[i].irq, rs_interrupt, 0, "SCC", &zs_soft[i])) printk(KERN_ERR "macserial: can't get irq %d\n", zs_soft[i].irq); disable_irq(zs_soft[i].irq); } restore_flags(flags); show_serial_version(); /* Initialize the tty_driver structure */ /* Not all of this is exactly right for us. */ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC;#ifdef CONFIG_DEVFS_FS serial_driver.name = "tts/%d";#else serial_driver.name = "ttyS";#endif /* CONFIG_DEVFS_FS */ serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = zs_channels_found; 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 = B38400 | 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_dr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -