hvc_console.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 880 行 · 第 1/2 页
C
880 行
hvc_kick(); return written;}/* * This is actually a contract between the driver and the tty layer outlining * how much write room the driver can guarentee will be sent OR BUFFERED. This * driver MUST honor the return value. */static int hvc_write_room(struct tty_struct *tty){ struct hvc_struct *hp = tty->driver_data; if (!hp) return -1; return N_OUTBUF - hp->n_outbuf;}static int hvc_chars_in_buffer(struct tty_struct *tty){ struct hvc_struct *hp = tty->driver_data; if (!hp) return -1; return hp->n_outbuf;}#define HVC_POLL_READ 0x00000001#define HVC_POLL_WRITE 0x00000002#define HVC_POLL_QUICK 0x00000004static int hvc_poll(struct hvc_struct *hp){ struct tty_struct *tty; int i, n, poll_mask = 0; char buf[N_INBUF] __ALIGNED__; unsigned long flags; int read_total = 0; spin_lock_irqsave(&hp->lock, flags); /* Push pending writes */ if (hp->n_outbuf > 0) hvc_push(hp); /* Reschedule us if still some write pending */ if (hp->n_outbuf > 0) poll_mask |= HVC_POLL_WRITE; /* No tty attached, just skip */ tty = hp->tty; if (tty == NULL) goto bail; /* Now check if we can get data (are we throttled ?) */ if (test_bit(TTY_THROTTLED, &tty->flags)) goto throttled; /* If we aren't interrupt driven and aren't throttled, we always * request a reschedule */ if (hp->irq == NO_IRQ) poll_mask |= HVC_POLL_READ; /* Read data if any */ for (;;) { int count = N_INBUF; if (count > (TTY_FLIPBUF_SIZE - tty->flip.count)) count = TTY_FLIPBUF_SIZE - tty->flip.count; /* If flip is full, just reschedule a later read */ if (count == 0) { poll_mask |= HVC_POLL_READ; break; } n = hvc_get_chars(hp->vtermno, buf, count); if (n <= 0) { /* Hangup the tty when disconnected from host */ if (n == -EPIPE) { spin_unlock_irqrestore(&hp->lock, flags); tty_hangup(tty); spin_lock_irqsave(&hp->lock, flags); } break; } for (i = 0; i < n; ++i) {#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (buf[i] == '\x0f') { /* ^O -- should support a sequence */ sysrq_pressed = 1; continue; } else if (sysrq_pressed) { handle_sysrq(buf[i], NULL, tty); sysrq_pressed = 0; continue; }#endif /* CONFIG_MAGIC_SYSRQ */ tty_insert_flip_char(tty, buf[i], 0); } if (tty->flip.count) tty_schedule_flip(tty); /* * Account for the total amount read in one loop, and if above * 64 bytes, we do a quick schedule loop to let the tty grok the * data and eventually throttle us. */ read_total += n; if (read_total >= 64) { poll_mask |= HVC_POLL_QUICK; break; } } throttled: /* Wakeup write queue if necessary */ if (hp->do_wakeup) { hp->do_wakeup = 0; tty_wakeup(tty); } bail: spin_unlock_irqrestore(&hp->lock, flags); return poll_mask;}#if defined(CONFIG_XMON) && defined(CONFIG_SMP)extern cpumask_t cpus_in_xmon;#elsestatic const cpumask_t cpus_in_xmon = CPU_MASK_NONE;#endif/* * This kthread is either polling or interrupt driven. This is determined by * calling hvc_poll() who determines whether a console adapter support * interrupts. */int khvcd(void *unused){ int poll_mask; struct hvc_struct *hp; __set_current_state(TASK_RUNNING); do { poll_mask = 0; hvc_kicked = 0; wmb(); if (cpus_empty(cpus_in_xmon)) { spin_lock(&hvc_structs_lock); list_for_each_entry(hp, &hvc_structs, next) { /*hp = list_entry(node, struct hvc_struct, * next); */ poll_mask |= hvc_poll(hp); } spin_unlock(&hvc_structs_lock); } else poll_mask |= HVC_POLL_READ; if (hvc_kicked) continue; if (poll_mask & HVC_POLL_QUICK) { yield(); continue; } set_current_state(TASK_INTERRUPTIBLE); if (!hvc_kicked) { if (poll_mask == 0) schedule(); else schedule_timeout(TIMEOUT); } __set_current_state(TASK_RUNNING); } while (!kthread_should_stop()); return 0;}static struct tty_operations hvc_ops = { .open = hvc_open, .close = hvc_close, .write = hvc_write, .hangup = hvc_hangup, .unthrottle = hvc_unthrottle, .write_room = hvc_write_room, .chars_in_buffer = hvc_chars_in_buffer,};char hvc_driver_name[] = "hvc_console";static struct vio_device_id hvc_driver_table[] __devinitdata= { {"serial", "hvterm1"}, { 0, }};MODULE_DEVICE_TABLE(vio, hvc_driver_table);/* callback when the kboject ref count reaches zero. */static void destroy_hvc_struct(struct kobject *kobj){ struct hvc_struct *hp = container_of(kobj, struct hvc_struct, kobj); unsigned long flags; spin_lock(&hvc_structs_lock); spin_lock_irqsave(&hp->lock, flags); list_del(&(hp->next)); spin_unlock_irqrestore(&hp->lock, flags); spin_unlock(&hvc_structs_lock); kfree(hp);}static struct kobj_type hvc_kobj_type = { .release = destroy_hvc_struct,};static int __devinit hvc_probe( struct vio_dev *dev, const struct vio_device_id *id){ struct hvc_struct *hp; /* probed with invalid parameters. */ if (!dev || !id) return -EPERM; hp = kmalloc(sizeof(*hp), GFP_KERNEL); if (!hp) return -ENOMEM; memset(hp, 0x00, sizeof(*hp)); hp->vtermno = dev->unit_address; hp->vdev = dev; hp->vdev->dev.driver_data = hp; hp->irq = dev->irq; kobject_init(&hp->kobj); hp->kobj.ktype = &hvc_kobj_type; hp->lock = SPIN_LOCK_UNLOCKED; spin_lock(&hvc_structs_lock); hp->index = ++hvc_count; list_add_tail(&(hp->next), &hvc_structs); spin_unlock(&hvc_structs_lock); return 0;}static int __devexit hvc_remove(struct vio_dev *dev){ struct hvc_struct *hp = dev->dev.driver_data; unsigned long flags; struct kobject *kobjp; struct tty_struct *tty; spin_lock_irqsave(&hp->lock, flags); tty = hp->tty; kobjp = &hp->kobj; if (hp->index < MAX_NR_HVC_CONSOLES) vtermnos[hp->index] = -1; /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ spin_unlock_irqrestore(&hp->lock, flags); /* * We 'put' the instance that was grabbed when the kobject instance * was intialized using kobject_init(). Let the last holder of this * kobject cause it to be removed, which will probably be the tty_hangup * below. */ kobject_put(kobjp); /* * This function call will auto chain call hvc_hangup. The tty should * always be valid at this time unless a simultaneous tty close already * cleaned up the hvc_struct. */ if (tty) tty_hangup(tty); return 0;}static struct vio_driver hvc_vio_driver = { .name = hvc_driver_name, .id_table = hvc_driver_table, .probe = hvc_probe, .remove = hvc_remove,};/* Driver initialization. Follow console initialization. This is where the TTY * interfaces start to become available. */int __init hvc_init(void){ int rc; /* We need more than num_vterms adapters due to hotplug additions. */ hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); /* hvc_driver = alloc_tty_driver(num_vterms); */ if (!hvc_driver) return -ENOMEM; hvc_driver->owner = THIS_MODULE; hvc_driver->devfs_name = "hvc/"; hvc_driver->driver_name = "hvc"; hvc_driver->name = "hvc"; hvc_driver->major = HVC_MAJOR; hvc_driver->minor_start = HVC_MINOR; hvc_driver->type = TTY_DRIVER_TYPE_SYSTEM; hvc_driver->init_termios = tty_std_termios; hvc_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(hvc_driver, &hvc_ops); if (tty_register_driver(hvc_driver)) panic("Couldn't register hvc console driver\n"); /* Always start the kthread because there can be hotplug vty adapters * added later. */ hvc_task = kthread_run(khvcd, NULL, "khvcd"); if (IS_ERR(hvc_task)) { panic("Couldn't create kthread for console.\n"); put_tty_driver(hvc_driver); return -EIO; } /* Register as a vio device to receive callbacks */ rc = vio_register_driver(&hvc_vio_driver); return rc;}/* This isn't particularily necessary due to this being a console driver but it * is nice to be thorough */static void __exit hvc_exit(void){ kthread_stop(hvc_task); vio_unregister_driver(&hvc_vio_driver); tty_unregister_driver(hvc_driver); /* return tty_struct instances allocated in hvc_init(). */ put_tty_driver(hvc_driver);}/* * Console APIs, NOT TTY. These APIs are available immediately when * hvc_console_setup() finds adapters. *//* * hvc_instantiate() is an early console discovery method which locates consoles * prior to the vio subsystem discovering them. Hotplugged vty adapters do NOT * get an hvc_instantiate() callback since the appear after early console init. */int hvc_instantiate(uint32_t vtermno, int index){ if (index < 0 || index >= MAX_NR_HVC_CONSOLES) return -1; if (vtermnos[index] != -1) return -1; vtermnos[index] = vtermno; return 0;}void hvc_console_print(struct console *co, const char *b, unsigned count){ char c[16] __ALIGNED__; unsigned i = 0, n = 0; int r, donecr = 0; /* Console access attempt outside of acceptable console range. */ if (co->index >= MAX_NR_HVC_CONSOLES) return; /* This console adapter was removed so it is not useable. */ if (vtermnos[co->index] < 0) return; while (count > 0 || i > 0) { if (count > 0 && i < sizeof(c)) { if (b[n] == '\n' && !donecr) { c[i++] = '\r'; donecr = 1; } else { c[i++] = b[n++]; donecr = 0; --count; } } else { r = hvc_put_chars(vtermnos[co->index], c, i); if (r < 0) { /* throw away chars on error */ i = 0; } else if (r > 0) { i -= r; if (i > 0) memmove(c, c+r, i); } } }}static struct tty_driver *hvc_console_device(struct console *c, int *index){ *index = c->index; return hvc_driver;}static int __init hvc_console_setup(struct console *co, char *options){ return 0;}struct console hvc_con_driver = { .name = "hvc", .write = hvc_console_print, .device = hvc_console_device, .setup = hvc_console_setup, .flags = CON_PRINTBUFFER, .index = -1,};/* Early console initialization. Preceeds driver initialization. */static int __init hvc_console_init(void){ int i; for (i=0; i<MAX_NR_HVC_CONSOLES; i++) vtermnos[i] = -1; num_vterms = hvc_find_vtys(); register_console(&hvc_con_driver); return 0;}console_initcall(hvc_console_init);module_init(hvc_init);module_exit(hvc_exit);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?