cregit-Linux how code gets into the kernel

Release 4.7 drivers/tty/serial/mux.c

/*
** mux.c:
**      serial driver for the Mux console found in some PA-RISC servers.
**
**      (c) Copyright 2002 Ryan Bradetich
**      (c) Copyright 2002 Hewlett-Packard Company
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This Driver currently only supports the console (port 0) on the MUX.
** Additional work will be needed on this driver to enable the full
** functionality of the MUX.
**
*/

#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/console.h>
#include <linux/delay.h> /* for udelay */
#include <linux/device.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/parisc-device.h>

#if defined(CONFIG_SERIAL_MUX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#include <linux/sysrq.h>

#define SUPPORT_SYSRQ
#endif

#include <linux/serial_core.h>


#define MUX_OFFSET 0x800

#define MUX_LINE_OFFSET 0x80


#define MUX_FIFO_SIZE 255

#define MUX_POLL_DELAY (30 * HZ / 1000)


#define IO_DATA_REG_OFFSET 0x3c

#define IO_DCOUNT_REG_OFFSET 0x40


#define MUX_EOFIFO(status) ((status & 0xF000) == 0xF000)

#define MUX_STATUS(status) ((status & 0xF000) == 0x8000)

#define MUX_BREAK(status) ((status & 0xF000) == 0x2000)


#define MUX_NR 256

static unsigned int port_cnt __read_mostly;

struct mux_port {
	
struct uart_port port;
	
int enabled;
};

static struct mux_port mux_ports[MUX_NR];


static struct uart_driver mux_driver = {
	.owner = THIS_MODULE,
	.driver_name = "ttyB",
	.dev_name = "ttyB",
	.major = MUX_MAJOR,
	.minor = 0,
	.nr = MUX_NR,
};


static struct timer_list mux_timer;


#define UART_PUT_CHAR(p, c) __raw_writel((c), (p)->membase + IO_DATA_REG_OFFSET)

#define UART_GET_FIFO_CNT(p) __raw_readl((p)->membase + IO_DCOUNT_REG_OFFSET)

/**
 * get_mux_port_count - Get the number of available ports on the Mux.
 * @dev: The parisc device.
 *
 * This function is used to determine the number of ports the Mux
 * supports.  The IODC data reports the number of ports the Mux
 * can support, but there are cases where not all the Mux ports
 * are connected.  This function can override the IODC and
 * return the true port count.
 */

static int __init get_mux_port_count(struct parisc_device *dev) { int status; u8 iodc_data[32]; unsigned long bytecnt; /* If this is the built-in Mux for the K-Class (Eole CAP/MUX), * we only need to allocate resources for 1 port since the * other 7 ports are not connected. */ if(dev->id.hversion == 0x15) return 1; status = pdc_iodc_read(&bytecnt, dev->hpa.start, 0, iodc_data, 32); BUG_ON(status != PDC_OK); /* Return the number of ports specified in the iodc data. */ return ((((iodc_data)[4] & 0xf0) >> 4) * 8) + 8; }

Contributors

PersonTokensPropCommitsCommitProp
ryan bradetichryan bradetich8797.75%266.67%
matthew wilcoxmatthew wilcox22.25%133.33%
Total89100.00%3100.00%

/** * mux_tx_empty - Check if the transmitter fifo is empty. * @port: Ptr to the uart_port. * * This function test if the transmitter fifo for the port * described by 'port' is empty. If it is empty, this function * should return TIOCSER_TEMT, otherwise return 0. */
static unsigned int mux_tx_empty(struct uart_port *port) { return UART_GET_FIFO_CNT(port) ? 0 : TIOCSER_TEMT; }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox2090.91%150.00%
ryan bradetichryan bradetich29.09%150.00%
Total22100.00%2100.00%

/** * mux_set_mctrl - Set the current state of the modem control inputs. * @ports: Ptr to the uart_port. * @mctrl: Modem control bits. * * The Serial MUX does not support CTS, DCD or DSR so this function * is ignored. */
static void mux_set_mctrl(struct uart_port *port, unsigned int mctrl) { }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox14100.00%1100.00%
Total14100.00%1100.00%

/** * mux_get_mctrl - Returns the current state of modem control inputs. * @port: Ptr to the uart_port. * * The Serial MUX does not support CTS, DCD or DSR so these lines are * treated as permanently active. */
static unsigned int mux_get_mctrl(struct uart_port *port) { return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox19100.00%1100.00%
Total19100.00%1100.00%

/** * mux_stop_tx - Stop transmitting characters. * @port: Ptr to the uart_port. * * The Serial MUX does not support this function. */
static void mux_stop_tx(struct uart_port *port) { }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox10100.00%1100.00%
Total10100.00%1100.00%

/** * mux_start_tx - Start transmitting characters. * @port: Ptr to the uart_port. * * The Serial Mux does not support this function. */
static void mux_start_tx(struct uart_port *port) { }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox10100.00%1100.00%
Total10100.00%1100.00%

/** * mux_stop_rx - Stop receiving characters. * @port: Ptr to the uart_port. * * The Serial Mux does not support this function. */
static void mux_stop_rx(struct uart_port *port) { }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox10100.00%1100.00%
Total10100.00%1100.00%

/** * mux_break_ctl - Control the transmitssion of a break signal. * @port: Ptr to the uart_port. * @break_state: Raise/Lower the break signal. * * The Serial Mux does not support this function. */
static void mux_break_ctl(struct uart_port *port, int break_state) { }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox13100.00%1100.00%
Total13100.00%1100.00%

/** * mux_write - Write chars to the mux fifo. * @port: Ptr to the uart_port. * * This function writes all the data from the uart buffer to * the mux fifo. */
static void mux_write(struct uart_port *port) { int count; struct circ_buf *xmit = &port->state->xmit; if(port->x_char) { UART_PUT_CHAR(port, port->x_char); port->icount.tx++; port->x_char = 0; return; } if(uart_circ_empty(xmit) || uart_tx_stopped(port)) { mux_stop_tx(port); return; } count = (port->fifosize) - UART_GET_FIFO_CNT(port); do { UART_PUT_CHAR(port, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if(uart_circ_empty(xmit)) break; } while(--count > 0); while(UART_GET_FIFO_CNT(port)) udelay(1); if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); if (uart_circ_empty(xmit)) mux_stop_tx(port); }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox18599.46%266.67%
alan coxalan cox10.54%133.33%
Total186100.00%3100.00%

/** * mux_read - Read chars from the mux fifo. * @port: Ptr to the uart_port. * * This reads all available data from the mux's fifo and pushes * the data to the tty layer. */
static void mux_read(struct uart_port *port) { struct tty_port *tport = &port->state->port; int data; __u32 start_count = port->icount.rx; while(1) { data = __raw_readl(port->membase + IO_DATA_REG_OFFSET); if (MUX_STATUS(data)) continue; if (MUX_EOFIFO(data)) break; port->icount.rx++; if (MUX_BREAK(data)) { port->icount.brk++; if(uart_handle_break(port)) continue; } if (uart_handle_sysrq_char(port, data & 0xffu)) continue; tty_insert_flip_char(tport, data & 0xFF, TTY_NORMAL); } if (start_count != port->icount.rx) tty_flip_buffer_push(tport); }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox11483.21%240.00%
jiri slabyjiri slaby1410.22%240.00%
alan coxalan cox96.57%120.00%
Total137100.00%5100.00%

/** * mux_startup - Initialize the port. * @port: Ptr to the uart_port. * * Grab any resources needed for this port and start the * mux timer. */
static int mux_startup(struct uart_port *port) { mux_ports[port->line].enabled = 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox1560.00%150.00%
ryan bradetichryan bradetich1040.00%150.00%
Total25100.00%2100.00%

/** * mux_shutdown - Disable the port. * @port: Ptr to the uart_port. * * Release any resources needed for the port. */
static void mux_shutdown(struct uart_port *port) { mux_ports[port->line].enabled = 0; }

Contributors

PersonTokensPropCommitsCommitProp
ryan bradetichryan bradetich1359.09%150.00%
matthew wilcoxmatthew wilcox940.91%150.00%
Total22100.00%2100.00%

/** * mux_set_termios - Chane port parameters. * @port: Ptr to the uart_port. * @termios: new termios settings. * @old: old termios settings. * * The Serial Mux does not support this function. */
static void mux_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox1155.00%125.00%
russell kingrussell king735.00%250.00%
alan coxalan cox210.00%125.00%
Total20100.00%4100.00%

/** * mux_type - Describe the port. * @port: Ptr to the uart_port. * * Return a pointer to a string constant describing the * specified port. */
static const char *mux_type(struct uart_port *port) { return "Mux"; }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox16100.00%1100.00%
Total16100.00%1100.00%

/** * mux_release_port - Release memory and IO regions. * @port: Ptr to the uart_port. * * Release any memory and IO region resources currently in use by * the port. */
static void mux_release_port(struct uart_port *port) { }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox10100.00%1100.00%
Total10100.00%1100.00%

/** * mux_request_port - Request memory and IO regions. * @port: Ptr to the uart_port. * * Request any memory and IO region resources required by the port. * If any fail, no resources should be registered when this function * returns, and it should return -EBUSY on failure. */
static int mux_request_port(struct uart_port *port) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox14100.00%1100.00%
Total14100.00%1100.00%

/** * mux_config_port - Perform port autoconfiguration. * @port: Ptr to the uart_port. * @type: Bitmask of required configurations. * * Perform any autoconfiguration steps for the port. This function is * called if the UPF_BOOT_AUTOCONF flag is specified for the port. * [Note: This is required for now because of a bug in the Serial core. * rmk has already submitted a patch to linus, should be available for * 2.5.47.] */
static void mux_config_port(struct uart_port *port, int type) { port->type = PORT_MUX; }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox20100.00%1100.00%
Total20100.00%1100.00%

/** * mux_verify_port - Verify the port information. * @port: Ptr to the uart_port. * @ser: Ptr to the serial information. * * Verify the new serial port information contained within serinfo is * suitable for this port type. */
static int mux_verify_port(struct uart_port *port, struct serial_struct *ser) { if(port->membase == NULL) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox31100.00%1100.00%
Total31100.00%1100.00%

/** * mux_drv_poll - Mux poll function. * @unused: Unused variable * * This function periodically polls the Serial MUX to check for new data. */
static void mux_poll(unsigned long unused) { int i; for(i = 0; i < port_cnt; ++i) { if(!mux_ports[i].enabled) continue; mux_read(&mux_ports[i].port); mux_write(&mux_ports[i].port); } mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox6692.96%375.00%
ryan bradetichryan bradetich57.04%125.00%
Total71100.00%4100.00%

#ifdef CONFIG_SERIAL_MUX_CONSOLE
static void mux_console_write(struct console *co, const char *s, unsigned count) { /* Wait until the FIFO drains. */ while(UART_GET_FIFO_CNT(&mux_ports[0].port)) udelay(1); while(count--) { if(*s == '\n') { UART_PUT_CHAR(&mux_ports[0].port, '\r'); } UART_PUT_CHAR(&mux_ports[0].port, *s++); } }

Contributors

PersonTokensPropCommitsCommitProp
ryan bradetichryan bradetich5263.41%150.00%
matthew wilcoxmatthew wilcox3036.59%150.00%
Total82100.00%2100.00%


static int mux_console_setup(struct console *co, char *options) { return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox18100.00%1100.00%
Total18100.00%1100.00%

static struct console mux_console = { .name = "ttyB", .write = mux_console_write, .device = uart_console_device, .setup = mux_console_setup, .flags = CON_ENABLED | CON_PRINTBUFFER, .index = 0, .data = &mux_driver, }; #define MUX_CONSOLE &mux_console #else #define MUX_CONSOLE NULL #endif static struct uart_ops mux_pops = { .tx_empty = mux_tx_empty, .set_mctrl = mux_set_mctrl, .get_mctrl = mux_get_mctrl, .stop_tx = mux_stop_tx, .start_tx = mux_start_tx, .stop_rx = mux_stop_rx, .break_ctl = mux_break_ctl, .startup = mux_startup, .shutdown = mux_shutdown, .set_termios = mux_set_termios, .type = mux_type, .release_port = mux_release_port, .request_port = mux_request_port, .config_port = mux_config_port, .verify_port = mux_verify_port, }; /** * mux_probe - Determine if the Serial Mux should claim this device. * @dev: The parisc device. * * Deterimine if the Serial Mux should claim this chip (return 0) * or not (return 1). */
static int __init mux_probe(struct parisc_device *dev) { int i, status; int port_count = get_mux_port_count(dev); printk(KERN_INFO "Serial mux driver (%d ports) Revision: 0.6\n", port_count); dev_set_drvdata(&dev->dev, (void *)(long)port_count); request_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET, "Mux"); if(!port_cnt) { mux_driver.cons = MUX_CONSOLE; status = uart_register_driver(&mux_driver); if(status) { printk(KERN_ERR "Serial mux: Unable to register driver.\n"); return 1; } } for(i = 0; i < port_count; ++i, ++port_cnt) { struct uart_port *port = &mux_ports[port_cnt].port; port->iobase = 0; port->mapbase = dev->hpa.start + MUX_OFFSET + (i * MUX_LINE_OFFSET); port->membase = ioremap_nocache(port->mapbase, MUX_LINE_OFFSET); port->iotype = UPIO_MEM; port->type = PORT_MUX; port->irq = 0; port->uartclk = 0; port->fifosize = MUX_FIFO_SIZE; port->ops = &mux_pops; port->flags = UPF_BOOT_AUTOCONF; port->line = port_cnt; /* The port->timeout needs to match what is present in * uart_wait_until_sent in serial_core.c. Otherwise * the time spent in msleep_interruptable will be very * long, causing the appearance of a console hang. */ port->timeout = HZ / 50; spin_lock_init(&port->lock); status = uart_add_one_port(&mux_driver, port); BUG_ON(status); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox19777.25%430.77%
ryan bradetichryan bradetich5521.57%646.15%
russell kingrussell king10.39%17.69%
helge dellerhelge deller10.39%17.69%
alan coxalan cox10.39%17.69%
Total255100.00%13100.00%


static int mux_remove(struct parisc_device *dev) { int i, j; int port_count = (long)dev_get_drvdata(&dev->dev); /* Find Port 0 for this card in the mux_ports list. */ for(i = 0; i < port_cnt; ++i) { if(mux_ports[i].port.mapbase == dev->hpa.start + MUX_OFFSET) break; } BUG_ON(i + port_count > port_cnt); /* Release the resources associated with each port on the device. */ for(j = 0; j < port_count; ++j, ++i) { struct uart_port *port = &mux_ports[i].port; uart_remove_one_port(&mux_driver, port); if(port->membase) iounmap(port->membase); } release_mem_region(dev->hpa.start + MUX_OFFSET, port_count * MUX_LINE_OFFSET); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
ryan bradetichryan bradetich13793.84%350.00%
matthew wilcoxmatthew wilcox96.16%350.00%
Total146100.00%6100.00%

/* Hack. This idea was taken from the 8250_gsc.c on how to properly order * the serial port detection in the proper order. The idea is we always * want the builtin mux to be detected before addin mux cards, so we * specifically probe for the builtin mux cards first. * * This table only contains the parisc_device_id of known builtin mux * devices. All other mux cards will be detected by the generic mux_tbl. */ static struct parisc_device_id builtin_mux_tbl[] = { { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */ { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */ { 0, } }; static struct parisc_device_id mux_tbl[] = { { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D }, { 0, } }; MODULE_DEVICE_TABLE(parisc, builtin_mux_tbl); MODULE_DEVICE_TABLE(parisc, mux_tbl); static struct parisc_driver builtin_serial_mux_driver = { .name = "builtin_serial_mux", .id_table = builtin_mux_tbl, .probe = mux_probe, .remove = mux_remove, }; static struct parisc_driver serial_mux_driver = { .name = "serial_mux", .id_table = mux_tbl, .probe = mux_probe, .remove = mux_remove, }; /** * mux_init - Serial MUX initialization procedure. * * Register the Serial MUX driver. */
static int __init mux_init(void) { register_parisc_driver(&builtin_serial_mux_driver); register_parisc_driver(&serial_mux_driver); if(port_cnt > 0) { /* Start the Mux timer */ init_timer(&mux_timer); mux_timer.function = mux_poll; mod_timer(&mux_timer, jiffies + MUX_POLL_DELAY); #ifdef CONFIG_SERIAL_MUX_CONSOLE register_console(&mux_console); #endif } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
ryan bradetichryan bradetich5177.27%250.00%
matthew wilcoxmatthew wilcox1522.73%250.00%
Total66100.00%4100.00%

/** * mux_exit - Serial MUX cleanup procedure. * * Unregister the Serial MUX driver from the tty layer. */
static void __exit mux_exit(void) { /* Delete the Mux timer. */ if(port_cnt > 0) { del_timer_sync(&mux_timer); #ifdef CONFIG_SERIAL_MUX_CONSOLE unregister_console(&mux_console); #endif } unregister_parisc_driver(&builtin_serial_mux_driver); unregister_parisc_driver(&serial_mux_driver); uart_unregister_driver(&mux_driver); }

Contributors

PersonTokensPropCommitsCommitProp
ryan bradetichryan bradetich2750.94%342.86%
matthew wilcoxmatthew wilcox2241.51%228.57%
amol ladamol lad35.66%114.29%
julia lawalljulia lawall11.89%114.29%
Total53100.00%7100.00%

module_init(mux_init); module_exit(mux_exit); MODULE_AUTHOR("Ryan Bradetich"); MODULE_DESCRIPTION("Serial MUX driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(MUX_MAJOR);

Overall Contributors

PersonTokensPropCommitsCommitProp
matthew wilcoxmatthew wilcox126367.50%618.18%
ryan bradetichryan bradetich53028.33%927.27%
jiri slabyjiri slaby201.07%39.09%
russell kingrussell king130.69%412.12%
alan coxalan cox130.69%412.12%
daniel thompsondaniel thompson100.53%13.03%
andrew mortonandrew morton80.43%13.03%
axel linaxel lin70.37%13.03%
amol ladamol lad30.16%13.03%
helge dellerhelge deller20.11%13.03%
julia lawalljulia lawall10.05%13.03%
joe perchesjoe perches10.05%13.03%
Total1871100.00%33100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}