📄 con3215.c
字号:
raw->count++; } if (!(raw->flags & RAW3215_WORKING)) { raw3215_mk_write_req(raw); /* start or queue request */ raw3215_try_io(raw); } spin_unlock_irqrestore(raw->lock, flags);}/* * Flush routine, it simply sets the flush flag and tries to start * pending IO. */static voidraw3215_flush_buffer(struct raw3215_info *raw){ unsigned long flags; spin_lock_irqsave(raw->lock, flags); if (raw->count > 0) { raw->flags |= RAW3215_FLUSHING; raw3215_try_io(raw); raw->flags &= ~RAW3215_FLUSHING; } spin_unlock_irqrestore(raw->lock, flags);}/* * Fire up a 3215 device. */static intraw3215_startup(struct raw3215_info *raw){ unsigned long flags; if (raw->flags & RAW3215_ACTIVE) return 0; raw->line_pos = 0; raw->flags |= RAW3215_ACTIVE; spin_lock_irqsave(raw->lock, flags); raw3215_try_io(raw); spin_unlock_irqrestore(raw->lock, flags); return 0;}/* * Shutdown a 3215 device. */static voidraw3215_shutdown(struct raw3215_info *raw){ DECLARE_WAITQUEUE(wait, current); unsigned long flags; if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FIXED)) return; /* Wait for outstanding requests, then free irq */ spin_lock_irqsave(raw->lock, flags); if ((raw->flags & RAW3215_WORKING) || raw->queued_write != NULL || raw->queued_read != NULL) { raw->flags |= RAW3215_CLOSING; add_wait_queue(&raw->empty_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); spin_unlock_irqrestore(raw->lock, flags); schedule(); spin_lock_irqsave(raw->lock, flags); remove_wait_queue(&raw->empty_wait, &wait); set_current_state(TASK_RUNNING); raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING); } spin_unlock_irqrestore(raw->lock, flags);}static intraw3215_probe (struct ccw_device *cdev){ struct raw3215_info *raw; int line; raw = kmalloc(sizeof(struct raw3215_info) + RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA); if (raw == NULL) return -ENOMEM; spin_lock(&raw3215_device_lock); for (line = 0; line < NR_3215; line++) { if (!raw3215[line]) { raw3215[line] = raw; break; } } spin_unlock(&raw3215_device_lock); if (line == NR_3215) { kfree(raw); return -ENODEV; } raw->cdev = cdev; raw->lock = get_ccwdev_lock(cdev); raw->inbuf = (char *) raw + sizeof(struct raw3215_info); memset(raw, 0, sizeof(struct raw3215_info)); raw->buffer = (char *) kmalloc(RAW3215_BUFFER_SIZE, GFP_KERNEL|GFP_DMA); if (raw->buffer == NULL) { spin_lock(&raw3215_device_lock); raw3215[line] = 0; spin_unlock(&raw3215_device_lock); kfree(raw); return -ENOMEM; } tasklet_init(&raw->tasklet, (void (*)(unsigned long)) raw3215_tasklet, (unsigned long) raw); init_waitqueue_head(&raw->empty_wait); cdev->dev.driver_data = raw; cdev->handler = raw3215_irq; return 0;}static voidraw3215_remove (struct ccw_device *cdev){ struct raw3215_info *raw; ccw_device_set_offline(cdev); raw = cdev->dev.driver_data; if (raw) { cdev->dev.driver_data = NULL; kfree(raw->buffer); kfree(raw); }}static intraw3215_set_online (struct ccw_device *cdev){ struct raw3215_info *raw; raw = cdev->dev.driver_data; if (!raw) return -ENODEV; return raw3215_startup(raw);}static intraw3215_set_offline (struct ccw_device *cdev){ struct raw3215_info *raw; raw = cdev->dev.driver_data; if (!raw) return -ENODEV; raw3215_shutdown(raw); return 0;}static struct ccw_device_id raw3215_id[] = { { CCW_DEVICE(0x3215, 0) }, { /* end of list */ },};static struct ccw_driver raw3215_ccw_driver = { .name = "3215", .owner = THIS_MODULE, .ids = raw3215_id, .probe = &raw3215_probe, .remove = &raw3215_remove, .set_online = &raw3215_set_online, .set_offline = &raw3215_set_offline,};#ifdef CONFIG_TN3215_CONSOLE/* * Write a string to the 3215 console */static voidcon3215_write(struct console *co, const char *str, unsigned int count){ struct raw3215_info *raw; int i; if (count <= 0) return; raw = raw3215[0]; /* console 3215 is the first one */ while (count > 0) { for (i = 0; i < count; i++) if (str[i] == '\t' || str[i] == '\n') break; raw3215_write(raw, str, i); count -= i; str += i; if (count > 0) { raw3215_putchar(raw, *str); count--; str++; } }}static struct tty_driver *con3215_device(struct console *c, int *index){ *index = c->index; return tty3215_driver;}/* * panic() calls console_unblank before the system enters a * disabled, endless loop. */static voidcon3215_unblank(void){ struct raw3215_info *raw; unsigned long flags; raw = raw3215[0]; /* console 3215 is the first one */ spin_lock_irqsave(raw->lock, flags); raw3215_make_room(raw, RAW3215_BUFFER_SIZE); spin_unlock_irqrestore(raw->lock, flags);}static int __init con3215_consetup(struct console *co, char *options){ return 0;}/* * The console structure for the 3215 console */static struct console con3215 = { .name = "ttyS", .write = con3215_write, .device = con3215_device, .unblank = con3215_unblank, .setup = con3215_consetup, .flags = CON_PRINTBUFFER,};/* * 3215 console initialization code called from console_init(). * NOTE: This is called before kmalloc is available. */static int __initcon3215_init(void){ struct ccw_device *cdev; struct raw3215_info *raw; struct raw3215_req *req; int i; /* Check if 3215 is to be the console */ if (!CONSOLE_IS_3215) return -ENODEV; /* Set the console mode for VM */ if (MACHINE_IS_VM) { cpcmd("TERM CONMODE 3215", NULL, 0, NULL); cpcmd("TERM AUTOCR OFF", NULL, 0, NULL); } /* allocate 3215 request structures */ raw3215_freelist = NULL; spin_lock_init(&raw3215_freelist_lock); for (i = 0; i < NR_3215_REQ; i++) { req = (struct raw3215_req *) alloc_bootmem_low(sizeof(struct raw3215_req)); req->next = raw3215_freelist; raw3215_freelist = req; } cdev = ccw_device_probe_console(); if (!cdev) return -ENODEV; raw3215[0] = raw = (struct raw3215_info *) alloc_bootmem_low(sizeof(struct raw3215_info)); memset(raw, 0, sizeof(struct raw3215_info)); raw->buffer = (char *) alloc_bootmem_low(RAW3215_BUFFER_SIZE); raw->inbuf = (char *) alloc_bootmem_low(RAW3215_INBUF_SIZE); raw->cdev = cdev; raw->lock = get_ccwdev_lock(cdev); cdev->dev.driver_data = raw; cdev->handler = raw3215_irq; raw->flags |= RAW3215_FIXED; tasklet_init(&raw->tasklet, (void (*)(unsigned long)) raw3215_tasklet, (unsigned long) raw); init_waitqueue_head(&raw->empty_wait); /* Request the console irq */ if (raw3215_startup(raw) != 0) { free_bootmem((unsigned long) raw->inbuf, RAW3215_INBUF_SIZE); free_bootmem((unsigned long) raw->buffer, RAW3215_BUFFER_SIZE); free_bootmem((unsigned long) raw, sizeof(struct raw3215_info)); raw3215[0] = NULL; printk("Couldn't find a 3215 console device\n"); return -ENODEV; } register_console(&con3215); return 0;}console_initcall(con3215_init);#endif/* * tty3215_open * * This routine is called whenever a 3215 tty is opened. */static inttty3215_open(struct tty_struct *tty, struct file * filp){ struct raw3215_info *raw; int retval, line; line = tty->index; if ((line < 0) || (line >= NR_3215)) return -ENODEV; raw = raw3215[line]; if (raw == NULL) return -ENODEV; tty->driver_data = raw; raw->tty = tty; tty->low_latency = 0; /* don't use bottom half for pushing chars */ /* * Start up 3215 device */ retval = raw3215_startup(raw); if (retval) return retval; return 0;}/* * tty3215_close() * * This routine is called when the 3215 tty is closed. We wait * for the remaining request to be completed. Then we clean up. */static voidtty3215_close(struct tty_struct *tty, struct file * filp){ struct raw3215_info *raw; raw = (struct raw3215_info *) tty->driver_data; if (raw == NULL || tty->count > 1) return; tty->closing = 1; /* Shutdown the terminal */ raw3215_shutdown(raw); tty->closing = 0; raw->tty = NULL;}/* * Returns the amount of free space in the output buffer. */static inttty3215_write_room(struct tty_struct *tty){ struct raw3215_info *raw; raw = (struct raw3215_info *) tty->driver_data; /* Subtract TAB_STOP_SIZE to allow for a tab, 8 <<< 64K */ if ((RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE) >= 0) return RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE; else return 0;}/* * String write routine for 3215 ttys */static inttty3215_write(struct tty_struct * tty, const unsigned char *buf, int count){ struct raw3215_info *raw; if (!tty) return 0; raw = (struct raw3215_info *) tty->driver_data; raw3215_write(raw, buf, count); return count;}/* * Put character routine for 3215 ttys */static voidtty3215_put_char(struct tty_struct *tty, unsigned char ch){ struct raw3215_info *raw; if (!tty) return; raw = (struct raw3215_info *) tty->driver_data; raw3215_putchar(raw, ch);}static voidtty3215_flush_chars(struct tty_struct *tty){}/* * Returns the number of characters in the output buffer */static inttty3215_chars_in_buffer(struct tty_struct *tty){ struct raw3215_info *raw; raw = (struct raw3215_info *) tty->driver_data; return raw->count;}static voidtty3215_flush_buffer(struct tty_struct *tty){ struct raw3215_info *raw; raw = (struct raw3215_info *) tty->driver_data; raw3215_flush_buffer(raw); tty_wakeup(tty);}/* * Currently we don't have any io controls for 3215 ttys */static inttty3215_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){ if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; switch (cmd) { default: return -ENOIOCTLCMD; } return 0;}/* * Disable reading from a 3215 tty */static voidtty3215_throttle(struct tty_struct * tty){ struct raw3215_info *raw; raw = (struct raw3215_info *) tty->driver_data; raw->flags |= RAW3215_THROTTLED;}/* * Enable reading from a 3215 tty */static voidtty3215_unthrottle(struct tty_struct * tty){ struct raw3215_info *raw; unsigned long flags; raw = (struct raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_THROTTLED) { spin_lock_irqsave(raw->lock, flags); raw->flags &= ~RAW3215_THROTTLED; raw3215_try_io(raw); spin_unlock_irqrestore(raw->lock, flags); }}/* * Disable writing to a 3215 tty */static voidtty3215_stop(struct tty_struct *tty){ struct raw3215_info *raw; raw = (struct raw3215_info *) tty->driver_data; raw->flags |= RAW3215_STOPPED;}/* * Enable writing to a 3215 tty */static voidtty3215_start(struct tty_struct *tty){ struct raw3215_info *raw; unsigned long flags; raw = (struct raw3215_info *) tty->driver_data; if (raw->flags & RAW3215_STOPPED) { spin_lock_irqsave(raw->lock, flags); raw->flags &= ~RAW3215_STOPPED; raw3215_try_io(raw); spin_unlock_irqrestore(raw->lock, flags); }}static struct tty_operations tty3215_ops = { .open = tty3215_open, .close = tty3215_close, .write = tty3215_write, .put_char = tty3215_put_char, .flush_chars = tty3215_flush_chars, .write_room = tty3215_write_room, .chars_in_buffer = tty3215_chars_in_buffer, .flush_buffer = tty3215_flush_buffer, .ioctl = tty3215_ioctl, .throttle = tty3215_throttle, .unthrottle = tty3215_unthrottle, .stop = tty3215_stop, .start = tty3215_start,};/* * 3215 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. */int __inittty3215_init(void){ struct tty_driver *driver; int ret; if (!CONSOLE_IS_3215) return 0; driver = alloc_tty_driver(NR_3215); if (!driver) return -ENOMEM; ret = ccw_driver_register(&raw3215_ccw_driver); if (ret) { put_tty_driver(driver); return ret; } /* * Initialize the tty_driver structure * Entries in tty3215_driver that are NOT initialized: * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc */ driver->owner = THIS_MODULE; driver->driver_name = "tty3215"; driver->name = "ttyS"; driver->major = TTY_MAJOR; driver->minor_start = 64; driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->subtype = SYSTEM_TYPE_TTY; driver->init_termios = tty_std_termios; driver->init_termios.c_iflag = IGNBRK | IGNPAR; driver->init_termios.c_oflag = ONLCR | XTABS; driver->init_termios.c_lflag = ISIG; driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &tty3215_ops); ret = tty_register_driver(driver); if (ret) { printk("Couldn't register tty3215 driver\n"); put_tty_driver(driver); return ret; } tty3215_driver = driver; return 0;}static void __exittty3215_exit(void){ tty_unregister_driver(tty3215_driver); put_tty_driver(tty3215_driver); ccw_driver_unregister(&raw3215_ccw_driver);}module_init(tty3215_init);module_exit(tty3215_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -