/* * Returns the free space inside the ring buffer of this line. * * Should be called while holding line->lock (this does not modify data).
*/ staticunsignedint write_room(struct line *line)
{ int n;
if (line->buffer == NULL) return LINE_BUFSIZE - 1;
/* This is for the case where the buffer is wrapped! */
n = line->head - line->tail;
if (n <= 0)
n += LINE_BUFSIZE; /* The other case */ return n - 1;
}
spin_lock_irqsave(&line->lock, flags); /* write_room subtracts 1 for the needed NULL, so we readd it.*/
ret = LINE_BUFSIZE - (write_room(line) + 1);
spin_unlock_irqrestore(&line->lock, flags);
return ret;
}
/* * This copies the content of buf into the circular buffer associated with * this line. * The return value is the number of characters actually copied, i.e. the ones * for which there was space: this function is not supposed to ever flush out * the circular buffer. * * Must be called while holding line->lock!
*/ staticint buffer_data(struct line *line, const u8 *buf, size_t len)
{ int end, room;
if (len < end) {
memcpy(line->tail, buf, len);
line->tail += len;
} else { /* The circular buffer is wrapping */
memcpy(line->tail, buf, end);
buf += end;
memcpy(line->buffer, buf, len - end);
line->tail = line->buffer + len - end;
}
return len;
}
/* * Flushes the ring buffer to the output channels. That is, write_chan is * called, passing it line->head as buffer, and an appropriate count. * * On exit, returns 1 when the buffer is empty, * 0 when the buffer is not empty on exit, * and -errno when an error occurred. *
* Must be called while holding line->lock!*/ staticint flush_buffer(struct line *line)
{ int n, count;
if ((line->buffer == NULL) || (line->head == line->tail)) return 1;
if (line->tail < line->head) { /* line->buffer + LINE_BUFSIZE is the end of the buffer! */
count = line->buffer + LINE_BUFSIZE - line->head;
n = write_chan(line->chan_out, line->head, count,
line->write_irq); if (n < 0) return n; if (n == count) { /* * We have flushed from ->head to buffer end, now we * must flush only from the beginning to ->tail.
*/
line->head = line->buffer;
} else {
line->head += n; return 0;
}
}
/* * We map both ->flush_chars and ->put_char (which go in pair) onto * ->flush_buffer and ->write. Hope it's not that bad.
*/ void line_flush_chars(struct tty_struct *tty)
{
line_flush_buffer(tty);
}
ssize_t line_write(struct tty_struct *tty, const u8 *buf, size_t len)
{ struct line *line = tty->driver_data; unsignedlong flags; int n, ret = 0;
spin_lock_irqsave(&line->lock, flags); if (line->head != line->tail)
ret = buffer_data(line, buf, len); else {
n = write_chan(line->chan_out, buf, len,
line->write_irq); if (n < 0) {
ret = n; goto out_up;
}
len -= n;
ret += n; if (len > 0)
ret += buffer_data(line, buf + n, len);
}
out_up:
spin_unlock_irqrestore(&line->lock, flags); return ret;
}
void line_throttle(struct tty_struct *tty)
{ struct line *line = tty->driver_data;
void line_hangup(struct tty_struct *tty)
{ struct line *line = tty->driver_data;
tty_port_hangup(&line->port);
}
void close_lines(struct line *lines, int nlines)
{ int i;
for(i = 0; i < nlines; i++)
close_chan(&lines[i]);
}
int setup_one_line(struct line *lines, int n, char *init, conststruct chan_opts *opts, char **error_out)
{ struct line *line = &lines[n]; struct tty_driver *driver = line->driver->driver; int err = -EINVAL;
if (line->port.count) {
*error_out = "Device is already open"; goto out;
}
if (!strcmp(init, "none")) { if (line->valid) {
line->valid = 0;
kfree(line->init_str);
tty_unregister_device(driver, n);
parse_chan_pair(NULL, line, n, opts, error_out);
err = 0;
}
*error_out = "configured as 'none'";
} else { char *new = kstrdup(init, GFP_KERNEL); if (!new) {
*error_out = "Failed to allocate memory"; return -ENOMEM;
} if (line->valid) {
tty_unregister_device(driver, n);
kfree(line->init_str);
}
line->init_str = new;
line->valid = 1;
err = parse_chan_pair(new, line, n, opts, error_out); if (!err) { struct device *d = tty_port_register_device(&line->port,
driver, n, NULL); if (IS_ERR(d)) {
*error_out = "Failed to register device";
err = PTR_ERR(d);
parse_chan_pair(NULL, line, n, opts, error_out);
}
} if (err) {
*error_out = "failed to parse channel pair";
line->init_str = NULL;
line->valid = 0;
kfree(new);
}
}
out: return err;
}
/* * Common setup code for both startup command line and mconsole initialization. * @lines contains the array (of size @num) to modify; * @init is the setup string; * @error_out is an error string in the case of failure;
*/
if (*init == '=') { /* * We said con=/ssl= instead of con#=, so we are configuring all * consoles at once.
*/
*def = init + 1;
} else { char *end; unsigned n = simple_strtoul(init, &end, 0);
if (*end != '=') {
error = "Couldn't parse device number"; goto out;
} if (n >= num) {
error = "Device number out of range"; goto out;
}
conf[n] = end + 1;
} return 0;
out:
printk(KERN_ERR "Failed to set up %s with " "configuration string \"%s\" : %s\n", name, init, error); return -EINVAL;
}
int line_config(struct line *lines, unsignedint num, char *str, conststruct chan_opts *opts, char **error_out)
{ char *end; int n;
if (*str == '=') {
*error_out = "Can't configure all devices from mconsole"; return -EINVAL;
}
n = simple_strtoul(str, &end, 0); if (*end++ != '=') {
*error_out = "Couldn't parse device number"; return -EINVAL;
} if (n >= num) {
*error_out = "Device number out of range"; return -EINVAL;
}
return setup_one_line(lines, n, end, opts, error_out);
}
int line_get_config(char *name, struct line *lines, unsignedint num, char *str, int size, char **error_out)
{ struct line *line; char *end; int dev, n = 0;
dev = simple_strtoul(name, &end, 0); if ((*end != '\0') || (end == name)) {
*error_out = "line_get_config failed to parse device number"; return 0;
}
if ((dev < 0) || (dev >= num)) {
*error_out = "device number out of range"; return 0;
}
line = &lines[dev];
if (!line->valid)
CONFIG_CHUNK(str, size, n, "none", 1); else { struct tty_struct *tty = tty_port_tty_get(&line->port); if (tty == NULL) {
CONFIG_CHUNK(str, size, n, line->init_str, 1);
} else {
n = chan_config_string(line, str, size, error_out);
tty_kref_put(tty);
}
}
return n;
}
int line_id(char **str, int *start_out, int *end_out)
{ char *end; int n;
n = simple_strtoul(*str, &end, 0); if ((*end != '\0') || (end == *str)) return -1;
int line_remove(struct line *lines, unsignedint num, int n, char **error_out)
{ if (n >= num) {
*error_out = "Device number out of range"; return -EINVAL;
} return setup_one_line(lines, n, "none", NULL, error_out);
}
int register_lines(struct line_driver *line_driver, conststruct tty_operations *ops, struct line *lines, int nlines)
{ struct tty_driver *driver; int err; int i;
driver = tty_alloc_driver(nlines, TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV); if (IS_ERR(driver)) return PTR_ERR(driver);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.