We need the tty/serial fixes in here as well.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
the driver will use only 32-bit accessors to read/write
the device registers.
+ liteuart,<addr>
+ Start an early console on a litex serial port at the
+ specified address. The serial port must already be
+ setup and configured. Options are not yet supported.
+
meson,<addr>
Start an early, polled-mode console on a meson serial
port at the specified address. The serial port must
- devicetree@vger.kernel.org
allOf:
- - $ref: /schemas/serial.yaml#
+ - $ref: serial.yaml#
- if:
anyOf:
- required:
- const: pclk
- const: baud
+ fifo-size:
+ description: The fifo size supported by the UART channel.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [64, 128]
+
required:
- compatible
- reg
- Al Cooper <alcooperx@gmail.com>
allOf:
- - $ref: /schemas/serial.yaml#
+ - $ref: serial.yaml#
description: |+
The Broadcom UART is based on the basic 8250 UART but with
- Paul Cercueil <paul@crapouillou.net>
allOf:
- - $ref: /schemas/serial.yaml#
+ - $ref: serial.yaml#
properties:
$nodename:
- Rob Herring <robh@kernel.org>
allOf:
- - $ref: /schemas/serial.yaml#
+ - $ref: serial.yaml#
# Need a custom select here or 'arm,primecell' will match on lots of nodes
select:
properties:
compatible:
- oneOf:
- - items:
- - const: arm,pl011
- - const: arm,primecell
- - items:
- - const: arm,primecell
+ items:
+ - const: arm,pl011
+ - const: arm,primecell
reg:
maxItems: 1
poll-rate-ms: [ auto-poll ]
poll-timeout-ms: [ auto-poll ]
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
- Oleksij Rempel <o.rempel@pengutronix.de>
allOf:
- - $ref: /schemas/serial.yaml#
+ - $ref: serial.yaml#
properties:
compatible:
- clocks
- clock-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
- clocks
- clock-names
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
- const: renesas,rcar-gen3-scif # R-Car Gen3 and RZ/G2
- const: renesas,scif # generic SCIF compatible UART
+ - items:
+ - enum:
+ - renesas,scif-r9a07g044 # RZ/G2{L,LC}
+
reg:
maxItems: 1
unevaluatedProperties: false
allOf:
- - $ref: /schemas/serial.yaml#
+ - $ref: serial.yaml#
- if:
properties:
$nodename:
pattern: "^serial(@.*)?$"
+ label: true
+
cts-gpios:
maxItems: 1
description:
- Palmer Dabbelt <palmer@sifive.com>
allOf:
- - $ref: /schemas/serial.yaml#
+ - $ref: serial.yaml#
properties:
compatible:
- interrupts
- clocks
-additionalProperties: false
+unevaluatedProperties: false
examples:
- |
- Rob Herring <robh@kernel.org>
allOf:
- - $ref: /schemas/serial.yaml#
+ - $ref: serial.yaml#
properties:
compatible:
- items:
- enum:
- rockchip,px30-uart
+ - rockchip,rk1808-uart
- rockchip,rk3036-uart
- rockchip,rk3066-uart
- rockchip,rk3188-uart
- rockchip,rk3328-uart
- rockchip,rk3368-uart
- rockchip,rk3399-uart
+ - rockchip,rk3568-uart
- rockchip,rv1108-uart
- const: snps,dw-apb-uart
- items:
- interrupts
- clocks
-additionalProperties:
- type: object
+unevaluatedProperties: false
examples:
- |
- 0x01 - tty->warned is on.
- 0x04 - tty->packed is on.
- - 0x08 - tty->flow_stopped is on.
+ - 0x08 - tty->flow.tco_stopped is on.
- 0x10 - tty->hw_stopped is on.
- - 0x20 - tty->stopped is on.
+ - 0x20 - tty->flow.stopped is on.
* last_tx_msg: Binary blob Prints the last transmitted frame.
F: Documentation/driver-api/serial/
F: drivers/tty/
F: drivers/tty/serial/serial_core.c
+F: include/linux/selection.h
F: include/linux/serial.h
F: include/linux/serial_core.h
-F: include/linux/tty.h
+F: include/linux/sysrq.h
+F: include/linux/tty*.h
+F: include/linux/vt.h
+F: include/linux/vt_*.h
F: include/uapi/linux/serial.h
F: include/uapi/linux/serial_core.h
F: include/uapi/linux/tty.h
return count;
}
-static int
+static unsigned int
srmcons_write_room(struct tty_struct *tty)
{
return 512;
}
-static int
-srmcons_chars_in_buffer(struct tty_struct *tty)
-{
- return 0;
-}
-
static int
srmcons_open(struct tty_struct *tty, struct file *filp)
{
.close = srmcons_close,
.write = srmcons_write,
.write_room = srmcons_write_room,
- .chars_in_buffer= srmcons_chars_in_buffer,
};
static int __init
return 1;
}
-static int nfcon_tty_write_room(struct tty_struct *tty)
+static unsigned int nfcon_tty_write_room(struct tty_struct *tty)
{
return 64;
}
return count;
}
-static int pdc_console_tty_write_room(struct tty_struct *tty)
+static unsigned int pdc_console_tty_write_room(struct tty_struct *tty)
{
return 32768; /* no limit, no buffer used */
}
-static int pdc_console_tty_chars_in_buffer(struct tty_struct *tty)
-{
- return 0; /* no buffer */
-}
-
static const struct tty_operations pdc_console_tty_ops = {
.open = pdc_console_tty_open,
.close = pdc_console_tty_close,
.write = pdc_console_tty_write,
.write_room = pdc_console_tty_write_room,
- .chars_in_buffer = pdc_console_tty_chars_in_buffer,
};
static void pdc_console_poll(struct timer_list *unused)
CONFIG_HW_RANDOM_VIRTIO=m
CONFIG_NVRAM=y
CONFIG_DTLK=m
-CONFIG_R3964=m
CONFIG_CARDMAN_4000=m
CONFIG_CARDMAN_4040=m
CONFIG_IPWIRELESS=m
*
* Should be called while holding line->lock (this does not modify data).
*/
-static int write_room(struct line *line)
+static unsigned int write_room(struct line *line)
{
int n;
return n - 1;
}
-int line_write_room(struct tty_struct *tty)
+unsigned int line_write_room(struct tty_struct *tty)
{
struct line *line = tty->driver_data;
unsigned long flags;
- int room;
+ unsigned int room;
spin_lock_irqsave(&line->lock, flags);
room = write_room(line);
return room;
}
-int line_chars_in_buffer(struct tty_struct *tty)
+unsigned int line_chars_in_buffer(struct tty_struct *tty)
{
struct line *line = tty->driver_data;
unsigned long flags;
- int ret;
+ unsigned int ret;
spin_lock_irqsave(&line->lock, flags);
/* write_room subtracts 1 for the needed NULL, so we readd it.*/
return ret;
}
-void line_set_termios(struct tty_struct *tty, struct ktermios * old)
-{
- /* nothing */
-}
-
void line_throttle(struct tty_struct *tty)
{
struct line *line = tty->driver_data;
char *init, char *name);
extern int line_write(struct tty_struct *tty, const unsigned char *buf,
int len);
-extern void line_set_termios(struct tty_struct *tty, struct ktermios * old);
-extern int line_chars_in_buffer(struct tty_struct *tty);
+extern unsigned int line_chars_in_buffer(struct tty_struct *tty);
extern void line_flush_buffer(struct tty_struct *tty);
extern void line_flush_chars(struct tty_struct *tty);
-extern int line_write_room(struct tty_struct *tty);
+extern unsigned int line_write_room(struct tty_struct *tty);
extern void line_throttle(struct tty_struct *tty);
extern void line_unthrottle(struct tty_struct *tty);
.chars_in_buffer = line_chars_in_buffer,
.flush_buffer = line_flush_buffer,
.flush_chars = line_flush_chars,
- .set_termios = line_set_termios,
.throttle = line_throttle,
.unthrottle = line_unthrottle,
.install = ssl_install,
.chars_in_buffer = line_chars_in_buffer,
.flush_buffer = line_flush_buffer,
.flush_chars = line_flush_chars,
- .set_termios = line_set_termios,
.throttle = line_throttle,
.unthrottle = line_unthrottle,
.hangup = line_hangup,
{
}
-static int rs_write_room(struct tty_struct *tty)
+static unsigned int rs_write_room(struct tty_struct *tty)
{
/* Let's say iss can always accept 2K characters.. */
return 2 * 1024;
}
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
- /* the iss doesn't buffer characters */
- return 0;
-}
-
static void rs_hangup(struct tty_struct *tty)
{
/* Stub, once again.. */
.put_char = rs_put_char,
.flush_chars = rs_flush_chars,
.write_room = rs_write_room,
- .chars_in_buffer = rs_chars_in_buffer,
.hangup = rs_hangup,
.wait_until_sent = rs_wait_until_sent,
.proc_show = rs_proc_show,
}
static int spk_ttyio_receive_buf2(struct tty_struct *tty,
- const unsigned char *cp, char *fp, int count)
+ const unsigned char *cp,
+ const char *fp, int count)
{
struct spk_ldisc_data *ldisc_data = tty->disc_data;
struct spk_synth *synth = ldisc_data->synth;
static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
.owner = THIS_MODULE,
+ .num = N_SPEAKUP,
.name = "speakup_ldisc",
.open = spk_ttyio_ldisc_open,
.close = spk_ttyio_ldisc_close,
void spk_ttyio_register_ldisc(void)
{
- if (tty_register_ldisc(N_SPEAKUP, &spk_ttyio_ldisc_ops))
+ if (tty_register_ldisc(&spk_ttyio_ldisc_ops))
pr_warn("speakup: Error registering line discipline. Most synths won't work.\n");
}
void spk_ttyio_unregister_ldisc(void)
{
- if (tty_unregister_ldisc(N_SPEAKUP))
- pr_warn("speakup: Couldn't unregister ldisc\n");
+ tty_unregister_ldisc(&spk_ttyio_ldisc_ops);
}
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
* Return Value: None
*/
static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
- char *flags, int count)
+ const char *flags, int count)
{
struct hci_uart *hu = tty->disc_data;
static struct tty_ldisc_ops hci_uart_ldisc = {
.owner = THIS_MODULE,
+ .num = N_HCI,
.name = "n_hci",
.open = hci_uart_tty_open,
.close = hci_uart_tty_close,
BT_INFO("HCI UART driver ver %s", VERSION);
/* Register the tty discipline */
- err = tty_register_ldisc(N_HCI, &hci_uart_ldisc);
+ err = tty_register_ldisc(&hci_uart_ldisc);
if (err) {
BT_ERR("HCI line discipline registration failed. (%d)", err);
return err;
static void __exit hci_uart_exit(void)
{
- int err;
-
#ifdef CONFIG_BT_HCIUART_H4
h4_deinit();
#endif
mrvl_deinit();
#endif
- /* Release tty registration of line discipline */
- err = tty_unregister_ldisc(N_HCI);
- if (err)
- BT_ERR("Can't unregister HCI line discipline (%d)", err);
+ tty_unregister_ldisc(&hci_uart_ldisc);
}
module_init(hci_uart_init);
If unsure, say N.
-config R3964
- tristate "Siemens R3964 line discipline"
- depends on TTY && BROKEN
- help
- This driver allows synchronous communication with devices using the
- Siemens R3964 packet protocol. Unless you are dealing with special
- hardware like PLCs, you are unlikely to need this.
-
- To compile this driver as a module, choose M here: the
- module will be called n_r3964.
-
- If unsure, say N.
-
config APPLICOM
tristate "Applicom intelligent fieldbus card support"
depends on PCI
else
#endif
{
- if (tty && (tty->stopped || tty->hw_stopped)) {
+ if (tty && (tty->flow.stopped || tty->hw_stopped)) {
tx_stop(info);
return;
}
if (!info->tx_active)
return;
} else {
- if (tty && (tty->stopped || tty->hw_stopped)) {
+ if (tty && (tty->flow.stopped || tty->hw_stopped)) {
tx_stop(info);
return;
}
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars"))
return;
- if (info->tx_count <= 0 || tty->stopped ||
+ if (info->tx_count <= 0 || tty->flow.stopped ||
tty->hw_stopped || !info->tx_buf)
return;
ret += c;
}
start:
- if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
+ if (info->tx_count && !tty->flow.stopped && !tty->hw_stopped) {
spin_lock_irqsave(&info->lock, flags);
if (!info->tx_active)
tx_start(info, tty);
/* Return the count of free bytes in transmit buffer
*/
-static int mgslpc_write_room(struct tty_struct *tty)
+static unsigned int mgslpc_write_room(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
int ret;
/* Return the count of bytes in transmit buffer
*/
-static int mgslpc_chars_in_buffer(struct tty_struct *tty)
+static unsigned int mgslpc_chars_in_buffer(struct tty_struct *tty)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
- int rc;
+ unsigned int rc;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgslpc_chars_in_buffer(%s)\n",
rc = info->tx_count;
if (debug_level >= DEBUG_LEVEL_INFO)
- printk("%s(%d):mgslpc_chars_in_buffer(%s)=%d\n",
+ printk("%s(%d):mgslpc_chars_in_buffer(%s)=%u\n",
__FILE__, __LINE__, info->device_name, rc);
return rc;
static int tpk_printk(const unsigned char *buf, int count)
{
- int i = tpk_curr;
-
- if (buf == NULL) {
- tpk_flush();
- return i;
- }
+ int i;
for (i = 0; i < count; i++) {
if (tpk_curr >= TPK_STR_SIZE) {
static void tpk_close(struct tty_struct *tty, struct file *filp)
{
struct ttyprintk_port *tpkp = tty->driver_data;
- unsigned long flags;
-
- spin_lock_irqsave(&tpkp->spinlock, flags);
- /* flush tpk_printk buffer */
- tpk_printk(NULL, 0);
- spin_unlock_irqrestore(&tpkp->spinlock, flags);
tty_port_close(&tpkp->port, tty, filp);
}
unsigned long flags;
int ret;
-
/* exclusive use of tpk_printk within this tty */
spin_lock_irqsave(&tpkp->spinlock, flags);
ret = tpk_printk(buf, count);
/*
* TTY operations write_room function.
*/
-static int tpk_write_room(struct tty_struct *tty)
+static unsigned int tpk_write_room(struct tty_struct *tty)
{
return TPK_MAX_ROOM;
}
/*
- * TTY operations ioctl function.
+ * TTY operations hangup function.
*/
-static int tpk_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
+static void tpk_hangup(struct tty_struct *tty)
{
struct ttyprintk_port *tpkp = tty->driver_data;
- if (!tpkp)
- return -EINVAL;
-
- switch (cmd) {
- /* Stop TIOCCONS */
- case TIOCCONS:
- return -EOPNOTSUPP;
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
+ tty_port_hangup(&tpkp->port);
}
/*
- * TTY operations hangup function.
+ * TTY port operations shutdown function.
*/
-static void tpk_hangup(struct tty_struct *tty)
+static void tpk_port_shutdown(struct tty_port *tport)
{
- struct ttyprintk_port *tpkp = tty->driver_data;
+ struct ttyprintk_port *tpkp =
+ container_of(tport, struct ttyprintk_port, port);
+ unsigned long flags;
- tty_port_hangup(&tpkp->port);
+ spin_lock_irqsave(&tpkp->spinlock, flags);
+ tpk_flush();
+ spin_unlock_irqrestore(&tpkp->spinlock, flags);
}
static const struct tty_operations ttyprintk_ops = {
.close = tpk_close,
.write = tpk_write,
.write_room = tpk_write_room,
- .ioctl = tpk_ioctl,
.hangup = tpk_hangup,
};
-static const struct tty_port_operations null_ops = { };
+static const struct tty_port_operations tpk_port_ops = {
+ .shutdown = tpk_port_shutdown,
+};
static struct tty_driver *ttyprintk_driver;
return PTR_ERR(ttyprintk_driver);
tty_port_init(&tpk_port.port);
- tpk_port.port.ops = &null_ops;
+ tpk_port.port.ops = &tpk_port_ops;
ttyprintk_driver->driver_name = "ttyprintk";
ttyprintk_driver->name = "ttyprintk";
* 'interrupt' routine.
*/
-static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+static void serport_ldisc_receive(struct tty_struct *tty,
+ const unsigned char *cp, const char *fp, int count)
{
struct serport *serport = (struct serport*) tty->disc_data;
unsigned long flags;
static struct tty_ldisc_ops serport_ldisc = {
.owner = THIS_MODULE,
+ .num = N_MOUSE,
.name = "input",
.open = serport_ldisc_open,
.close = serport_ldisc_close,
static int __init serport_init(void)
{
int retval;
- retval = tty_register_ldisc(N_MOUSE, &serport_ldisc);
+ retval = tty_register_ldisc(&serport_ldisc);
if (retval)
printk(KERN_ERR "serport.c: Error registering line discipline.\n");
static void __exit serport_exit(void)
{
- tty_unregister_ldisc(N_MOUSE);
+ tty_unregister_ldisc(&serport_ldisc);
}
module_init(serport_init);
return char_copied;
}
-static int ipoctal_write_room(struct tty_struct *tty)
+static unsigned int ipoctal_write_room(struct tty_struct *tty)
{
struct ipoctal_channel *channel = tty->driver_data;
return PAGE_SIZE - channel->nb_bytes;
}
-static int ipoctal_chars_in_buffer(struct tty_struct *tty)
+static unsigned int ipoctal_chars_in_buffer(struct tty_struct *tty)
{
struct ipoctal_channel *channel = tty->driver_data;
struct capiminor *mp = tty->driver_data;
struct sk_buff *skb;
- pr_debug("capinc_tty_flush_chars\n");
-
spin_lock_bh(&mp->outlock);
skb = mp->outskb;
if (skb) {
handle_minor_recv(mp);
}
-static int capinc_tty_write_room(struct tty_struct *tty)
+static unsigned int capinc_tty_write_room(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
- int room;
+ unsigned int room;
room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
room *= CAPI_MAX_BLKSIZE;
- pr_debug("capinc_tty_write_room = %d\n", room);
+ pr_debug("capinc_tty_write_room = %u\n", room);
return room;
}
-static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int capinc_tty_chars_in_buffer(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
return mp->outbytes;
}
-static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
- pr_debug("capinc_tty_set_termios\n");
-}
-
static void capinc_tty_throttle(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
- pr_debug("capinc_tty_throttle\n");
mp->ttyinstop = 1;
}
{
struct capiminor *mp = tty->driver_data;
- pr_debug("capinc_tty_unthrottle\n");
mp->ttyinstop = 0;
handle_minor_recv(mp);
}
{
struct capiminor *mp = tty->driver_data;
- pr_debug("capinc_tty_stop\n");
mp->ttyoutstop = 1;
}
{
struct capiminor *mp = tty->driver_data;
- pr_debug("capinc_tty_start\n");
mp->ttyoutstop = 0;
handle_minor_send(mp);
}
{
struct capiminor *mp = tty->driver_data;
- pr_debug("capinc_tty_hangup\n");
tty_port_hangup(&mp->port);
}
-static int capinc_tty_break_ctl(struct tty_struct *tty, int state)
-{
- pr_debug("capinc_tty_break_ctl(%d)\n", state);
- return 0;
-}
-
-static void capinc_tty_flush_buffer(struct tty_struct *tty)
-{
- pr_debug("capinc_tty_flush_buffer\n");
-}
-
-static void capinc_tty_set_ldisc(struct tty_struct *tty)
-{
- pr_debug("capinc_tty_set_ldisc\n");
-}
-
static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
{
pr_debug("capinc_tty_send_xchar(%d)\n", ch);
.flush_chars = capinc_tty_flush_chars,
.write_room = capinc_tty_write_room,
.chars_in_buffer = capinc_tty_chars_in_buffer,
- .set_termios = capinc_tty_set_termios,
.throttle = capinc_tty_throttle,
.unthrottle = capinc_tty_unthrottle,
.stop = capinc_tty_stop,
.start = capinc_tty_start,
.hangup = capinc_tty_hangup,
- .break_ctl = capinc_tty_break_ctl,
- .flush_buffer = capinc_tty_flush_buffer,
- .set_ldisc = capinc_tty_set_ldisc,
.send_xchar = capinc_tty_send_xchar,
.install = capinc_tty_install,
.cleanup = capinc_tty_cleanup,
return count;
}
-static int bcm_vk_tty_write_room(struct tty_struct *tty)
+static unsigned int bcm_vk_tty_write_room(struct tty_struct *tty)
{
struct bcm_vk *vk = dev_get_drvdata(tty->dev);
*/
int st_get_uart_wr_room(struct st_data_s *st_gdata)
{
- struct tty_struct *tty;
if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) {
pr_err("tty unavailable to perform write");
return -1;
}
- tty = st_gdata->tty;
- return tty->ops->write_room(tty);
+
+ return tty_write_room(st_gdata->tty);
}
/*
}
static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
- char *tty_flags, int count)
+ const char *tty_flags, int count)
{
#ifdef VERBOSE
print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
}
static struct tty_ldisc_ops st_ldisc_ops = {
+ .num = N_TI_WL,
.name = "n_st",
.open = st_tty_open,
.close = st_tty_close,
struct st_data_s *st_gdata;
long err;
- err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops);
+ err = tty_register_ldisc(&st_ldisc_ops);
if (err) {
pr_err("error registering %d line discipline %ld",
N_TI_WL, err);
st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL);
if (!st_gdata) {
pr_err("memory allocation failed");
- err = tty_unregister_ldisc(N_TI_WL);
- if (err)
- pr_err("unable to un-register ldisc %ld", err);
err = -ENOMEM;
- return err;
+ goto err_unreg_ldisc;
}
/* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's
err = st_ll_init(st_gdata);
if (err) {
pr_err("error during st_ll initialization(%ld)", err);
- kfree(st_gdata);
- err = tty_unregister_ldisc(N_TI_WL);
- if (err)
- pr_err("unable to un-register ldisc");
- return err;
+ goto err_free_gdata;
}
INIT_WORK(&st_gdata->work_write_wakeup, work_fn_write_wakeup);
*core_data = st_gdata;
return 0;
+err_free_gdata:
+ kfree(st_gdata);
+err_unreg_ldisc:
+ tty_unregister_ldisc(&st_ldisc_ops);
+ return err;
}
void st_core_exit(struct st_data_s *st_gdata)
kfree_skb(st_gdata->rx_skb);
kfree_skb(st_gdata->tx_skb);
/* TTY ldisc cleanup */
- err = tty_unregister_ldisc(N_TI_WL);
- if (err)
- pr_err("unable to un-register ldisc %ld", err);
+ tty_unregister_ldisc(&st_ldisc_ops);
/* free the global data pointer */
kfree(st_gdata);
}
tty = tty_port_tty_get(&port->port);
if (tty == NULL || !kfifo_len(xmit) ||
- tty->stopped || tty->hw_stopped) {
+ tty->flow.stopped || tty->hw_stopped) {
sdio_uart_stop_tx(port);
tty_kref_put(tty);
return;
return ret;
}
-static int sdio_uart_write_room(struct tty_struct *tty)
+static unsigned int sdio_uart_write_room(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
return FIFO_SIZE - kfifo_len(&port->xmit_fifo);
}
-static int sdio_uart_chars_in_buffer(struct tty_struct *tty)
+static unsigned int sdio_uart_chars_in_buffer(struct tty_struct *tty)
{
struct sdio_uart_port *port = tty->driver_data;
return kfifo_len(&port->xmit_fifo);
static inline void update_tty_status(struct ser_device *ser)
{
ser->tty_status =
- ser->tty->stopped << 5 |
- ser->tty->flow_stopped << 3 |
- ser->tty->packet << 2;
+ ser->tty->flow.stopped << 5 |
+ ser->tty->flow.tco_stopped << 3 |
+ ser->tty->ctrl.packet << 2;
}
static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
{
#endif
static void ldisc_receive(struct tty_struct *tty, const u8 *data,
- char *flags, int count)
+ const char *flags, int count)
{
struct sk_buff *skb = NULL;
struct ser_device *ser;
/* The line discipline structure. */
static struct tty_ldisc_ops caif_ldisc = {
.owner = THIS_MODULE,
+ .num = N_CAIF,
.name = "n_caif",
.open = ldisc_open,
.close = ldisc_close,
{
int ret;
- ret = tty_register_ldisc(N_CAIF, &caif_ldisc);
+ ret = tty_register_ldisc(&caif_ldisc);
if (ret < 0)
pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF, ret);
spin_unlock(&ser_lock);
ser_release(NULL);
cancel_work_sync(&ser_release_work);
- tty_unregister_ldisc(N_CAIF);
+ tty_unregister_ldisc(&caif_ldisc);
debugfs_remove_recursive(debugfsdir);
}
*/
static void slcan_receive_buf(struct tty_struct *tty,
- const unsigned char *cp, char *fp, int count)
+ const unsigned char *cp, const char *fp,
+ int count)
{
struct slcan *sl = (struct slcan *) tty->disc_data;
static struct tty_ldisc_ops slc_ldisc = {
.owner = THIS_MODULE,
+ .num = N_SLCAN,
.name = "slcan",
.open = slcan_open,
.close = slcan_close,
return -ENOMEM;
/* Fill in our line protocol discipline, and register it */
- status = tty_register_ldisc(N_SLCAN, &slc_ldisc);
+ status = tty_register_ldisc(&slc_ldisc);
if (status) {
printk(KERN_ERR "slcan: can't register line discipline\n");
kfree(slcan_devs);
kfree(slcan_devs);
slcan_devs = NULL;
- i = tty_unregister_ldisc(N_SLCAN);
- if (i)
- printk(KERN_ERR "slcan: can't unregister ldisc (err %d)\n", i);
+ tty_unregister_ldisc(&slc_ldisc);
}
module_init(slcan_init);
* and sent on to some IP layer for further processing.
*/
static void sixpack_receive_buf(struct tty_struct *tty,
- const unsigned char *cp, char *fp, int count)
+ const unsigned char *cp, const char *fp, int count)
{
struct sixpack *sp;
int count1;
static struct tty_ldisc_ops sp_ldisc = {
.owner = THIS_MODULE,
+ .num = N_6PACK,
.name = "6pack",
.open = sixpack_open,
.close = sixpack_close,
printk(msg_banner);
/* Register the provided line protocol discipline */
- if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0)
+ status = tty_register_ldisc(&sp_ldisc);
+ if (status)
printk(msg_regfail, status);
return status;
}
-static const char msg_unregfail[] = KERN_ERR \
- "6pack: can't unregister line discipline (err = %d)\n";
-
static void __exit sixpack_exit_driver(void)
{
- int ret;
-
- if ((ret = tty_unregister_ldisc(N_6PACK)))
- printk(msg_unregfail, ret);
+ tty_unregister_ldisc(&sp_ldisc);
}
/* encode an AX.25 packet into 6pack */
* and sent on to the AX.25 layer for further processing.
*/
static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct mkiss *ax = mkiss_get(tty);
static struct tty_ldisc_ops ax_ldisc = {
.owner = THIS_MODULE,
+ .num = N_AX25,
.name = "mkiss",
.open = mkiss_open,
.close = mkiss_close,
printk(banner);
- status = tty_register_ldisc(N_AX25, &ax_ldisc);
+ status = tty_register_ldisc(&ax_ldisc);
if (status != 0)
printk(msg_regfail, status);
return status;
}
-static const char msg_unregfail[] = KERN_ERR \
- "mkiss: can't unregister line discipline (err = %d)\n";
-
static void __exit mkiss_exit_driver(void)
{
- int ret;
-
- if ((ret = tty_unregister_ldisc(N_AX25)))
- printk(msg_unregfail, ret);
+ tty_unregister_ldisc(&ax_ldisc);
}
MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>");
static int ppp_async_push(struct asyncppp *ap);
static void ppp_async_flush_output(struct asyncppp *ap);
static void ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
- char *flags, int count);
+ const char *flags, int count);
static int ppp_async_ioctl(struct ppp_channel *chan, unsigned int cmd,
unsigned long arg);
static void ppp_async_process(struct tasklet_struct *t);
/* May sleep, don't call from interrupt level or with interrupts disabled */
static void
ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
- char *cflags, int count)
+ const char *cflags, int count)
{
struct asyncppp *ap = ap_get(tty);
unsigned long flags;
static struct tty_ldisc_ops ppp_ldisc = {
.owner = THIS_MODULE,
+ .num = N_PPP,
.name = "ppp",
.open = ppp_asynctty_open,
.close = ppp_asynctty_close,
{
int err;
- err = tty_register_ldisc(N_PPP, &ppp_ldisc);
+ err = tty_register_ldisc(&ppp_ldisc);
if (err != 0)
printk(KERN_ERR "PPP_async: error %d registering line disc.\n",
err);
static void
ppp_async_input(struct asyncppp *ap, const unsigned char *buf,
- char *flags, int count)
+ const char *flags, int count)
{
struct sk_buff *skb;
int c, i, j, n, s, f;
static void __exit ppp_async_cleanup(void)
{
- if (tty_unregister_ldisc(N_PPP) != 0)
- printk(KERN_ERR "failed to unregister PPP line discipline\n");
+ tty_unregister_ldisc(&ppp_ldisc);
}
module_init(ppp_async_init);
static int ppp_sync_push(struct syncppp *ap);
static void ppp_sync_flush_output(struct syncppp *ap);
static void ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
- char *flags, int count);
+ const char *flags, int count);
static const struct ppp_channel_ops sync_ops = {
.start_xmit = ppp_sync_send,
/* May sleep, don't call from interrupt level or with interrupts disabled */
static void
ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
- char *cflags, int count)
+ const char *cflags, int count)
{
struct syncppp *ap = sp_get(tty);
unsigned long flags;
static struct tty_ldisc_ops ppp_sync_ldisc = {
.owner = THIS_MODULE,
+ .num = N_SYNC_PPP,
.name = "pppsync",
.open = ppp_sync_open,
.close = ppp_sync_close,
{
int err;
- err = tty_register_ldisc(N_SYNC_PPP, &ppp_sync_ldisc);
+ err = tty_register_ldisc(&ppp_sync_ldisc);
if (err != 0)
printk(KERN_ERR "PPP_sync: error %d registering line disc.\n",
err);
*/
static void
ppp_sync_input(struct syncppp *ap, const unsigned char *buf,
- char *flags, int count)
+ const char *flags, int count)
{
struct sk_buff *skb;
unsigned char *p;
static void __exit
ppp_sync_cleanup(void)
{
- if (tty_unregister_ldisc(N_SYNC_PPP) != 0)
- printk(KERN_ERR "failed to unregister Sync PPP line discipline\n");
+ tty_unregister_ldisc(&ppp_sync_ldisc);
}
module_init(ppp_sync_init);
*/
static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct slip *sl = tty->disc_data;
static struct tty_ldisc_ops sl_ldisc = {
.owner = THIS_MODULE,
+ .num = N_SLIP,
.name = "slip",
.open = slip_open,
.close = slip_close,
return -ENOMEM;
/* Fill in our line protocol discipline, and register it */
- status = tty_register_ldisc(N_SLIP, &sl_ldisc);
+ status = tty_register_ldisc(&sl_ldisc);
if (status != 0) {
printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status);
kfree(slip_devs);
kfree(slip_devs);
slip_devs = NULL;
- i = tty_unregister_ldisc(N_SLIP);
- if (i != 0)
- printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i);
+ tty_unregister_ldisc(&sl_ldisc);
}
module_init(slip_init);
}
/* how much room is there for writing */
-static int hso_serial_write_room(struct tty_struct *tty)
+static unsigned int hso_serial_write_room(struct tty_struct *tty)
{
struct hso_serial *serial = tty->driver_data;
- int room;
+ unsigned int room;
unsigned long flags;
spin_lock_irqsave(&serial->serial_lock, flags);
}
/* how many characters in the buffer */
-static int hso_serial_chars_in_buffer(struct tty_struct *tty)
+static unsigned int hso_serial_chars_in_buffer(struct tty_struct *tty)
{
struct hso_serial *serial = tty->driver_data;
- int chars;
unsigned long flags;
+ unsigned int chars;
/* sanity check */
if (serial == NULL)
/* Init PPS_TTY data */
pps_ldisc_ops.owner = THIS_MODULE;
+ pps_ldisc_ops.num = N_PPS;
pps_ldisc_ops.name = "pps_tty";
pps_ldisc_ops.dcd_change = pps_tty_dcd_change;
pps_ldisc_ops.open = pps_tty_open;
pps_ldisc_ops.close = pps_tty_close;
- err = tty_register_ldisc(N_PPS, &pps_ldisc_ops);
+ err = tty_register_ldisc(&pps_ldisc_ops);
if (err)
pr_err("can't register PPS line discipline\n");
else
static void __exit pps_tty_cleanup(void)
{
- int err;
-
- err = tty_unregister_ldisc(N_PPS);
- if (err)
- pr_err("can't unregister PPS line discipline\n");
- else
- pr_info("PPS line discipline removed\n");
+ tty_unregister_ldisc(&pps_ldisc_ops);
}
module_init(pps_tty_init);
/*
* Returns the amount of free space in the output buffer.
*/
-static int tty3215_write_room(struct tty_struct *tty)
+static unsigned int tty3215_write_room(struct tty_struct *tty)
{
struct raw3215_info *raw = tty->driver_data;
/*
* Returns the number of characters in the output buffer
*/
-static int tty3215_chars_in_buffer(struct tty_struct *tty)
+static unsigned int tty3215_chars_in_buffer(struct tty_struct *tty)
{
struct raw3215_info *raw = tty->driver_data;
/*
* Return number of characters in buffer
*/
-int
+unsigned int
sclp_chars_in_buffer(struct sclp_buffer *buffer)
{
- int count;
+ unsigned int count;
count = buffer->char_sum;
if (buffer->current_line != NULL)
int sclp_buffer_space(struct sclp_buffer *);
int sclp_write(struct sclp_buffer *buffer, const unsigned char *, int);
int sclp_emit_buffer(struct sclp_buffer *,void (*)(struct sclp_buffer *,int));
-int sclp_chars_in_buffer(struct sclp_buffer *);
+unsigned int sclp_chars_in_buffer(struct sclp_buffer *);
#ifdef CONFIG_SCLP_CONSOLE
void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event);
* a string of newlines. Every newline creates a new message which
* needs 82 bytes.
*/
-static int
+static unsigned int
sclp_tty_write_room (struct tty_struct *tty)
{
unsigned long flags;
struct list_head *l;
- int count;
+ unsigned int count;
spin_lock_irqsave(&sclp_tty_lock, flags);
count = 0;
* characters in the write buffer (will not be written as long as there is a
* final line feed missing).
*/
-static int
+static unsigned int
sclp_tty_chars_in_buffer(struct tty_struct *tty)
{
unsigned long flags;
struct list_head *l;
struct sclp_buffer *t;
- int count;
+ unsigned int count = 0;
spin_lock_irqsave(&sclp_tty_lock, flags);
- count = 0;
if (sclp_ttybuf != NULL)
count = sclp_chars_in_buffer(sclp_ttybuf);
list_for_each(l, &sclp_tty_outqueue) {
* to change as output buffers get emptied, or if the output flow
* control is acted.
*/
-static int
+static unsigned int
sclp_vt220_write_room(struct tty_struct *tty)
{
unsigned long flags;
struct list_head *l;
- int count;
+ unsigned int count;
spin_lock_irqsave(&sclp_vt220_lock, flags);
count = 0;
/*
* Return number of buffered chars.
*/
-static int
+static unsigned int
sclp_vt220_chars_in_buffer(struct tty_struct *tty)
{
unsigned long flags;
struct list_head *l;
struct sclp_vt220_request *r;
- int count;
+ unsigned int count = 0;
spin_lock_irqsave(&sclp_vt220_lock, flags);
- count = 0;
if (sclp_vt220_current_request != NULL)
count = sclp_vt220_chars_stored(sclp_vt220_current_request);
list_for_each(l, &sclp_vt220_outqueue) {
/*
* We always have room.
*/
-static int
+static unsigned int
tty3270_write_room(struct tty_struct *tty)
{
return INT_MAX;
int i_msg, i;
spin_lock_bh(&tp->view.lock);
- for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) {
+ for (i_msg = 0; !tty->flow.stopped && i_msg < count; i_msg++) {
if (tp->esc_state != 0) {
/* Continue escape sequence. */
tty3270_escape_sequence(tp, buf[i_msg]);
}
}
-/*
- * Returns the number of characters in the output buffer. This is
- * used in tty_wait_until_sent to wait until all characters have
- * appeared on the screen.
- */
-static int
-tty3270_chars_in_buffer(struct tty_struct *tty)
-{
- return 0;
-}
-
-static void
-tty3270_flush_buffer(struct tty_struct *tty)
-{
-}
-
/*
* Check for visible/invisible input switches
*/
.put_char = tty3270_put_char,
.flush_chars = tty3270_flush_chars,
.write_room = tty3270_write_room,
- .chars_in_buffer = tty3270_chars_in_buffer,
- .flush_buffer = tty3270_flush_buffer,
.throttle = tty3270_throttle,
.unthrottle = tty3270_unthrottle,
.hangup = tty3270_hangup,
/* try to write as many dma transactions out as possible */
n = -EAGAIN;
- while (!tty->stopped && !tty->hw_stopped &&
+ while (!tty->flow.stopped && !tty->hw_stopped &&
!test_bit(STOP_TX, &port->flags)) {
txn = kmem_cache_alloc(fwtty_txn_cache, GFP_ATOMIC);
if (!txn) {
return (n < 0) ? 0 : n;
}
-static int fwtty_write_room(struct tty_struct *tty)
+static unsigned int fwtty_write_room(struct tty_struct *tty)
{
struct fwtty_port *port = tty->driver_data;
- int n;
+ unsigned int n;
spin_lock_bh(&port->lock);
n = dma_fifo_avail(&port->tx_fifo);
spin_unlock_bh(&port->lock);
- fwtty_dbg(port, "%d\n", n);
+ fwtty_dbg(port, "%u\n", n);
return n;
}
-static int fwtty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int fwtty_chars_in_buffer(struct tty_struct *tty)
{
struct fwtty_port *port = tty->driver_data;
- int n;
+ unsigned int n;
spin_lock_bh(&port->lock);
n = dma_fifo_level(&port->tx_fifo);
spin_unlock_bh(&port->lock);
- fwtty_dbg(port, "%d\n", n);
+ fwtty_dbg(port, "%u\n", n);
return n;
}
return len;
}
-static int gdm_tty_write_room(struct tty_struct *tty)
+static unsigned int gdm_tty_write_room(struct tty_struct *tty)
{
struct gdm *gdm = tty->driver_data;
return count;
}
-static int gb_tty_write_room(struct tty_struct *tty)
+static unsigned int gb_tty_write_room(struct tty_struct *tty)
{
struct gb_tty *gb_tty = tty->driver_data;
unsigned long flags;
return room;
}
-static int gb_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int gb_tty_chars_in_buffer(struct tty_struct *tty)
{
struct gb_tty *gb_tty = tty->driver_data;
unsigned long flags;
- int chars;
+ unsigned int chars;
spin_lock_irqsave(&gb_tty->write_lock, flags);
chars = kfifo_len(&gb_tty->write_fifo);
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_N_GSM) += n_gsm.o
-obj-$(CONFIG_R3964) += n_r3964.o
obj-y += vt/
obj-$(CONFIG_HVC_DRIVER) += hvc/
* ------------------------------------------------------------
* rs_stop() and rs_start()
*
- * This routines are called before setting or resetting tty->stopped.
+ * This routines are called before setting or resetting tty->flow.stopped.
* They enable or disable transmitter interrupts, as necessary.
* ------------------------------------------------------------
*/
return;
}
if (info->xmit.head == info->xmit.tail
- || info->tport.tty->stopped
+ || info->tport.tty->flow.stopped
|| info->tport.tty->hw_stopped) {
info->IER &= ~UART_IER_THRI;
custom.intena = IF_TBE;
unsigned long flags;
if (info->xmit.head == info->xmit.tail
- || tty->stopped
+ || tty->flow.stopped
|| tty->hw_stopped
|| !info->xmit.buf)
return;
local_irq_restore(flags);
if (info->xmit.head != info->xmit.tail
- && !tty->stopped
+ && !tty->flow.stopped
&& !tty->hw_stopped
&& !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
return ret;
}
-static int rs_write_room(struct tty_struct *tty)
+static unsigned int rs_write_room(struct tty_struct *tty)
{
struct serial_state *info = tty->driver_data;
return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
}
-static int rs_chars_in_buffer(struct tty_struct *tty)
+static unsigned int rs_chars_in_buffer(struct tty_struct *tty)
{
struct serial_state *info = tty->driver_data;
* how much write room the driver can guarantee will be sent OR BUFFERED. This
* driver MUST honor the return value.
*/
-static int ehv_bc_tty_write_room(struct tty_struct *ttys)
+static unsigned int ehv_bc_tty_write_room(struct tty_struct *ttys)
{
struct ehv_bc_data *bc = ttys->driver_data;
unsigned long flags;
- int count;
+ unsigned int count;
spin_lock_irqsave(&bc->lock, flags);
count = CIRC_SPACE(bc->head, bc->tail, BUF_SIZE);
return count;
}
-static int goldfish_tty_write_room(struct tty_struct *tty)
+static unsigned int goldfish_tty_write_room(struct tty_struct *tty)
{
return 0x10000;
}
-static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
{
struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
void __iomem *base = qtty->base;
if (vtermnos[index] != -1)
return -1;
- /* make sure no no tty has been registered in this index */
+ /* make sure no tty has been registered in this index */
hp = hvc_get_by_index(index);
if (hp) {
tty_port_put(&hp->port);
* how much write room the driver can guarantee will be sent OR BUFFERED. This
* driver MUST honor the return value.
*/
-static int hvc_write_room(struct tty_struct *tty)
+static unsigned int hvc_write_room(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
return hp->outbuf_size - hp->n_outbuf;
}
-static int hvc_chars_in_buffer(struct tty_struct *tty)
+static unsigned int hvc_chars_in_buffer(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
/*
* Maximum number of bytes to get from the console driver if hvc_poll is
* called from driver (and can't sleep). Any more than this and we break
- * and start polling with khvcd. This value was derived from from an OpenBMC
+ * and start polling with khvcd. This value was derived from an OpenBMC
* console with the OPAL driver that results in about 0.25ms interrupts off
* latency.
*/
struct hvc_iucv_private *priv;
priv = container_of(work, struct hvc_iucv_private, sndbuf_work.work);
- if (!priv)
- return;
spin_lock_bh(&priv->lock);
hvc_iucv_send(priv);
* absolutely WILL BUFFER if we can't send it. This driver MUST honor the
* return value, hence the reason for hvcs_struct buffering.
*/
-static int hvcs_write_room(struct tty_struct *tty)
+static unsigned int hvcs_write_room(struct tty_struct *tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
}
-static int hvcs_chars_in_buffer(struct tty_struct *tty)
+static unsigned int hvcs_chars_in_buffer(struct tty_struct *tty)
{
struct hvcs_struct *hvcsd = tty->driver_data;
spin_unlock_irqrestore(&hp->lock, flags);
}
-static int hvsi_write_room(struct tty_struct *tty)
+static unsigned int hvsi_write_room(struct tty_struct *tty)
{
struct hvsi_struct *hp = tty->driver_data;
return N_OUTBUF - hp->n_outbuf;
}
-static int hvsi_chars_in_buffer(struct tty_struct *tty)
+static unsigned int hvsi_chars_in_buffer(struct tty_struct *tty)
{
struct hvsi_struct *hp = tty->driver_data;
* will see there is no room in outbuf and return.
*/
while ((count > 0) && (hvsi_write_room(tty) > 0)) {
- int chunksize = min(count, hvsi_write_room(tty));
+ int chunksize = min_t(int, count, hvsi_write_room(tty));
BUG_ON(hp->n_outbuf < 0);
memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
return count;
}
-static int ipw_write_room(struct tty_struct *linux_tty)
+static unsigned int ipw_write_room(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
int room;
return 0; /* Keeps the PCMCIA scripts happy. */
}
-static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
+static unsigned int ipw_chars_in_buffer(struct tty_struct *linux_tty)
{
struct ipw_tty *tty = linux_tty->driver_data;
return total;
}
-static int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty)
+static unsigned int mips_ejtag_fdc_tty_write_room(struct tty_struct *tty)
{
struct mips_ejtag_fdc_tty_port *dport = tty->driver_data;
struct mips_ejtag_fdc_tty *priv = dport->driver;
- int room;
+ unsigned int room;
/* Report the space in the xmit buffer */
spin_lock(&dport->xmit_lock);
return room;
}
-static int mips_ejtag_fdc_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int mips_ejtag_fdc_tty_chars_in_buffer(struct tty_struct *tty)
{
struct mips_ejtag_fdc_tty_port *dport = tty->driver_data;
- int chars;
+ unsigned int chars;
/* Report the number of bytes in the xmit buffer */
spin_lock(&dport->xmit_lock);
static int moxa_open(struct tty_struct *, struct file *);
static void moxa_close(struct tty_struct *, struct file *);
static int moxa_write(struct tty_struct *, const unsigned char *, int);
-static int moxa_write_room(struct tty_struct *);
+static unsigned int moxa_write_room(struct tty_struct *);
static void moxa_flush_buffer(struct tty_struct *);
-static int moxa_chars_in_buffer(struct tty_struct *);
+static unsigned int moxa_chars_in_buffer(struct tty_struct *);
static void moxa_set_termios(struct tty_struct *, struct ktermios *);
static void moxa_stop(struct tty_struct *);
static void moxa_start(struct tty_struct *);
static void MoxaPortFlushData(struct moxa_port *, int);
static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int);
static int MoxaPortReadData(struct moxa_port *);
-static int MoxaPortTxQueue(struct moxa_port *);
+static unsigned int MoxaPortTxQueue(struct moxa_port *);
static int MoxaPortRxQueue(struct moxa_port *);
-static int MoxaPortTxFree(struct moxa_port *);
+static unsigned int MoxaPortTxFree(struct moxa_port *);
static void MoxaPortTxDisable(struct moxa_port *);
static void MoxaPortTxEnable(struct moxa_port *);
static int moxa_get_serial_info(struct tty_struct *, struct serial_struct *);
return len;
}
-static int moxa_write_room(struct tty_struct *tty)
+static unsigned int moxa_write_room(struct tty_struct *tty)
{
struct moxa_port *ch;
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
ch = tty->driver_data;
if (ch == NULL)
tty_wakeup(tty);
}
-static int moxa_chars_in_buffer(struct tty_struct *tty)
+static unsigned int moxa_chars_in_buffer(struct tty_struct *tty)
{
struct moxa_port *ch = tty->driver_data;
- int chars;
+ unsigned int chars;
chars = MoxaPortTxQueue(ch);
if (chars)
clear_bit(EMPTYWAIT, &p->statusflags);
tty_wakeup(tty);
}
- if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped &&
+ if (test_bit(LOWWAIT, &p->statusflags) && !tty->flow.stopped &&
MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
clear_bit(LOWWAIT, &p->statusflags);
tty_wakeup(tty);
}
-static int MoxaPortTxQueue(struct moxa_port *port)
+static unsigned int MoxaPortTxQueue(struct moxa_port *port)
{
void __iomem *ofsAddr = port->tableAddr;
u16 rptr, wptr, mask;
return (wptr - rptr) & mask;
}
-static int MoxaPortTxFree(struct moxa_port *port)
+static unsigned int MoxaPortTxFree(struct moxa_port *port)
{
void __iomem *ofsAddr = port->tableAddr;
u16 rptr, wptr, mask;
total += c;
}
- if (info->xmit_cnt && !tty->stopped) {
+ if (info->xmit_cnt && !tty->flow.stopped) {
if (!tty->hw_stopped ||
(info->type == PORT_16550A) ||
(info->board->chip_flag)) {
info->xmit_head &= SERIAL_XMIT_SIZE - 1;
info->xmit_cnt++;
spin_unlock_irqrestore(&info->slock, flags);
- if (!tty->stopped) {
+ if (!tty->flow.stopped) {
if (!tty->hw_stopped ||
(info->type == PORT_16550A) ||
info->board->chip_flag) {
struct mxser_port *info = tty->driver_data;
unsigned long flags;
- if (info->xmit_cnt <= 0 || tty->stopped || !info->port.xmit_buf ||
+ if (info->xmit_cnt <= 0 || tty->flow.stopped || !info->port.xmit_buf ||
(tty->hw_stopped && info->type != PORT_16550A &&
!info->board->chip_flag))
return;
spin_unlock_irqrestore(&info->slock, flags);
}
-static int mxser_write_room(struct tty_struct *tty)
+static unsigned int mxser_write_room(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
int ret;
return ret < 0 ? 0 : ret;
}
-static int mxser_chars_in_buffer(struct tty_struct *tty)
+static unsigned int mxser_chars_in_buffer(struct tty_struct *tty)
{
struct mxser_port *info = tty->driver_data;
return info->xmit_cnt;
/*
* mxser_stop() and mxser_start()
*
- * This routines are called before setting or resetting tty->stopped.
+ * This routines are called before setting or resetting tty->flow.stopped.
* They enable or disable transmitter interrupts, as necessary.
*/
static void mxser_stop(struct tty_struct *tty)
/* Handle sw stopped */
if ((old_termios->c_iflag & IXON) && !I_IXON(tty)) {
- tty->stopped = 0;
+ tty->flow.stopped = 0;
if (info->board->chip_flag) {
spin_lock_irqsave(&info->slock, flags);
if (port->port.xmit_buf == NULL)
return;
- if (port->xmit_cnt <= 0 || tty->stopped ||
+ if (port->xmit_cnt <= 0 || tty->flow.stopped ||
(tty->hw_stopped &&
(port->type != PORT_16550A) &&
(!port->board->chip_flag))) {
*/
/**
- * gsm_stuff_packet - bytestuff a packet
+ * gsm_stuff_frame - bytestuff a packet
* @input: input buffer
* @output: output buffer
* @len: length of input
}
/**
- * gsm_dlci_control - data arrived on control channel
+ * gsm_dlci_command - data arrived on control channel
* @dlci: channel
* @data: block of bytes received
* @len: length of received block
}
static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct gsm_mux *gsm = tty->disc_data;
char flags = TTY_NORMAL;
* @file: file object
* @buf: userspace buffer pointer
* @nr: size of I/O
+ * @cookie: unused
+ * @offset: unused
*
* Perform reads for the line discipline. We are guaranteed that the
* line discipline will not be closed under us but we may get multiple
/* Line discipline for real tty */
static struct tty_ldisc_ops tty_ldisc_packet = {
.owner = THIS_MODULE,
+ .num = N_GSM0710,
.name = "n_gsm",
.open = gsmld_open,
.close = gsmld_close,
return sent;
}
-static int gsmtty_write_room(struct tty_struct *tty)
+static unsigned int gsmtty_write_room(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
return TX_SIZE - kfifo_len(&dlci->fifo);
}
-static int gsmtty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
if (dlci->state == DLCI_CLOSED)
static int __init gsm_init(void)
{
/* Fill in our line protocol discipline, and register it */
- int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
+ int status = tty_register_ldisc(&tty_ldisc_packet);
if (status != 0) {
pr_err("n_gsm: can't register line discipline (err = %d)\n",
status);
gsm_tty_driver = alloc_tty_driver(256);
if (!gsm_tty_driver) {
- tty_unregister_ldisc(N_GSM0710);
pr_err("gsm_init: tty allocation failed.\n");
- return -EINVAL;
+ status = -ENOMEM;
+ goto err_unreg_ldisc;
}
gsm_tty_driver->driver_name = "gsmtty";
gsm_tty_driver->name = "gsmtty";
tty_set_operations(gsm_tty_driver, &gsmtty_ops);
if (tty_register_driver(gsm_tty_driver)) {
- put_tty_driver(gsm_tty_driver);
- tty_unregister_ldisc(N_GSM0710);
pr_err("gsm_init: tty registration failed.\n");
- return -EBUSY;
+ status = -EBUSY;
+ goto err_put_driver;
}
pr_debug("gsm_init: loaded as %d,%d.\n",
gsm_tty_driver->major, gsm_tty_driver->minor_start);
return 0;
+err_put_driver:
+ put_tty_driver(gsm_tty_driver);
+err_unreg_ldisc:
+ tty_unregister_ldisc(&tty_ldisc_packet);
+ return status;
}
static void __exit gsm_exit(void)
{
- int status = tty_unregister_ldisc(N_GSM0710);
- if (status != 0)
- pr_err("n_gsm: can't unregister line discipline (err = %d)\n",
- status);
+ tty_unregister_ldisc(&tty_ldisc_packet);
tty_unregister_driver(gsm_tty_driver);
put_tty_driver(gsm_tty_driver);
}
* interpreted as one HDLC frame.
*/
static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
- char *flags, int count)
+ const char *flags, int count)
{
register struct n_hdlc *n_hdlc = tty->disc_data;
register struct n_hdlc_buf *buf;
* n_hdlc_tty_read - Called to retrieve one frame of data (if available)
* @tty: pointer to tty instance data
* @file: pointer to open file object
- * @buf: pointer to returned data buffer
+ * @kbuf: pointer to returned data buffer
* @nr: size of returned data buffer
+ * @cookie: stored rbuf from previous run
+ * @offset: offset into the data buffer
*
* Returns the number of bytes returned or error code.
*/
static struct tty_ldisc_ops n_hdlc_ldisc = {
.owner = THIS_MODULE,
+ .num = N_HDLC,
.name = "hdlc",
.open = n_hdlc_tty_open,
.close = n_hdlc_tty_close,
/* range check maxframe arg */
maxframe = clamp(maxframe, 4096, MAX_HDLC_FRAME_SIZE);
- status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
+ status = tty_register_ldisc(&n_hdlc_ldisc);
if (!status)
pr_info("N_HDLC line discipline registered with maxframe=%d\n",
maxframe);
static void __exit n_hdlc_exit(void)
{
- /* Release tty registration of line discipline */
- int status = tty_unregister_ldisc(N_HDLC);
-
- if (status)
- pr_err("N_HDLC: can't unregister line discipline (err = %d)\n",
- status);
- else
- pr_info("N_HDLC: line discipline unregistered\n");
+ tty_unregister_ldisc(&n_hdlc_ldisc);
}
module_init(n_hdlc_init);
}
static void n_null_receivebuf(struct tty_struct *tty,
- const unsigned char *cp, char *fp,
+ const unsigned char *cp, const char *fp,
int cnt)
{
}
static struct tty_ldisc_ops null_ldisc = {
.owner = THIS_MODULE,
+ .num = N_NULL,
.name = "n_null",
.open = n_null_open,
.close = n_null_close,
static int __init n_null_init(void)
{
- BUG_ON(tty_register_ldisc(N_NULL, &null_ldisc));
+ BUG_ON(tty_register_ldisc(&null_ldisc));
return 0;
}
static void __exit n_null_exit(void)
{
- tty_unregister_ldisc(N_NULL);
+ tty_unregister_ldisc(&null_ldisc);
}
module_init(n_null_init);
+++ /dev/null
-// SPDX-License-Identifier: GPL-1.0+
-/* r3964 linediscipline for linux
- *
- * -----------------------------------------------------------
- * Copyright by
- * Philips Automation Projects
- * Kassel (Germany)
- * -----------------------------------------------------------
- * Author:
- * L. Haag
- *
- * $Log: n_r3964.c,v $
- * Revision 1.10 2001/03/18 13:02:24 dwmw2
- * Fix timer usage, use spinlocks properly.
- *
- * Revision 1.9 2001/03/18 12:52:14 dwmw2
- * Merge changes in 2.4.2
- *
- * Revision 1.8 2000/03/23 14:14:54 dwmw2
- * Fix race in sleeping in r3964_read()
- *
- * Revision 1.7 1999/28/08 11:41:50 dwmw2
- * Port to 2.3 kernel
- *
- * Revision 1.6 1998/09/30 00:40:40 dwmw2
- * Fixed compilation on 2.0.x kernels
- * Updated to newly registered tty-ldisc number 9
- *
- * Revision 1.5 1998/09/04 21:57:36 dwmw2
- * Signal handling bug fixes, port to 2.1.x.
- *
- * Revision 1.4 1998/04/02 20:26:59 lhaag
- * select, blocking, ...
- *
- * Revision 1.3 1998/02/12 18:58:43 root
- * fixed some memory leaks
- * calculation of checksum characters
- *
- * Revision 1.2 1998/02/07 13:03:34 root
- * ioctl read_telegram
- *
- * Revision 1.1 1998/02/06 19:21:03 root
- * Initial revision
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/string.h> /* used in new tty drivers */
-#include <linux/signal.h> /* used in new tty drivers */
-#include <linux/ioctl.h>
-#include <linux/n_r3964.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/uaccess.h>
-
-/*#define DEBUG_QUEUE*/
-
-/* Log successful handshake and protocol operations */
-/*#define DEBUG_PROTO_S*/
-
-/* Log handshake and protocol errors: */
-/*#define DEBUG_PROTO_E*/
-
-/* Log Linediscipline operations (open, close, read, write...): */
-/*#define DEBUG_LDISC*/
-
-/* Log module and memory operations (init, cleanup; kmalloc, kfree): */
-/*#define DEBUG_MODUL*/
-
-/* Macro helpers for debug output: */
-#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)
-
-#ifdef DEBUG_MODUL
-#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_M(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_S
-#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PS(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_PROTO_E
-#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_PE(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_LDISC
-#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_L(fmt, arg...) do {} while (0)
-#endif
-#ifdef DEBUG_QUEUE
-#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)
-#else
-#define TRACE_Q(fmt, arg...) do {} while (0)
-#endif
-static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
-static void put_char(struct r3964_info *pInfo, unsigned char ch);
-static void trigger_transmit(struct r3964_info *pInfo);
-static void retry_transmit(struct r3964_info *pInfo);
-static void transmit_block(struct r3964_info *pInfo);
-static void receive_char(struct r3964_info *pInfo, const unsigned char c);
-static void receive_error(struct r3964_info *pInfo, const char flag);
-static void on_timeout(struct timer_list *t);
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
- unsigned char __user * buf);
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
- int error_code, struct r3964_block_header *pBlock);
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
- struct r3964_client_info *pClient);
-static void remove_client_block(struct r3964_info *pInfo,
- struct r3964_client_info *pClient);
-
-static int r3964_open(struct tty_struct *tty);
-static void r3964_close(struct tty_struct *tty);
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
- void *cookie, unsigned char *buf, size_t nr);
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
- const unsigned char *buf, size_t nr);
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg);
-#ifdef CONFIG_COMPAT
-static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg);
-#endif
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
-static __poll_t r3964_poll(struct tty_struct *tty, struct file *file,
- struct poll_table_struct *wait);
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count);
-
-static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
- .owner = THIS_MODULE,
- .name = "R3964",
- .open = r3964_open,
- .close = r3964_close,
- .read = r3964_read,
- .write = r3964_write,
- .ioctl = r3964_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = r3964_compat_ioctl,
-#endif
- .set_termios = r3964_set_termios,
- .poll = r3964_poll,
- .receive_buf = r3964_receive_buf,
-};
-
-static void dump_block(const unsigned char *block, unsigned int length)
-{
- unsigned int i, j;
- char linebuf[16 * 3 + 1];
-
- for (i = 0; i < length; i += 16) {
- for (j = 0; (j < 16) && (j + i < length); j++) {
- sprintf(linebuf + 3 * j, "%02x ", block[i + j]);
- }
- linebuf[3 * j] = '\0';
- TRACE_PS("%s", linebuf);
- }
-}
-
-/*************************************************************
- * Driver initialisation
- *************************************************************/
-
-/*************************************************************
- * Module support routines
- *************************************************************/
-
-static void __exit r3964_exit(void)
-{
- int status;
-
- TRACE_M("cleanup_module()");
-
- status = tty_unregister_ldisc(N_R3964);
-
- if (status != 0) {
- printk(KERN_ERR "r3964: error unregistering linediscipline: "
- "%d\n", status);
- } else {
- TRACE_L("linediscipline successfully unregistered");
- }
-}
-
-static int __init r3964_init(void)
-{
- int status;
-
- printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");
-
- /*
- * Register the tty line discipline
- */
-
- status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);
- if (status == 0) {
- TRACE_L("line discipline %d registered", N_R3964);
- TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,
- tty_ldisc_N_R3964.num);
- TRACE_L("open=%p", tty_ldisc_N_R3964.open);
- TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);
- } else {
- printk(KERN_ERR "r3964: error registering line discipline: "
- "%d\n", status);
- }
- return status;
-}
-
-module_init(r3964_init);
-module_exit(r3964_exit);
-
-/*************************************************************
- * Protocol implementation routines
- *************************************************************/
-
-static void add_tx_queue(struct r3964_info *pInfo,
- struct r3964_block_header *pHeader)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- pHeader->next = NULL;
-
- if (pInfo->tx_last == NULL) {
- pInfo->tx_first = pInfo->tx_last = pHeader;
- } else {
- pInfo->tx_last->next = pHeader;
- pInfo->tx_last = pHeader;
- }
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",
- pHeader, pHeader->length, pInfo->tx_first);
-}
-
-static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
-{
- struct r3964_block_header *pHeader;
- unsigned long flags;
-#ifdef DEBUG_QUEUE
- struct r3964_block_header *pDump;
-#endif
-
- pHeader = pInfo->tx_first;
-
- if (pHeader == NULL)
- return;
-
-#ifdef DEBUG_QUEUE
- printk("r3964: remove_from_tx_queue: %p, length %u - ",
- pHeader, pHeader->length);
- for (pDump = pHeader; pDump; pDump = pDump->next)
- printk("%p ", pDump);
- printk("\n");
-#endif
-
- if (pHeader->owner) {
- if (error_code) {
- add_msg(pHeader->owner, R3964_MSG_ACK, 0,
- error_code, NULL);
- } else {
- add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,
- error_code, NULL);
- }
- wake_up_interruptible(&pInfo->tty->read_wait);
- }
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- pInfo->tx_first = pHeader->next;
- if (pInfo->tx_first == NULL) {
- pInfo->tx_last = NULL;
- }
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- kfree(pHeader);
- TRACE_M("remove_from_tx_queue - kfree %p", pHeader);
-
- TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",
- pInfo->tx_first, pInfo->tx_last);
-}
-
-static void add_rx_queue(struct r3964_info *pInfo,
- struct r3964_block_header *pHeader)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- pHeader->next = NULL;
-
- if (pInfo->rx_last == NULL) {
- pInfo->rx_first = pInfo->rx_last = pHeader;
- } else {
- pInfo->rx_last->next = pHeader;
- pInfo->rx_last = pHeader;
- }
- pInfo->blocks_in_rx_queue++;
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",
- pHeader, pHeader->length,
- pInfo->rx_first, pInfo->blocks_in_rx_queue);
-}
-
-static void remove_from_rx_queue(struct r3964_info *pInfo,
- struct r3964_block_header *pHeader)
-{
- unsigned long flags;
- struct r3964_block_header *pFind;
-
- if (pHeader == NULL)
- return;
-
- TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
- pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
- TRACE_Q("remove_from_rx_queue: %p, length %u",
- pHeader, pHeader->length);
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- if (pInfo->rx_first == pHeader) {
- /* Remove the first block in the linked list: */
- pInfo->rx_first = pHeader->next;
-
- if (pInfo->rx_first == NULL) {
- pInfo->rx_last = NULL;
- }
- pInfo->blocks_in_rx_queue--;
- } else {
- /* Find block to remove: */
- for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {
- if (pFind->next == pHeader) {
- /* Got it. */
- pFind->next = pHeader->next;
- pInfo->blocks_in_rx_queue--;
- if (pFind->next == NULL) {
- /* Oh, removed the last one! */
- pInfo->rx_last = pFind;
- }
- break;
- }
- }
- }
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- kfree(pHeader);
- TRACE_M("remove_from_rx_queue - kfree %p", pHeader);
-
- TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",
- pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);
-}
-
-static void put_char(struct r3964_info *pInfo, unsigned char ch)
-{
- struct tty_struct *tty = pInfo->tty;
- /* FIXME: put_char should not be called from an IRQ */
- tty_put_char(tty, ch);
- pInfo->bcc ^= ch;
-}
-
-static void flush(struct r3964_info *pInfo)
-{
- struct tty_struct *tty = pInfo->tty;
-
- if (tty == NULL || tty->ops->flush_chars == NULL)
- return;
- tty->ops->flush_chars(tty);
-}
-
-static void trigger_transmit(struct r3964_info *pInfo)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pInfo->lock, flags);
-
- if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {
- pInfo->state = R3964_TX_REQUEST;
- pInfo->nRetry = 0;
- pInfo->flags &= ~R3964_ERROR;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
-
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- TRACE_PS("trigger_transmit - sent STX");
-
- put_char(pInfo, STX);
- flush(pInfo);
-
- pInfo->bcc = 0;
- } else {
- spin_unlock_irqrestore(&pInfo->lock, flags);
- }
-}
-
-static void retry_transmit(struct r3964_info *pInfo)
-{
- if (pInfo->nRetry < R3964_MAX_RETRIES) {
- TRACE_PE("transmission failed. Retry #%d", pInfo->nRetry);
- pInfo->bcc = 0;
- put_char(pInfo, STX);
- flush(pInfo);
- pInfo->state = R3964_TX_REQUEST;
- pInfo->nRetry++;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
- } else {
- TRACE_PE("transmission failed after %d retries",
- R3964_MAX_RETRIES);
-
- remove_from_tx_queue(pInfo, R3964_TX_FAIL);
-
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state = R3964_IDLE;
-
- trigger_transmit(pInfo);
- }
-}
-
-static void transmit_block(struct r3964_info *pInfo)
-{
- struct tty_struct *tty = pInfo->tty;
- struct r3964_block_header *pBlock = pInfo->tx_first;
- int room = 0;
-
- if (tty == NULL || pBlock == NULL) {
- return;
- }
-
- room = tty_write_room(tty);
-
- TRACE_PS("transmit_block %p, room %d, length %d",
- pBlock, room, pBlock->length);
-
- while (pInfo->tx_position < pBlock->length) {
- if (room < 2)
- break;
-
- if (pBlock->data[pInfo->tx_position] == DLE) {
- /* send additional DLE char: */
- put_char(pInfo, DLE);
- }
- put_char(pInfo, pBlock->data[pInfo->tx_position++]);
-
- room--;
- }
-
- if ((pInfo->tx_position == pBlock->length) && (room >= 3)) {
- put_char(pInfo, DLE);
- put_char(pInfo, ETX);
- if (pInfo->flags & R3964_BCC) {
- put_char(pInfo, pInfo->bcc);
- }
- pInfo->state = R3964_WAIT_FOR_TX_ACK;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);
- }
- flush(pInfo);
-}
-
-static void on_receive_block(struct r3964_info *pInfo)
-{
- unsigned int length;
- struct r3964_client_info *pClient;
- struct r3964_block_header *pBlock;
-
- length = pInfo->rx_position;
-
- /* compare byte checksum characters: */
- if (pInfo->flags & R3964_BCC) {
- if (pInfo->bcc != pInfo->last_rx) {
- TRACE_PE("checksum error - got %x but expected %x",
- pInfo->last_rx, pInfo->bcc);
- pInfo->flags |= R3964_CHECKSUM;
- }
- }
-
- /* check for errors (parity, overrun,...): */
- if (pInfo->flags & R3964_ERROR) {
- TRACE_PE("on_receive_block - transmission failed error %x",
- pInfo->flags & R3964_ERROR);
-
- put_char(pInfo, NAK);
- flush(pInfo);
- if (pInfo->nRetry < R3964_MAX_RETRIES) {
- pInfo->state = R3964_WAIT_FOR_RX_REPEAT;
- pInfo->nRetry++;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_RX_PANIC);
- } else {
- TRACE_PE("on_receive_block - failed after max retries");
- pInfo->state = R3964_IDLE;
- }
- return;
- }
-
- /* received block; submit DLE: */
- put_char(pInfo, DLE);
- flush(pInfo);
- del_timer_sync(&pInfo->tmr);
- TRACE_PS(" rx success: got %d chars", length);
-
- /* prepare struct r3964_block_header: */
- pBlock = kmalloc(length + sizeof(struct r3964_block_header),
- GFP_KERNEL);
- TRACE_M("on_receive_block - kmalloc %p", pBlock);
-
- if (pBlock == NULL)
- return;
-
- pBlock->length = length;
- pBlock->data = ((unsigned char *)pBlock) +
- sizeof(struct r3964_block_header);
- pBlock->locks = 0;
- pBlock->next = NULL;
- pBlock->owner = NULL;
-
- memcpy(pBlock->data, pInfo->rx_buf, length);
-
- /* queue block into rx_queue: */
- add_rx_queue(pInfo, pBlock);
-
- /* notify attached client processes: */
- for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
- if (pClient->sig_flags & R3964_SIG_DATA) {
- add_msg(pClient, R3964_MSG_DATA, length, R3964_OK,
- pBlock);
- }
- }
- wake_up_interruptible(&pInfo->tty->read_wait);
-
- pInfo->state = R3964_IDLE;
-
- trigger_transmit(pInfo);
-}
-
-static void receive_char(struct r3964_info *pInfo, const unsigned char c)
-{
- switch (pInfo->state) {
- case R3964_TX_REQUEST:
- if (c == DLE) {
- TRACE_PS("TX_REQUEST - got DLE");
-
- pInfo->state = R3964_TRANSMITTING;
- pInfo->tx_position = 0;
-
- transmit_block(pInfo);
- } else if (c == STX) {
- if (pInfo->nRetry == 0) {
- TRACE_PE("TX_REQUEST - init conflict");
- if (pInfo->priority == R3964_SLAVE) {
- goto start_receiving;
- }
- } else {
- TRACE_PE("TX_REQUEST - secondary init "
- "conflict!? Switching to SLAVE mode "
- "for next rx.");
- goto start_receiving;
- }
- } else {
- TRACE_PE("TX_REQUEST - char != DLE: %x", c);
- retry_transmit(pInfo);
- }
- break;
- case R3964_TRANSMITTING:
- if (c == NAK) {
- TRACE_PE("TRANSMITTING - got NAK");
- retry_transmit(pInfo);
- } else {
- TRACE_PE("TRANSMITTING - got invalid char");
-
- pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
- }
- break;
- case R3964_WAIT_FOR_TX_ACK:
- if (c == DLE) {
- TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
- remove_from_tx_queue(pInfo, R3964_OK);
-
- pInfo->state = R3964_IDLE;
- trigger_transmit(pInfo);
- } else {
- retry_transmit(pInfo);
- }
- break;
- case R3964_WAIT_FOR_RX_REPEAT:
- case R3964_IDLE:
- if (c == STX) {
- /* Prevent rx_queue from overflow: */
- if (pInfo->blocks_in_rx_queue >=
- R3964_MAX_BLOCKS_IN_RX_QUEUE) {
- TRACE_PE("IDLE - got STX but no space in "
- "rx_queue!");
- pInfo->state = R3964_WAIT_FOR_RX_BUF;
- mod_timer(&pInfo->tmr,
- jiffies + R3964_TO_NO_BUF);
- break;
- }
-start_receiving:
- /* Ok, start receiving: */
- TRACE_PS("IDLE - got STX");
- pInfo->rx_position = 0;
- pInfo->last_rx = 0;
- pInfo->flags &= ~R3964_ERROR;
- pInfo->state = R3964_RECEIVING;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
- pInfo->nRetry = 0;
- put_char(pInfo, DLE);
- flush(pInfo);
- pInfo->bcc = 0;
- }
- break;
- case R3964_RECEIVING:
- if (pInfo->rx_position < RX_BUF_SIZE) {
- pInfo->bcc ^= c;
-
- if (c == DLE) {
- if (pInfo->last_rx == DLE) {
- pInfo->last_rx = 0;
- goto char_to_buf;
- }
- pInfo->last_rx = DLE;
- break;
- } else if ((c == ETX) && (pInfo->last_rx == DLE)) {
- if (pInfo->flags & R3964_BCC) {
- pInfo->state = R3964_WAIT_FOR_BCC;
- mod_timer(&pInfo->tmr,
- jiffies + R3964_TO_ZVZ);
- } else {
- on_receive_block(pInfo);
- }
- } else {
- pInfo->last_rx = c;
-char_to_buf:
- pInfo->rx_buf[pInfo->rx_position++] = c;
- mod_timer(&pInfo->tmr, jiffies + R3964_TO_ZVZ);
- }
- }
- /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */
- break;
- case R3964_WAIT_FOR_BCC:
- pInfo->last_rx = c;
- on_receive_block(pInfo);
- break;
- }
-}
-
-static void receive_error(struct r3964_info *pInfo, const char flag)
-{
- switch (flag) {
- case TTY_NORMAL:
- break;
- case TTY_BREAK:
- TRACE_PE("received break");
- pInfo->flags |= R3964_BREAK;
- break;
- case TTY_PARITY:
- TRACE_PE("parity error");
- pInfo->flags |= R3964_PARITY;
- break;
- case TTY_FRAME:
- TRACE_PE("frame error");
- pInfo->flags |= R3964_FRAME;
- break;
- case TTY_OVERRUN:
- TRACE_PE("frame overrun");
- pInfo->flags |= R3964_OVERRUN;
- break;
- default:
- TRACE_PE("receive_error - unknown flag %d", flag);
- pInfo->flags |= R3964_UNKNOWN;
- break;
- }
-}
-
-static void on_timeout(struct timer_list *t)
-{
- struct r3964_info *pInfo = from_timer(pInfo, t, tmr);
-
- switch (pInfo->state) {
- case R3964_TX_REQUEST:
- TRACE_PE("TX_REQUEST - timeout");
- retry_transmit(pInfo);
- break;
- case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
- put_char(pInfo, NAK);
- flush(pInfo);
- retry_transmit(pInfo);
- break;
- case R3964_WAIT_FOR_TX_ACK:
- TRACE_PE("WAIT_FOR_TX_ACK - timeout");
- retry_transmit(pInfo);
- break;
- case R3964_WAIT_FOR_RX_BUF:
- TRACE_PE("WAIT_FOR_RX_BUF - timeout");
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state = R3964_IDLE;
- break;
- case R3964_RECEIVING:
- TRACE_PE("RECEIVING - timeout after %d chars",
- pInfo->rx_position);
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state = R3964_IDLE;
- break;
- case R3964_WAIT_FOR_RX_REPEAT:
- TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
- pInfo->state = R3964_IDLE;
- break;
- case R3964_WAIT_FOR_BCC:
- TRACE_PE("WAIT_FOR_BCC - timeout");
- put_char(pInfo, NAK);
- flush(pInfo);
- pInfo->state = R3964_IDLE;
- break;
- }
-}
-
-static struct r3964_client_info *findClient(struct r3964_info *pInfo,
- struct pid *pid)
-{
- struct r3964_client_info *pClient;
-
- for (pClient = pInfo->firstClient; pClient; pClient = pClient->next) {
- if (pClient->pid == pid) {
- return pClient;
- }
- }
- return NULL;
-}
-
-static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg)
-{
- struct r3964_client_info *pClient;
- struct r3964_client_info **ppClient;
- struct r3964_message *pMsg;
-
- if ((arg & R3964_SIG_ALL) == 0) {
- /* Remove client from client list */
- for (ppClient = &pInfo->firstClient; *ppClient;
- ppClient = &(*ppClient)->next) {
- pClient = *ppClient;
-
- if (pClient->pid == pid) {
- TRACE_PS("removing client %d from client list",
- pid_nr(pid));
- *ppClient = pClient->next;
- while (pClient->msg_count) {
- pMsg = remove_msg(pInfo, pClient);
- if (pMsg) {
- kfree(pMsg);
- TRACE_M("enable_signals - msg "
- "kfree %p", pMsg);
- }
- }
- put_pid(pClient->pid);
- kfree(pClient);
- TRACE_M("enable_signals - kfree %p", pClient);
- return 0;
- }
- }
- return -EINVAL;
- } else {
- pClient = findClient(pInfo, pid);
- if (pClient) {
- /* update signal options */
- pClient->sig_flags = arg;
- } else {
- /* add client to client list */
- pClient = kmalloc(sizeof(struct r3964_client_info),
- GFP_KERNEL);
- TRACE_M("enable_signals - kmalloc %p", pClient);
- if (pClient == NULL)
- return -ENOMEM;
-
- TRACE_PS("add client %d to client list", pid_nr(pid));
- spin_lock_init(&pClient->lock);
- pClient->sig_flags = arg;
- pClient->pid = get_pid(pid);
- pClient->next = pInfo->firstClient;
- pClient->first_msg = NULL;
- pClient->last_msg = NULL;
- pClient->next_block_to_read = NULL;
- pClient->msg_count = 0;
- pInfo->firstClient = pClient;
- }
- }
-
- return 0;
-}
-
-static int read_telegram(struct r3964_info *pInfo, struct pid *pid,
- unsigned char __user * buf)
-{
- struct r3964_client_info *pClient;
- struct r3964_block_header *block;
-
- if (!buf) {
- return -EINVAL;
- }
-
- pClient = findClient(pInfo, pid);
- if (pClient == NULL) {
- return -EINVAL;
- }
-
- block = pClient->next_block_to_read;
- if (!block) {
- return 0;
- } else {
- if (copy_to_user(buf, block->data, block->length))
- return -EFAULT;
-
- remove_client_block(pInfo, pClient);
- return block->length;
- }
-
- return -EINVAL;
-}
-
-static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
- int error_code, struct r3964_block_header *pBlock)
-{
- struct r3964_message *pMsg;
- unsigned long flags;
-
- if (pClient->msg_count < R3964_MAX_MSG_COUNT - 1) {
-queue_the_message:
-
- pMsg = kmalloc(sizeof(struct r3964_message),
- error_code ? GFP_ATOMIC : GFP_KERNEL);
- TRACE_M("add_msg - kmalloc %p", pMsg);
- if (pMsg == NULL) {
- return;
- }
-
- spin_lock_irqsave(&pClient->lock, flags);
-
- pMsg->msg_id = msg_id;
- pMsg->arg = arg;
- pMsg->error_code = error_code;
- pMsg->block = pBlock;
- pMsg->next = NULL;
-
- if (pClient->last_msg == NULL) {
- pClient->first_msg = pClient->last_msg = pMsg;
- } else {
- pClient->last_msg->next = pMsg;
- pClient->last_msg = pMsg;
- }
-
- pClient->msg_count++;
-
- if (pBlock != NULL) {
- pBlock->locks++;
- }
- spin_unlock_irqrestore(&pClient->lock, flags);
- } else {
- if ((pClient->last_msg->msg_id == R3964_MSG_ACK)
- && (pClient->last_msg->error_code == R3964_OVERFLOW)) {
- pClient->last_msg->arg++;
- TRACE_PE("add_msg - inc prev OVERFLOW-msg");
- } else {
- msg_id = R3964_MSG_ACK;
- arg = 0;
- error_code = R3964_OVERFLOW;
- pBlock = NULL;
- TRACE_PE("add_msg - queue OVERFLOW-msg");
- goto queue_the_message;
- }
- }
- /* Send SIGIO signal to client process: */
- if (pClient->sig_flags & R3964_USE_SIGIO) {
- kill_pid(pClient->pid, SIGIO, 1);
- }
-}
-
-static struct r3964_message *remove_msg(struct r3964_info *pInfo,
- struct r3964_client_info *pClient)
-{
- struct r3964_message *pMsg = NULL;
- unsigned long flags;
-
- if (pClient->first_msg) {
- spin_lock_irqsave(&pClient->lock, flags);
-
- pMsg = pClient->first_msg;
- pClient->first_msg = pMsg->next;
- if (pClient->first_msg == NULL) {
- pClient->last_msg = NULL;
- }
-
- pClient->msg_count--;
- if (pMsg->block) {
- remove_client_block(pInfo, pClient);
- pClient->next_block_to_read = pMsg->block;
- }
- spin_unlock_irqrestore(&pClient->lock, flags);
- }
- return pMsg;
-}
-
-static void remove_client_block(struct r3964_info *pInfo,
- struct r3964_client_info *pClient)
-{
- struct r3964_block_header *block;
-
- TRACE_PS("remove_client_block PID %d", pid_nr(pClient->pid));
-
- block = pClient->next_block_to_read;
- if (block) {
- block->locks--;
- if (block->locks == 0) {
- remove_from_rx_queue(pInfo, block);
- }
- }
- pClient->next_block_to_read = NULL;
-}
-
-/*************************************************************
- * Line discipline routines
- *************************************************************/
-
-static int r3964_open(struct tty_struct *tty)
-{
- struct r3964_info *pInfo;
-
- TRACE_L("open");
- TRACE_L("tty=%p, PID=%d, disc_data=%p",
- tty, current->pid, tty->disc_data);
-
- pInfo = kmalloc(sizeof(struct r3964_info), GFP_KERNEL);
- TRACE_M("r3964_open - info kmalloc %p", pInfo);
-
- if (!pInfo) {
- printk(KERN_ERR "r3964: failed to alloc info structure\n");
- return -ENOMEM;
- }
-
- pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
- TRACE_M("r3964_open - rx_buf kmalloc %p", pInfo->rx_buf);
-
- if (!pInfo->rx_buf) {
- printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
- kfree(pInfo);
- TRACE_M("r3964_open - info kfree %p", pInfo);
- return -ENOMEM;
- }
-
- pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
- TRACE_M("r3964_open - tx_buf kmalloc %p", pInfo->tx_buf);
-
- if (!pInfo->tx_buf) {
- printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
- kfree(pInfo->rx_buf);
- TRACE_M("r3964_open - rx_buf kfree %p", pInfo->rx_buf);
- kfree(pInfo);
- TRACE_M("r3964_open - info kfree %p", pInfo);
- return -ENOMEM;
- }
-
- spin_lock_init(&pInfo->lock);
- mutex_init(&pInfo->read_lock);
- pInfo->tty = tty;
- pInfo->priority = R3964_MASTER;
- pInfo->rx_first = pInfo->rx_last = NULL;
- pInfo->tx_first = pInfo->tx_last = NULL;
- pInfo->rx_position = 0;
- pInfo->tx_position = 0;
- pInfo->last_rx = 0;
- pInfo->blocks_in_rx_queue = 0;
- pInfo->firstClient = NULL;
- pInfo->state = R3964_IDLE;
- pInfo->flags = R3964_DEBUG;
- pInfo->nRetry = 0;
-
- tty->disc_data = pInfo;
- tty->receive_room = 65536;
-
- timer_setup(&pInfo->tmr, on_timeout, 0);
-
- return 0;
-}
-
-static void r3964_close(struct tty_struct *tty)
-{
- struct r3964_info *pInfo = tty->disc_data;
- struct r3964_client_info *pClient, *pNext;
- struct r3964_message *pMsg;
- struct r3964_block_header *pHeader, *pNextHeader;
- unsigned long flags;
-
- TRACE_L("close");
-
- /*
- * Make sure that our task queue isn't activated. If it
- * is, take it out of the linked list.
- */
- del_timer_sync(&pInfo->tmr);
-
- /* Remove client-structs and message queues: */
- pClient = pInfo->firstClient;
- while (pClient) {
- pNext = pClient->next;
- while (pClient->msg_count) {
- pMsg = remove_msg(pInfo, pClient);
- if (pMsg) {
- kfree(pMsg);
- TRACE_M("r3964_close - msg kfree %p", pMsg);
- }
- }
- put_pid(pClient->pid);
- kfree(pClient);
- TRACE_M("r3964_close - client kfree %p", pClient);
- pClient = pNext;
- }
- /* Remove jobs from tx_queue: */
- spin_lock_irqsave(&pInfo->lock, flags);
- pHeader = pInfo->tx_first;
- pInfo->tx_first = pInfo->tx_last = NULL;
- spin_unlock_irqrestore(&pInfo->lock, flags);
-
- while (pHeader) {
- pNextHeader = pHeader->next;
- kfree(pHeader);
- pHeader = pNextHeader;
- }
-
- /* Free buffers: */
- kfree(pInfo->rx_buf);
- TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf);
- kfree(pInfo->tx_buf);
- TRACE_M("r3964_close - tx_buf kfree %p", pInfo->tx_buf);
- kfree(pInfo);
- TRACE_M("r3964_close - info kfree %p", pInfo);
-}
-
-static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
- unsigned char *kbuf, size_t nr,
- void **cookie, unsigned long offset)
-{
- struct r3964_info *pInfo = tty->disc_data;
- struct r3964_client_info *pClient;
- struct r3964_message *pMsg;
- struct r3964_client_message theMsg;
- int ret;
-
- TRACE_L("read()");
-
- /*
- * Internal serialization of reads.
- */
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&pInfo->read_lock))
- return -EAGAIN;
- } else {
- if (mutex_lock_interruptible(&pInfo->read_lock))
- return -ERESTARTSYS;
- }
-
- pClient = findClient(pInfo, task_pid(current));
- if (pClient) {
- pMsg = remove_msg(pInfo, pClient);
- if (pMsg == NULL) {
- /* no messages available. */
- if (tty_io_nonblock(tty, file)) {
- ret = -EAGAIN;
- goto unlock;
- }
- /* block until there is a message: */
- wait_event_interruptible(tty->read_wait,
- (pMsg = remove_msg(pInfo, pClient)));
- }
-
- /* If we still haven't got a message, we must have been signalled */
-
- if (!pMsg) {
- ret = -EINTR;
- goto unlock;
- }
-
- /* deliver msg to client process: */
- theMsg.msg_id = pMsg->msg_id;
- theMsg.arg = pMsg->arg;
- theMsg.error_code = pMsg->error_code;
- ret = sizeof(struct r3964_client_message);
-
- kfree(pMsg);
- TRACE_M("r3964_read - msg kfree %p", pMsg);
-
- memcpy(kbuf, &theMsg, ret);
-
- TRACE_PS("read - return %d", ret);
- goto unlock;
- }
- ret = -EPERM;
-unlock:
- mutex_unlock(&pInfo->read_lock);
- return ret;
-}
-
-static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
- const unsigned char *data, size_t count)
-{
- struct r3964_info *pInfo = tty->disc_data;
- struct r3964_block_header *pHeader;
- struct r3964_client_info *pClient;
- unsigned char *new_data;
-
- TRACE_L("write request, %d characters", count);
-/*
- * Verify the pointers
- */
-
- if (!pInfo)
- return -EIO;
-
-/*
- * Ensure that the caller does not wish to send too much.
- */
- if (count > R3964_MTU) {
- if (pInfo->flags & R3964_DEBUG) {
- TRACE_L(KERN_WARNING "r3964_write: truncating user "
- "packet from %u to mtu %d", count, R3964_MTU);
- }
- count = R3964_MTU;
- }
-/*
- * Allocate a buffer for the data and copy it from the buffer with header prepended
- */
- new_data = kmalloc(count + sizeof(struct r3964_block_header),
- GFP_KERNEL);
- TRACE_M("r3964_write - kmalloc %p", new_data);
- if (new_data == NULL) {
- if (pInfo->flags & R3964_DEBUG) {
- printk(KERN_ERR "r3964_write: no memory\n");
- }
- return -ENOSPC;
- }
-
- pHeader = (struct r3964_block_header *)new_data;
- pHeader->data = new_data + sizeof(struct r3964_block_header);
- pHeader->length = count;
- pHeader->locks = 0;
- pHeader->owner = NULL;
-
- pClient = findClient(pInfo, task_pid(current));
- if (pClient) {
- pHeader->owner = pClient;
- }
-
- memcpy(pHeader->data, data, count); /* We already verified this */
-
- if (pInfo->flags & R3964_DEBUG) {
- dump_block(pHeader->data, count);
- }
-
-/*
- * Add buffer to transmit-queue:
- */
- add_tx_queue(pInfo, pHeader);
- trigger_transmit(pInfo);
-
- return 0;
-}
-
-static int r3964_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct r3964_info *pInfo = tty->disc_data;
- if (pInfo == NULL)
- return -EINVAL;
- switch (cmd) {
- case R3964_ENABLE_SIGNALS:
- return enable_signals(pInfo, task_pid(current), arg);
- case R3964_SETPRIORITY:
- if (arg < R3964_MASTER || arg > R3964_SLAVE)
- return -EINVAL;
- pInfo->priority = arg & 0xff;
- return 0;
- case R3964_USE_BCC:
- if (arg)
- pInfo->flags |= R3964_BCC;
- else
- pInfo->flags &= ~R3964_BCC;
- return 0;
- case R3964_READ_TELEGRAM:
- return read_telegram(pInfo, task_pid(current),
- (unsigned char __user *)arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-#ifdef CONFIG_COMPAT
-static int r3964_compat_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case R3964_ENABLE_SIGNALS:
- case R3964_SETPRIORITY:
- case R3964_USE_BCC:
- return r3964_ioctl(tty, file, cmd, arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-#endif
-
-static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old)
-{
- TRACE_L("set_termios");
-}
-
-/* Called without the kernel lock held - fine */
-static __poll_t r3964_poll(struct tty_struct *tty, struct file *file,
- struct poll_table_struct *wait)
-{
- struct r3964_info *pInfo = tty->disc_data;
- struct r3964_client_info *pClient;
- struct r3964_message *pMsg = NULL;
- unsigned long flags;
- __poll_t result = EPOLLOUT;
-
- TRACE_L("POLL");
-
- pClient = findClient(pInfo, task_pid(current));
- if (pClient) {
- poll_wait(file, &tty->read_wait, wait);
- spin_lock_irqsave(&pInfo->lock, flags);
- pMsg = pClient->first_msg;
- spin_unlock_irqrestore(&pInfo->lock, flags);
- if (pMsg)
- result |= EPOLLIN | EPOLLRDNORM;
- } else {
- result = -EINVAL;
- }
- return result;
-}
-
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
-{
- struct r3964_info *pInfo = tty->disc_data;
- const unsigned char *p;
- char *f, flags = TTY_NORMAL;
- int i;
-
- for (i = count, p = cp, f = fp; i; i--, p++) {
- if (f)
- flags = *f++;
- if (flags == TTY_NORMAL) {
- receive_char(pInfo, *p);
- } else {
- receive_error(pInfo, flags);
- }
-
- }
-}
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_LDISC(N_R3964);
{
unsigned long flags;
- if (tty->link->packet) {
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- tty->ctrl_status |= TIOCPKT_FLUSHREAD;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->link->ctrl.packet) {
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ tty->ctrl.pktstatus |= TIOCPKT_FLUSHREAD;
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
wake_up_interruptible(&tty->link->read_wait);
}
}
* Holds termios_rwsem to exclude producer/consumer while
* buffer indices are reset.
*
- * Locking: ctrl_lock, exclusive termios_rwsem
+ * Locking: ctrl.lock, exclusive termios_rwsem
*/
static void n_tty_flush_buffer(struct tty_struct *tty)
* buffer is 'output'. The signal is processed first to alert any current
* readers or writers to discontinue and exit their i/o loops.
*
- * Locking: ctrl_lock
+ * Locking: ctrl.lock
*/
static void __isig(int sig, struct tty_struct *tty)
commit_echoes(tty);
} else
process_echoes(tty);
- return;
}
/**
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
* publishes canon_head if canonical mode is active
- *
- * Returns 1 if LNEXT was received, else returns 0
*/
-
-static int
-n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
+static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
if (c == START_CHAR(tty)) {
start_tty(tty);
process_echoes(tty);
- return 0;
+ return;
}
if (c == STOP_CHAR(tty)) {
stop_tty(tty);
- return 0;
+ return;
}
}
if (L_ISIG(tty)) {
if (c == INTR_CHAR(tty)) {
n_tty_receive_signal_char(tty, SIGINT, c);
- return 0;
+ return;
} else if (c == QUIT_CHAR(tty)) {
n_tty_receive_signal_char(tty, SIGQUIT, c);
- return 0;
+ return;
} else if (c == SUSP_CHAR(tty)) {
n_tty_receive_signal_char(tty, SIGTSTP, c);
- return 0;
+ return;
}
}
- if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+ if (tty->flow.stopped && !tty->flow.tco_stopped && I_IXON(tty) && I_IXANY(tty)) {
start_tty(tty);
process_echoes(tty);
}
if (c == '\r') {
if (I_IGNCR(tty))
- return 0;
+ return;
if (I_ICRNL(tty))
c = '\n';
} else if (c == '\n' && I_INLCR(tty))
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
eraser(c, tty);
commit_echoes(tty);
- return 0;
+ return;
}
if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
ldata->lnext = 1;
commit_echoes(tty);
}
}
- return 1;
+ return;
}
if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) {
size_t tail = ldata->canon_head;
tail++;
}
commit_echoes(tty);
- return 0;
+ return;
}
if (c == '\n') {
if (L_ECHO(tty) || L_ECHONL(tty)) {
smp_store_release(&ldata->canon_head, ldata->read_head);
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
wake_up_interruptible_poll(&tty->read_wait, EPOLLIN);
- return 0;
+ return;
}
}
put_tty_queue(c, ldata);
put_tty_queue(c, ldata);
- return 0;
}
-static inline void
-n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
+static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
- if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+ if (tty->flow.stopped && !tty->flow.tco_stopped && I_IXON(tty) && I_IXANY(tty)) {
start_tty(tty);
process_echoes(tty);
}
put_tty_queue(c, ldata);
}
-static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
-{
- n_tty_receive_char_inline(tty, c);
-}
-
-static inline void
-n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)
-{
- struct n_tty_data *ldata = tty->disc_data;
-
- if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
- start_tty(tty);
- process_echoes(tty);
- }
- if (L_ECHO(tty)) {
- finish_erasing(ldata);
- /* Record the column of first canon char. */
- if (ldata->canon_head == ldata->read_head)
- echo_set_canon_col(ldata);
- echo_char(c, tty);
- commit_echoes(tty);
- }
- put_tty_queue(c, ldata);
-}
-
static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
{
if (I_ISTRIP(tty))
if (c == STOP_CHAR(tty))
stop_tty(tty);
else if (c == START_CHAR(tty) ||
- (tty->stopped && !tty->flow_stopped && I_IXANY(tty) &&
+ (tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) &&
c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) &&
c != SUSP_CHAR(tty))) {
start_tty(tty);
static void
n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct n_tty_data *ldata = tty->disc_data;
size_t n, head;
static void
n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct n_tty_data *ldata = tty->disc_data;
char flag = TTY_NORMAL;
static void
n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
char flag = TTY_NORMAL;
}
}
-static void
-n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static void n_tty_receive_buf_standard(struct tty_struct *tty,
+ const unsigned char *cp, const char *fp, int count)
{
struct n_tty_data *ldata = tty->disc_data;
char flag = TTY_NORMAL;
while (count--) {
+ unsigned char c = *cp++;
+
if (fp)
flag = *fp++;
- if (likely(flag == TTY_NORMAL)) {
- unsigned char c = *cp++;
-
- if (I_ISTRIP(tty))
- c &= 0x7f;
- if (I_IUCLC(tty) && L_IEXTEN(tty))
- c = tolower(c);
- if (L_EXTPROC(tty)) {
- put_tty_queue(c, ldata);
- continue;
- }
- if (!test_bit(c, ldata->char_map))
- n_tty_receive_char_inline(tty, c);
- else if (n_tty_receive_char_special(tty, c) && count) {
- if (fp)
- flag = *fp++;
- n_tty_receive_char_lnext(tty, *cp++, flag);
- count--;
- }
- } else
- n_tty_receive_char_flagged(tty, *cp++, flag);
- }
-}
-static void
-n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
-{
- struct n_tty_data *ldata = tty->disc_data;
- char flag = TTY_NORMAL;
+ if (ldata->lnext) {
+ n_tty_receive_char_lnext(tty, c, flag);
+ continue;
+ }
- while (count--) {
- if (fp)
- flag = *fp++;
- if (likely(flag == TTY_NORMAL)) {
- unsigned char c = *cp++;
-
- if (!test_bit(c, ldata->char_map))
- n_tty_receive_char_fast(tty, c);
- else if (n_tty_receive_char_special(tty, c) && count) {
- if (fp)
- flag = *fp++;
- n_tty_receive_char_lnext(tty, *cp++, flag);
- count--;
- }
- } else
- n_tty_receive_char_flagged(tty, *cp++, flag);
+ if (unlikely(flag != TTY_NORMAL)) {
+ n_tty_receive_char_flagged(tty, c, flag);
+ continue;
+ }
+
+ if (I_ISTRIP(tty))
+ c &= 0x7f;
+ if (I_IUCLC(tty) && L_IEXTEN(tty))
+ c = tolower(c);
+ if (L_EXTPROC(tty)) {
+ put_tty_queue(c, ldata);
+ continue;
+ }
+
+ if (test_bit(c, ldata->char_map))
+ n_tty_receive_char_special(tty, c);
+ else
+ n_tty_receive_char(tty, c);
}
}
static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
struct n_tty_data *ldata = tty->disc_data;
bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
else if (tty->closing && !L_EXTPROC(tty))
n_tty_receive_buf_closing(tty, cp, fp, count);
else {
- if (ldata->lnext) {
- char flag = TTY_NORMAL;
-
- if (fp)
- flag = *fp++;
- n_tty_receive_char_lnext(tty, *cp++, flag);
- count--;
- }
-
- if (!preops && !I_PARMRK(tty))
- n_tty_receive_buf_fast(tty, cp, fp, count);
- else
- n_tty_receive_buf_standard(tty, cp, fp, count);
+ n_tty_receive_buf_standard(tty, cp, fp, count);
flush_echoes(tty);
if (tty->ops->flush_chars)
*/
static int
n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count, int flow)
+ const char *fp, int count, int flow)
{
struct n_tty_data *ldata = tty->disc_data;
int room, n, rcvd = 0, overflow;
}
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
n_tty_receive_buf_common(tty, cp, fp, count, 0);
}
static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+ const char *fp, int count)
{
return n_tty_receive_buf_common(tty, cp, fp, count, 1);
}
* Fix tty hang when I_IXON(tty) is cleared, but the tty
* been stopped by STOP_CHAR(tty) before it.
*/
- if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {
+ if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow.tco_stopped) {
start_tty(tty);
process_echoes(tty);
}
*
* Locking: redirected write test is safe
* current->signal->tty check is safe
- * ctrl_lock to safely reference tty->pgrp
+ * ctrl.lock to safely reference tty->ctrl.pgrp
*/
static int job_control(struct tty_struct *tty, struct file *file)
int minimum, time;
ssize_t retval = 0;
long timeout;
- int packet;
+ bool packet;
size_t tail;
/*
}
}
- packet = tty->packet;
+ packet = tty->ctrl.packet;
tail = ldata->read_tail;
add_wait_queue(&tty->read_wait, &wait);
while (nr) {
/* First test for status change. */
- if (packet && tty->link->ctrl_status) {
+ if (packet && tty->link->ctrl.pktstatus) {
unsigned char cs;
if (kb != kbuf)
break;
- spin_lock_irq(&tty->link->ctrl_lock);
- cs = tty->link->ctrl_status;
- tty->link->ctrl_status = 0;
- spin_unlock_irq(&tty->link->ctrl_lock);
+ spin_lock_irq(&tty->link->ctrl.lock);
+ cs = tty->link->ctrl.pktstatus;
+ tty->link->ctrl.pktstatus = 0;
+ spin_unlock_irq(&tty->link->ctrl.lock);
*kb++ = cs;
nr--;
break;
if (input_available_p(tty, 1))
mask |= EPOLLIN | EPOLLRDNORM;
}
- if (tty->packet && tty->link->ctrl_status)
+ if (tty->ctrl.packet && tty->link->ctrl.pktstatus)
mask |= EPOLLPRI | EPOLLIN | EPOLLRDNORM;
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
mask |= EPOLLHUP;
static struct tty_ldisc_ops n_tty_ops = {
.owner = THIS_MODULE,
+ .num = N_TTY,
.name = "n_tty",
.open = n_tty_open,
.close = n_tty_close,
{
*ops = n_tty_ops;
ops->owner = NULL;
- ops->refcount = ops->flags = 0;
+ ops->flags = 0;
}
EXPORT_SYMBOL_GPL(n_tty_inherit_ops);
void __init n_tty_init(void)
{
- tty_register_ldisc(N_TTY, &n_tty_ops);
+ tty_register_ldisc(&n_tty_ops);
}
NOZOMI_NAME, dc);
if (unlikely(ret)) {
dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq);
- goto err_free_kfifo;
+ goto err_free_all_kfifo;
}
DBG1("base_addr: %p", dc->base_addr);
return 0;
err_free_tty:
- for (i = 0; i < MAX_PORT; ++i) {
+ for (i--; i >= 0; i--) {
tty_unregister_device(ntty_driver, dc->index_start + i);
tty_port_destroy(&dc->port[i].port);
}
+ free_irq(pdev->irq, dc);
+err_free_all_kfifo:
+ i = MAX_PORT;
err_free_kfifo:
- for (i = 0; i < MAX_PORT; i++)
+ for (i--; i >= PORT_MDM; i--)
kfifo_free(&dc->port[i].fifo_ul);
err_free_sbuf:
kfree(dc->send_buf);
* If the port is unplugged report lots of room and let the bits
* dribble away so we don't block anything.
*/
-static int ntty_write_room(struct tty_struct *tty)
+static unsigned int ntty_write_room(struct tty_struct *tty)
{
struct port *port = tty->driver_data;
- int room = 4096;
+ unsigned int room = 4096;
const struct nozomi *dc = get_dc_by_tty(tty);
if (dc)
}
/* Returns number of chars in buffer, called by tty layer */
-static s32 ntty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int ntty_chars_in_buffer(struct tty_struct *tty)
{
struct port *port = tty->driver_data;
struct nozomi *dc = get_dc_by_tty(tty);
- s32 rval = 0;
- if (unlikely(!dc || !port)) {
- goto exit_in_buffer;
- }
-
- rval = kfifo_len(&port->fifo_ul);
+ if (unlikely(!dc || !port))
+ return 0;
-exit_in_buffer:
- return rval;
+ return kfifo_len(&port->fifo_ul);
}
static const struct tty_port_operations noz_tty_port_ops = {
set_bit(TTY_IO_ERROR, &tty->flags);
wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait);
- spin_lock_irq(&tty->ctrl_lock);
- tty->packet = 0;
- spin_unlock_irq(&tty->ctrl_lock);
+ spin_lock_irq(&tty->ctrl.lock);
+ tty->ctrl.packet = false;
+ spin_unlock_irq(&tty->ctrl.lock);
/* Review - krefs on tty_link ?? */
if (!tty->link)
return;
struct tty_struct *to = tty->link;
unsigned long flags;
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
if (c > 0) {
* the other device.
*/
-static int pty_write_room(struct tty_struct *tty)
+static unsigned int pty_write_room(struct tty_struct *tty)
{
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
return tty_buffer_space_avail(tty->link->port);
}
-/**
- * pty_chars_in_buffer - characters currently in our tx queue
- * @tty: our tty
- *
- * Report how much we have in the transmit queue. As everything is
- * instantly at the other end this is easy to implement.
- */
-
-static int pty_chars_in_buffer(struct tty_struct *tty)
-{
- return 0;
-}
-
/* Set the lock flag on a pty */
static int pty_set_lock(struct tty_struct *tty, int __user *arg)
{
if (get_user(pktmode, arg))
return -EFAULT;
- spin_lock_irq(&tty->ctrl_lock);
+ spin_lock_irq(&tty->ctrl.lock);
if (pktmode) {
- if (!tty->packet) {
- tty->link->ctrl_status = 0;
+ if (!tty->ctrl.packet) {
+ tty->link->ctrl.pktstatus = 0;
smp_mb();
- tty->packet = 1;
+ tty->ctrl.packet = true;
}
} else
- tty->packet = 0;
- spin_unlock_irq(&tty->ctrl_lock);
+ tty->ctrl.packet = false;
+ spin_unlock_irq(&tty->ctrl.lock);
return 0;
}
/* Get the packet mode of a pty */
static int pty_get_pktmode(struct tty_struct *tty, int __user *arg)
{
- int pktmode = tty->packet;
+ int pktmode = tty->ctrl.packet;
return put_user(pktmode, arg);
}
return;
tty_buffer_flush(to, NULL);
- if (to->packet) {
- spin_lock_irq(&tty->ctrl_lock);
- tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
+ if (to->ctrl.packet) {
+ spin_lock_irq(&tty->ctrl.lock);
+ tty->ctrl.pktstatus |= TIOCPKT_FLUSHWRITE;
wake_up_interruptible(&to->read_wait);
- spin_unlock_irq(&tty->ctrl_lock);
+ spin_unlock_irq(&tty->ctrl.lock);
}
}
struct ktermios *old_termios)
{
/* See if packet mode change of state. */
- if (tty->link && tty->link->packet) {
+ if (tty->link && tty->link->ctrl.packet) {
int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty);
int old_flow = ((old_termios->c_iflag & IXON) &&
(old_termios->c_cc[VSTOP] == '\023') &&
STOP_CHAR(tty) == '\023' &&
START_CHAR(tty) == '\021');
if ((old_flow != new_flow) || extproc) {
- spin_lock_irq(&tty->ctrl_lock);
+ spin_lock_irq(&tty->ctrl.lock);
if (old_flow != new_flow) {
- tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
+ tty->ctrl.pktstatus &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
if (new_flow)
- tty->ctrl_status |= TIOCPKT_DOSTOP;
+ tty->ctrl.pktstatus |= TIOCPKT_DOSTOP;
else
- tty->ctrl_status |= TIOCPKT_NOSTOP;
+ tty->ctrl.pktstatus |= TIOCPKT_NOSTOP;
}
if (extproc)
- tty->ctrl_status |= TIOCPKT_IOCTL;
- spin_unlock_irq(&tty->ctrl_lock);
+ tty->ctrl.pktstatus |= TIOCPKT_IOCTL;
+ spin_unlock_irq(&tty->ctrl.lock);
wake_up_interruptible(&tty->link->read_wait);
}
}
}
/**
- * pty_do_resize - resize event
+ * pty_resize - resize event
* @tty: tty being resized
* @ws: window size being set.
*
{
unsigned long flags;
- if (tty->link && tty->link->packet) {
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- tty->ctrl_status &= ~TIOCPKT_STOP;
- tty->ctrl_status |= TIOCPKT_START;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->link && tty->link->ctrl.packet) {
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ tty->ctrl.pktstatus &= ~TIOCPKT_STOP;
+ tty->ctrl.pktstatus |= TIOCPKT_START;
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
wake_up_interruptible_poll(&tty->link->read_wait, EPOLLIN);
}
}
{
unsigned long flags;
- if (tty->link && tty->link->packet) {
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- tty->ctrl_status &= ~TIOCPKT_START;
- tty->ctrl_status |= TIOCPKT_STOP;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->link && tty->link->ctrl.packet) {
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ tty->ctrl.pktstatus &= ~TIOCPKT_START;
+ tty->ctrl.pktstatus |= TIOCPKT_STOP;
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
wake_up_interruptible_poll(&tty->link->read_wait, EPOLLIN);
}
}
.write = pty_write,
.write_room = pty_write_room,
.flush_buffer = pty_flush_buffer,
- .chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.ioctl = pty_bsd_ioctl,
.compat_ioctl = pty_bsd_compat_ioctl,
.write = pty_write,
.write_room = pty_write_room,
.flush_buffer = pty_flush_buffer,
- .chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.cleanup = pty_cleanup,
*/
int ptm_open_peer(struct file *master, struct tty_struct *tty, int flags)
{
- int fd = -1;
+ int fd;
struct file *filp;
int retval = -EINVAL;
struct path path;
.write = pty_write,
.write_room = pty_write_room,
.flush_buffer = pty_flush_buffer,
- .chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.ioctl = pty_unix98_ioctl,
.compat_ioctl = pty_unix98_compat_ioctl,
.write = pty_write,
.write_room = pty_write_room,
.flush_buffer = pty_flush_buffer,
- .chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
.set_termios = pty_set_termios,
.start = pty_start,
EXPORT_SYMBOL_GPL(serdev_controller_remove);
/**
- * serdev_driver_register() - Register client driver with serdev core
+ * __serdev_device_driver_register() - Register client driver with serdev core
* @sdrv: client driver to be associated with client-device.
* @owner: client driver owner to set.
*
struct aspeed_vuart {
struct device *dev;
- void __iomem *regs;
struct clk *clk;
int line;
struct timer_list unthrottle_timer;
* different system (though most of them use 3f8/4).
*/
+static inline u8 aspeed_vuart_readb(struct aspeed_vuart *vuart, u8 reg)
+{
+ return readb(vuart->port->port.membase + reg);
+}
+
+static inline void aspeed_vuart_writeb(struct aspeed_vuart *vuart, u8 val, u8 reg)
+{
+ writeb(val, vuart->port->port.membase + reg);
+}
+
static ssize_t lpc_address_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
u16 addr;
- addr = (readb(vuart->regs + ASPEED_VUART_ADDRH) << 8) |
- (readb(vuart->regs + ASPEED_VUART_ADDRL));
+ addr = (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRH) << 8) |
+ (aspeed_vuart_readb(vuart, ASPEED_VUART_ADDRL));
return snprintf(buf, PAGE_SIZE - 1, "0x%x\n", addr);
}
if (addr > U16_MAX)
return -EINVAL;
- writeb(addr >> 8, vuart->regs + ASPEED_VUART_ADDRH);
- writeb(addr >> 0, vuart->regs + ASPEED_VUART_ADDRL);
+ aspeed_vuart_writeb(vuart, addr >> 8, ASPEED_VUART_ADDRH);
+ aspeed_vuart_writeb(vuart, addr >> 0, ASPEED_VUART_ADDRL);
return 0;
}
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
u8 reg;
- reg = readb(vuart->regs + ASPEED_VUART_GCRB);
+ reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB);
reg &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
reg >>= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
sirq <<= ASPEED_VUART_GCRB_HOST_SIRQ_SHIFT;
sirq &= ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
- reg = readb(vuart->regs + ASPEED_VUART_GCRB);
+ reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRB);
reg &= ~ASPEED_VUART_GCRB_HOST_SIRQ_MASK;
reg |= sirq;
- writeb(reg, vuart->regs + ASPEED_VUART_GCRB);
+ aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRB);
return 0;
}
struct aspeed_vuart *vuart = dev_get_drvdata(dev);
u8 reg;
- reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+ reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
reg &= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
return snprintf(buf, PAGE_SIZE - 1, "%u\n", reg ? 1 : 0);
static void aspeed_vuart_set_sirq_polarity(struct aspeed_vuart *vuart,
bool polarity)
{
- u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+ u8 reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
if (polarity)
reg |= ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
else
reg &= ~ASPEED_VUART_GCRA_HOST_SIRQ_POLARITY;
- writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
+ aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA);
}
static ssize_t sirq_polarity_store(struct device *dev,
static void aspeed_vuart_set_enabled(struct aspeed_vuart *vuart, bool enabled)
{
- u8 reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+ u8 reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
if (enabled)
reg |= ASPEED_VUART_GCRA_VUART_EN;
else
reg &= ~ASPEED_VUART_GCRA_VUART_EN;
- writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
+ aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA);
}
static void aspeed_vuart_set_host_tx_discard(struct aspeed_vuart *vuart,
{
u8 reg;
- reg = readb(vuart->regs + ASPEED_VUART_GCRA);
+ reg = aspeed_vuart_readb(vuart, ASPEED_VUART_GCRA);
/* If the DISABLE_HOST_TX_DISCARD bit is set, discard is disabled */
if (!discard)
else
reg &= ~ASPEED_VUART_GCRA_DISABLE_HOST_TX_DISCARD;
- writeb(reg, vuart->regs + ASPEED_VUART_GCRA);
+ aspeed_vuart_writeb(vuart, reg, ASPEED_VUART_GCRA);
}
static int aspeed_vuart_startup(struct uart_port *uart_port)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned int iir, lsr;
- int space, count;
+ unsigned int space, count;
iir = serial_port_in(port, UART_IIR);
struct aspeed_vuart *vuart = port->private_data;
__aspeed_vuart_set_throttle(up, true);
- if (!timer_pending(&vuart->unthrottle_timer)) {
- vuart->port = up;
+ if (!timer_pending(&vuart->unthrottle_timer))
mod_timer(&vuart->unthrottle_timer,
jiffies + unthrottle_timeout);
- }
} else {
- count = min(space, 256);
+ count = min(space, 256U);
do {
serial8250_read_char(up, lsr);
timer_setup(&vuart->unthrottle_timer, aspeed_vuart_unthrottle_exp, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- vuart->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(vuart->regs))
- return PTR_ERR(vuart->regs);
memset(&port, 0, sizeof(port));
port.port.private_data = vuart;
- port.port.membase = vuart->regs;
port.port.mapbase = res->start;
port.port.mapsize = resource_size(res);
port.port.startup = aspeed_vuart_startup;
port.port.iotype = UPIO_MEM;
port.port.type = PORT_16550A;
port.port.uartclk = clk;
- port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
+ port.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
| UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_NO_THRE_TEST;
if (of_property_read_bool(np, "no-loopback-test"))
goto err_clk_disable;
vuart->line = rc;
+ vuart->port = serial8250_get_port(vuart->line);
rc = of_parse_phandle_with_fixed_args(
np, "aspeed,sirq-polarity-sense", 2, 0,
static int serial_link_irq_chain(struct uart_8250_port *up)
{
struct hlist_head *h;
- struct hlist_node *n;
struct irq_info *i;
int ret;
h = &irq_lists[up->port.irq % NR_IRQ_HASH];
- hlist_for_each(n, h) {
- i = hlist_entry(n, struct irq_info, node);
+ hlist_for_each_entry(i, h, node)
if (i->irq == up->port.irq)
break;
- }
- if (n == NULL) {
+ if (i == NULL) {
i = kzalloc(sizeof(struct irq_info), GFP_KERNEL);
if (i == NULL) {
mutex_unlock(&hash_mutex);
static void serial_unlink_irq_chain(struct uart_8250_port *up)
{
- /*
- * yes, some broken gcc emit "warning: 'i' may be used uninitialized"
- * but no, we are not going to take a patch that assigns NULL below.
- */
struct irq_info *i;
- struct hlist_node *n;
struct hlist_head *h;
mutex_lock(&hash_mutex);
h = &irq_lists[up->port.irq % NR_IRQ_HASH];
- hlist_for_each(n, h) {
- i = hlist_entry(n, struct irq_info, node);
+ hlist_for_each_entry(i, h, node)
if (i->irq == up->port.irq)
break;
- }
- BUG_ON(n == NULL);
+ BUG_ON(i == NULL);
BUG_ON(i->head == NULL);
if (list_empty(i->head))
* hardware interrupt, we use a timer-based system. The original
* driver used to do this with IRQ0.
*/
- if (!port->irq) {
+ if (!port->irq)
mod_timer(&up->timer, jiffies + uart_poll_timeout(port));
- } else
+ else
retval = serial_link_irq_chain(up);
return retval;
if (!console_suspend_enabled && uart_console(port) &&
port->type != PORT_8250) {
unsigned char canary = 0xa5;
+
serial_out(up, UART_SCR, canary);
if (serial_in(up, UART_SCR) == canary)
up->canary = canary;
*/
static DEFINE_MUTEX(serial_mutex);
-static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port *port)
+static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_port *port)
{
int i;
*
* On success the port is ready to use and the line number is returned.
*/
-int serial8250_register_8250_port(struct uart_8250_port *up)
+int serial8250_register_8250_port(const struct uart_8250_port *up)
{
struct uart_8250_port *uart;
int ret = -ENOSPC;
u32 tx_threshold;
int ret;
+ if (IS_ENABLED(CONFIG_SERIAL_8250_BCM7271) &&
+ of_device_is_compatible(ofdev->dev.of_node, "brcm,bcm7271-uart"))
+ return -ENODEV;
+
port_type = (unsigned long)of_device_get_match_data(&ofdev->dev);
if (port_type == PORT_UNKNOWN)
return -EINVAL;
poll_count--)
cpu_relax();
- if (!poll_count)
+ if (poll_count == -1)
dev_err(p->port.dev, "teardown incomplete\n");
}
}
static int serial_probe(struct pcmcia_device *link)
{
struct serial_info *info;
+ int ret;
dev_dbg(&link->dev, "serial_attach()\n");
if (do_sound)
link->config_flags |= CONF_ENABLE_SPKR;
- return serial_config(link);
+ ret = serial_config(link);
+ if (ret)
+ goto free_info;
+
+ return 0;
+
+free_info:
+ kfree(info);
+ return ret;
}
static void serial_detach(struct pcmcia_device *link)
bool "LiteUART serial port console support"
depends on SERIAL_LITEUART=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
help
Say 'Y' or 'M' here if you wish to use the FPGA-based LiteUART serial
controller from LiteX SoC builder as the system console
struct tty_port *port = &uap->port.state->port;
struct pl011_dmarx_data *dmarx = &uap->dmarx;
struct dma_chan *rxchan = uap->dmarx.chan;
- unsigned long flags = 0;
+ unsigned long flags;
unsigned int dmataken = 0;
unsigned int size = 0;
struct pl011_sgbuf *sgbuf;
/*
* Driver internal routine, used by both tty(serial core) as well as tx-isr
* -Called under spinlock in either cases
- * -also tty->stopped has already been checked
+ * -also tty->flow.stopped has already been checked
* = by uart_start( ) before calling us
* = tx_ist checks that too before calling
*/
#include <linux/irq.h>
#include <linux/suspend.h>
#include <linux/mm.h>
+#include <linux/io.h>
#include <asm/div64.h>
-#include <asm/io.h>
#include <asm/ioctls.h>
#define PDC_BUFFER_SIZE 512
#include <linux/tty_flip.h>
#include <linux/atomic.h>
+#include <linux/io.h>
#include <asm/bootinfo.h>
-#include <asm/io.h>
#include <asm/dec/interrupts.h>
#include <asm/dec/kn01.h>
* rs_stop () and rs_start ()
*
* These routines are called before setting or resetting
- * tty->stopped. They enable or disable transmitter interrupts,
+ * tty->flow.stopped. They enable or disable transmitter interrupts,
* as necessary.
* ------------------------------------------------------------
*/
static void lpuart_txint(struct lpuart_port *sport)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
lpuart_transmit_buffer(sport);
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ spin_unlock(&sport->port.lock);
}
static void lpuart_rxint(struct lpuart_port *sport)
{
unsigned int flg, ignored = 0, overrun = 0;
struct tty_port *port = &sport->port.state->port;
- unsigned long flags;
unsigned char rx, sr;
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
while (!(readb(sport->port.membase + UARTSFIFO) & UARTSFIFO_RXEMPT)) {
flg = TTY_NORMAL;
sr = readb(sport->port.membase + UARTSR1);
rx = readb(sport->port.membase + UARTDR);
- if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
+ if (uart_prepare_sysrq_char(&sport->port, rx))
continue;
if (sr & (UARTSR1_PE | UARTSR1_OR | UARTSR1_FE)) {
writeb(UARTSFIFO_RXOF, sport->port.membase + UARTSFIFO);
}
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ uart_unlock_and_check_sysrq(&sport->port);
tty_flip_buffer_push(port);
}
static void lpuart32_txint(struct lpuart_port *sport)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
lpuart32_transmit_buffer(sport);
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ spin_unlock(&sport->port.lock);
}
static void lpuart32_rxint(struct lpuart_port *sport)
{
unsigned int flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
- unsigned long flags;
unsigned long rx, sr;
+ bool is_break;
- spin_lock_irqsave(&sport->port.lock, flags);
+ spin_lock(&sport->port.lock);
while (!(lpuart32_read(&sport->port, UARTFIFO) & UARTFIFO_RXEMPT)) {
flg = TTY_NORMAL;
*/
sr = lpuart32_read(&sport->port, UARTSTAT);
rx = lpuart32_read(&sport->port, UARTDATA);
- rx &= 0x3ff;
+ rx &= UARTDATA_MASK;
+
+ /*
+ * The LPUART can't distinguish between a break and a framing error,
+ * thus we assume it is a break if the received data is zero.
+ */
+ is_break = (sr & UARTSTAT_FE) && !rx;
- if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
+ if (is_break && uart_handle_break(&sport->port))
+ continue;
+
+ if (uart_prepare_sysrq_char(&sport->port, rx))
continue;
if (sr & (UARTSTAT_PE | UARTSTAT_OR | UARTSTAT_FE)) {
- if (sr & UARTSTAT_PE)
- sport->port.icount.parity++;
- else if (sr & UARTSTAT_FE)
+ if (sr & UARTSTAT_PE) {
+ if (is_break)
+ sport->port.icount.brk++;
+ else
+ sport->port.icount.parity++;
+ } else if (sr & UARTSTAT_FE) {
sport->port.icount.frame++;
+ }
if (sr & UARTSTAT_OR)
sport->port.icount.overrun++;
sr &= sport->port.read_status_mask;
- if (sr & UARTSTAT_PE)
- flg = TTY_PARITY;
- else if (sr & UARTSTAT_FE)
+ if (sr & UARTSTAT_PE) {
+ if (is_break)
+ flg = TTY_BREAK;
+ else
+ flg = TTY_PARITY;
+ } else if (sr & UARTSTAT_FE) {
flg = TTY_FRAME;
+ }
if (sr & UARTSTAT_OR)
flg = TTY_OVERRUN;
-
- sport->port.sysrq = 0;
}
tty_insert_flip_char(port, rx, flg);
}
out:
- spin_unlock_irqrestore(&sport->port.lock, flags);
+ uart_unlock_and_check_sysrq(&sport->port);
tty_flip_buffer_push(port);
}
static unsigned int lpuart_get_mctrl(struct uart_port *port)
{
- unsigned int temp = 0;
- unsigned char reg;
-
- reg = readb(port->membase + UARTMODEM);
- if (reg & UARTMODEM_TXCTSE)
- temp |= TIOCM_CTS;
+ unsigned int mctrl = 0;
+ u8 reg;
- if (reg & UARTMODEM_RXRTSE)
- temp |= TIOCM_RTS;
+ reg = readb(port->membase + UARTCR1);
+ if (reg & UARTCR1_LOOPS)
+ mctrl |= TIOCM_LOOP;
- return temp;
+ return mctrl;
}
static unsigned int lpuart32_get_mctrl(struct uart_port *port)
{
- unsigned int temp = 0;
- unsigned long reg;
-
- reg = lpuart32_read(port, UARTMODIR);
- if (reg & UARTMODIR_TXCTSE)
- temp |= TIOCM_CTS;
+ unsigned int mctrl = 0;
+ u32 reg;
- if (reg & UARTMODIR_RXRTSE)
- temp |= TIOCM_RTS;
+ reg = lpuart32_read(port, UARTCTRL);
+ if (reg & UARTCTRL_LOOPS)
+ mctrl |= TIOCM_LOOP;
- return temp;
+ return mctrl;
}
static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- unsigned char temp;
- struct lpuart_port *sport = container_of(port,
- struct lpuart_port, port);
+ u8 reg;
- /* Make sure RXRTSE bit is not set when RS485 is enabled */
- if (!(sport->port.rs485.flags & SER_RS485_ENABLED)) {
- temp = readb(sport->port.membase + UARTMODEM) &
- ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE);
+ reg = readb(port->membase + UARTCR1);
- if (mctrl & TIOCM_RTS)
- temp |= UARTMODEM_RXRTSE;
+ /* for internal loopback we need LOOPS=1 and RSRC=0 */
+ reg &= ~(UARTCR1_LOOPS | UARTCR1_RSRC);
+ if (mctrl & TIOCM_LOOP)
+ reg |= UARTCR1_LOOPS;
- if (mctrl & TIOCM_CTS)
- temp |= UARTMODEM_TXCTSE;
-
- writeb(temp, port->membase + UARTMODEM);
- }
+ writeb(reg, port->membase + UARTCR1);
}
static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
+ u32 reg;
+
+ reg = lpuart32_read(port, UARTCTRL);
+ /* for internal loopback we need LOOPS=1 and RSRC=0 */
+ reg &= ~(UARTCTRL_LOOPS | UARTCTRL_RSRC);
+ if (mctrl & TIOCM_LOOP)
+ reg |= UARTCTRL_LOOPS;
+
+ lpuart32_write(port, reg, UARTCTRL);
}
static void lpuart_break_ctl(struct uart_port *port, int break_state)
u32 uartbaud;
int ret;
+ if (uart_console(&sport->port))
+ goto err;
+
if (!sport->dma_tx_chan)
goto err;
int ret;
unsigned char cr3;
+ if (uart_console(&sport->port))
+ goto err;
+
if (!sport->dma_rx_chan)
goto err;
sport->lpuart_dma_rx_use = true;
rx_dma_timer_init(sport);
- if (sport->port.has_sysrq) {
+ if (sport->port.has_sysrq && !lpuart_is_32(sport)) {
cr3 = readb(sport->port.membase + UARTCR3);
cr3 |= UARTCR3_FEIE;
writeb(cr3, sport->port.membase + UARTCR3);
unsigned long flags;
int locked = 1;
- if (sport->port.sysrq || oops_in_progress)
+ if (oops_in_progress)
locked = spin_trylock_irqsave(&sport->port.lock, flags);
else
spin_lock_irqsave(&sport->port.lock, flags);
unsigned long flags;
int locked = 1;
- if (sport->port.sysrq || oops_in_progress)
+ if (oops_in_progress)
locked = spin_trylock_irqsave(&sport->port.lock, flags);
else
spin_lock_irqsave(&sport->port.lock, flags);
bd = lpuart32_read(&sport->port, UARTBAUD);
bd &= UARTBAUD_SBR_MASK;
+ if (!bd)
+ return;
+
sbr = bd;
uartclk = lpuart_get_baud_clk_rate(sport);
/*
#include <linux/firmware.h>
#include <linux/bitops.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <linux/uaccess.h>
{
struct imx_port *sport = imx_uart_ports[co->index];
struct imx_port_ucrs old_ucr;
+ unsigned long flags;
unsigned int ucr1;
- unsigned long flags = 0;
int locked = 1;
if (sport->port.sysrq)
#include <linux/spinlock.h>
#include <linux/init.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/sgialib.h>
#include <asm/sgi/ioc.h>
static int kgdb_nmi_poll_one_knock(void)
{
static int n;
- int c = -1;
+ int c;
const char *magic = kgdb_nmi_magic;
size_t m = strlen(magic);
bool printch = false;
tty_port_hangup(&priv->port);
}
-static int kgdb_nmi_tty_write_room(struct tty_struct *tty)
+static unsigned int kgdb_nmi_tty_write_room(struct tty_struct *tty)
{
/* Actually, we can handle any amount as we use polled writes. */
return 2048;
return 0;
}
console_initcall(liteuart_console_init);
+
+static void early_liteuart_write(struct console *console, const char *s,
+ unsigned int count)
+{
+ struct earlycon_device *device = console->data;
+ struct uart_port *port = &device->port;
+
+ uart_console_write(port, s, count, liteuart_putchar);
+}
+
+static int __init early_liteuart_setup(struct earlycon_device *device,
+ const char *options)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = early_liteuart_write;
+ return 0;
+}
+
+OF_EARLYCON_DECLARE(liteuart, "litex,liteuart", early_liteuart_setup);
#endif /* CONFIG_SERIAL_LITEUART_CONSOLE */
static int __init liteuart_init(void)
return 1;
}
-static int max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
+static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
unsigned long freq, bool xtal)
{
unsigned int div, clksrc, pllcfg = 0;
}
}
- return (int)bestfreq;
+ return bestfreq;
}
static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len)
static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype,
struct regmap *regmap, int irq)
{
- int i, ret, fmin, fmax, freq, uartclk;
+ int i, ret, fmin, fmax, freq;
struct max310x_port *s;
- bool xtal = false;
+ u32 uartclk = 0;
+ bool xtal;
if (IS_ERR(regmap))
return PTR_ERR(regmap);
return -ENOMEM;
}
+ /* Always ask for fixed clock rate from a property. */
+ device_property_read_u32(dev, "clock-frequency", &uartclk);
+
s->clk = devm_clk_get_optional(dev, "osc");
if (IS_ERR(s->clk))
return PTR_ERR(s->clk);
if (s->clk) {
- fmin = 500000;
- fmax = 35000000;
+ xtal = false;
} else {
s->clk = devm_clk_get_optional(dev, "xtal");
if (IS_ERR(s->clk))
return PTR_ERR(s->clk);
- if (s->clk) {
- fmin = 1000000;
- fmax = 4000000;
- xtal = true;
- } else {
- dev_err(dev, "Cannot get clock\n");
- return -EINVAL;
- }
+
+ xtal = true;
}
ret = clk_prepare_enable(s->clk);
return ret;
freq = clk_get_rate(s->clk);
+ if (freq == 0)
+ freq = uartclk;
+ if (freq == 0) {
+ dev_err(dev, "Cannot get clock rate\n");
+ return -EINVAL;
+ }
+
+ if (xtal) {
+ fmin = 1000000;
+ fmax = 4000000;
+ } else {
+ fmin = 500000;
+ fmax = 35000000;
+ }
+
/* Check frequency limits */
if (freq < fmin || freq > fmax) {
ret = -ERANGE;
{
struct resource *res_mem, *res_irq;
struct uart_port *port;
+ u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */
int ret = 0;
- int id = -1;
if (pdev->dev.of_node)
pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
if (pdev->id < 0) {
+ int id;
+
for (id = AML_UART_PORT_OFFSET; id < AML_UART_PORT_NUM; id++) {
if (!meson_ports[id]) {
pdev->id = id;
if (!res_irq)
return -ENODEV;
+ of_property_read_u32(pdev->dev.of_node, "fifo-size", &fifosize);
+
if (meson_ports[pdev->id]) {
dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
return -EBUSY;
port->type = PORT_MESON;
port->x_char = 0;
port->ops = &meson_uart_ops;
- port->fifosize = 64;
+ port->fifosize = fifosize;
meson_ports[pdev->id] = port;
platform_set_drvdata(pdev, port);
#include <linux/console.h>
#include <linux/delay.h> /* for udelay */
#include <linux/device.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/parisc-device.h>
static unsigned int serial_omap_tx_empty(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- unsigned long flags = 0;
+ unsigned long flags;
unsigned int ret = 0;
pm_runtime_get_sync(up->dev);
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line);
pm_runtime_get_sync(up->dev);
static int serial_omap_startup(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- unsigned long flags = 0;
+ unsigned long flags;
int retval;
/*
static void serial_omap_shutdown(struct uart_port *port)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- unsigned long flags = 0;
+ unsigned long flags;
dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line);
{
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned char cval = 0;
- unsigned long flags = 0;
+ unsigned long flags;
unsigned int baud, quot;
switch (termios->c_cflag & CSIZE) {
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <asm/sections.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#ifdef CONFIG_PPC_PMAC
static int qcom_geni_serial_probe(struct platform_device *pdev)
{
int ret = 0;
- int line = -1;
+ int line;
struct qcom_geni_serial_port *port;
struct uart_port *uport;
struct resource *res;
default:
dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n",
prop);
- ret = -EINVAL;
- break;
+ return -EINVAL;
}
}
}
#include <linux/types.h>
#include <linux/refcount.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/sibyte/sb1250.h>
#include <asm/sibyte/sb1250_uart.h>
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk);
- s->clk = devm_clk_get(dev, NULL);
- if (IS_ERR(s->clk)) {
+ s->clk = devm_clk_get_optional(dev, NULL);
+ if (IS_ERR(s->clk))
+ return PTR_ERR(s->clk);
+
+ ret = clk_prepare_enable(s->clk);
+ if (ret)
+ return ret;
+
+ freq = clk_get_rate(s->clk);
+ if (freq == 0) {
if (uartclk)
freq = uartclk;
if (pfreq)
if (freq)
dev_dbg(dev, "Clock frequency: %luHz\n", freq);
else
- return PTR_ERR(s->clk);
- } else {
- ret = clk_prepare_enable(s->clk);
- if (ret)
- return ret;
-
- freq = clk_get_rate(s->clk);
+ return -EINVAL;
}
s->regmap = regmap;
kthread_stop(s->kworker_task);
out_clk:
- if (!IS_ERR(s->clk))
- clk_disable_unprepare(s->clk);
+ clk_disable_unprepare(s->clk);
return ret;
}
kthread_flush_worker(&s->kworker);
kthread_stop(s->kworker_task);
- if (!IS_ERR(s->clk))
- clk_disable_unprepare(s->clk);
+ clk_disable_unprepare(s->clk);
return 0;
}
int init_hw)
{
struct uart_port *uport = uart_port_check(state);
+ unsigned long flags;
unsigned long page;
- unsigned long flags = 0;
int retval = 0;
if (uport->type == PORT_UNKNOWN)
{
struct uart_port *uport = uart_port_check(state);
struct tty_port *port = &state->port;
- unsigned long flags = 0;
+ unsigned long flags;
char *xmit_buf = NULL;
/*
return ret;
}
-static int uart_write_room(struct tty_struct *tty)
+static unsigned int uart_write_room(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
unsigned long flags;
- int ret;
+ unsigned int ret;
port = uart_port_lock(state, flags);
ret = uart_circ_chars_free(&state->xmit);
return ret;
}
-static int uart_chars_in_buffer(struct tty_struct *tty)
+static unsigned int uart_chars_in_buffer(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
unsigned long flags;
- int ret;
+ unsigned int ret;
port = uart_port_lock(state, flags);
ret = uart_circ_chars_pending(&state->xmit);
/*
* Are the two ports equivalent?
*/
-int uart_match_port(struct uart_port *port1, struct uart_port *port2)
+bool uart_match_port(const struct uart_port *port1,
+ const struct uart_port *port2)
{
if (port1->iotype != port2->iotype)
- return 0;
+ return false;
switch (port1->iotype) {
case UPIO_PORT:
- return (port1->iobase == port2->iobase);
+ return port1->iobase == port2->iobase;
case UPIO_HUB6:
- return (port1->iobase == port2->iobase) &&
- (port1->hub6 == port2->hub6);
+ return port1->iobase == port2->iobase &&
+ port1->hub6 == port2->hub6;
case UPIO_MEM:
case UPIO_MEM16:
case UPIO_MEM32:
case UPIO_MEM32BE:
case UPIO_AU:
case UPIO_TSI:
- return (port1->mapbase == port2->mapbase);
+ return port1->mapbase == port2->mapbase;
}
- return 0;
+
+ return false;
}
EXPORT_SYMBOL(uart_match_port);
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <asm/io.h>
+#include <linux/io.h>
static char *serial_version = "1.11";
static char *serial_name = "TX39/49 Serial driver";
/* ASC_RXBUF */
#define ASC_RXBUF_PE 0x100
#define ASC_RXBUF_FE 0x200
-/**
+/*
* Some of status comes from higher bits of the character and some come from
* the status register. Combining both of them in to single status using dummy
* bits.
unsigned int oldstate)
{
struct asc_port *ascport = to_asc_port(port);
- unsigned long flags = 0;
+ unsigned long flags;
u32 ctl;
switch (state) {
struct stm32_port, port);
const struct stm32_usart_offsets *ofs = &stm32port->info->ofs;
const struct stm32_usart_config *cfg = &stm32port->info->cfg;
- unsigned long flags = 0;
+ unsigned long flags;
switch (state) {
case UART_PM_STATE_ON:
#include <linux/init.h>
#include <linux/of_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/setup.h>
#include <linux/delay.h>
#include <linux/of_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/setup.h>
#include <linux/init.h>
#include <linux/of_device.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/prom.h>
#include <asm/setup.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/vr41xx/siu.h>
#include <asm/vr41xx/vr41xx.h>
#ifdef CONFIG_COMMON_CLK
/**
- * cdns_uart_clk_notitifer_cb - Clock notifier callback
+ * cdns_uart_clk_notifier_cb - Clock notifier callback
* @nb: Notifier block
* @event: Notify event
* @data: Notifier data
struct uart_port *port;
int locked = 0;
struct clk_notifier_data *ndata = data;
- unsigned long flags = 0;
struct cdns_uart *cdns_uart = to_cdns_uart(nb);
+ unsigned long flags;
port = cdns_uart->port;
if (port->suspended)
unsigned int count)
{
struct uart_port *port = console_port;
- unsigned long flags = 0;
+ unsigned long flags;
unsigned int imr, ctrl;
int locked = 1;
may_wake = device_may_wakeup(device);
if (console_suspend_enabled && uart_console(port) && may_wake) {
- unsigned long flags = 0;
+ unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
/* Empty the receive FIFO 1st before making changes */
{
struct uart_port *port = dev_get_drvdata(device);
struct cdns_uart *cdns_uart = port->private_data;
- unsigned long flags = 0;
+ unsigned long flags;
u32 ctrl_reg;
int may_wake;
if (!info->tx_buf || (count > info->max_frame_size))
return -EIO;
- if (!count || tty->stopped || tty->hw_stopped)
+ if (!count || tty->flow.stopped || tty->hw_stopped)
return 0;
spin_lock_irqsave(&info->lock, flags);
DBGINFO(("%s wait_until_sent exit\n", info->device_name));
}
-static int write_room(struct tty_struct *tty)
+static unsigned int write_room(struct tty_struct *tty)
{
struct slgt_info *info = tty->driver_data;
- int ret;
+ unsigned int ret;
if (sanity_check(info, tty->name, "write_room"))
return 0;
ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;
- DBGINFO(("%s write_room=%d\n", info->device_name, ret));
+ DBGINFO(("%s write_room=%u\n", info->device_name, ret));
return ret;
}
return;
DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count));
- if (info->tx_count <= 0 || tty->stopped ||
+ if (info->tx_count <= 0 || tty->flow.stopped ||
tty->hw_stopped || !info->tx_buf)
return;
/*
* return count of bytes in transmit buffer
*/
-static int chars_in_buffer(struct tty_struct *tty)
+static unsigned int chars_in_buffer(struct tty_struct *tty)
{
struct slgt_info *info = tty->driver_data;
- int count;
+ unsigned int count;
if (sanity_check(info, tty->name, "chars_in_buffer"))
return 0;
count = tbuf_bytes(info);
- DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, count));
+ DBGINFO(("%s chars_in_buffer()=%u\n", info->device_name, count));
return count;
}
else
#endif
{
- if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) {
+ if (info->port.tty && (info->port.tty->flow.stopped || info->port.tty->hw_stopped)) {
tx_stop(info);
return;
}
int iclose = ibaud/50, oclose = obaud/50;
int ibinput = 0;
- if (obaud == 0) /* CD dropped */
+ if (obaud == 0) /* CD dropped */
ibaud = 0; /* Clear ibaud to be sure */
termios->c_ispeed = ibaud;
#endif
#ifdef BOTHER
/* If the user asked for a precise weird speed give a precise weird
- answer. If they asked for a Bfoo speed they may have problems
- digesting non-exact replies so fuzz a bit */
+ * answer. If they asked for a Bfoo speed they may have problems
+ * digesting non-exact replies so fuzz a bit.
+ */
if ((termios->c_cflag & CBAUD) == BOTHER) {
oclose = 0;
if (ibaud - iclose <= baud_table[i] &&
ibaud + iclose >= baud_table[i]) {
/* For the case input == output don't set IBAUD bits
- if the user didn't do so */
+ * if the user didn't do so.
+ */
if (ofound == i && !ibinput)
ifound = i;
#ifdef IBSHIFT
if (ofound == -1)
termios->c_cflag |= BOTHER;
/* Set exact input bits only if the input and output differ or the
- user already did */
+ * user already did.
+ */
if (ifound == -1 && (ibaud != obaud || ibinput))
termios->c_cflag |= (BOTHER << IBSHIFT);
#else
* We default to dicing tty buffer allocations to this many characters
* in order to avoid multiple page allocations. We know the size of
* tty_buffer itself but it must also be taken into account that the
- * the buffer is 256 byte aligned. See tty_buffer_find for the allocation
- * logic this must match
+ * buffer is 256 byte aligned. See tty_buffer_find for the allocation
+ * logic this must match.
*/
#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
* pre-allocate if memory guarantee is required).
*/
-int tty_buffer_space_avail(struct tty_port *port)
+unsigned int tty_buffer_space_avail(struct tty_port *port)
{
int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used);
+
return max(space, 0);
}
EXPORT_SYMBOL_GPL(tty_buffer_space_avail);
}
/* Should possibly check if this fails for the largest buffer we
- have queued and recycle that ? */
+ * have queued and recycle that ?
+ */
if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit)
return NULL;
p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
}
/**
- * tty_buffer_request_room - grow tty buffer if needed
+ * __tty_buffer_request_room - grow tty buffer if needed
* @port: tty port
* @size: size desired
* @flags: buffer flags if new buffer allocated (default = 0)
const unsigned char *chars, char flag, size_t size)
{
int copied = 0;
+
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;
int space = __tty_buffer_request_room(port, goal, flags);
struct tty_buffer *tb = port->buf.tail;
+
if (unlikely(space == 0))
break;
memcpy(char_buf_ptr(tb, tb->used), chars, space);
copied += space;
chars += space;
/* There is a small chance that we need to split the data over
- several buffers. If this is the case we must loop */
+ * several buffers. If this is the case we must loop.
+ */
} while (unlikely(size > copied));
return copied;
}
const unsigned char *chars, const char *flags, size_t size)
{
int copied = 0;
+
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int space = tty_buffer_request_room(port, goal);
struct tty_buffer *tb = port->buf.tail;
+
if (unlikely(space == 0))
break;
memcpy(char_buf_ptr(tb, tb->used), chars, space);
chars += space;
flags += space;
/* There is a small chance that we need to split the data over
- several buffers. If this is the case we must loop */
+ * several buffers. If this is the case we must loop.
+ */
} while (unlikely(size > copied));
return copied;
}
size_t size)
{
int space = __tty_buffer_request_room(port, size, TTYB_NORMAL);
+
if (likely(space)) {
struct tty_buffer *tb = port->buf.tail;
+
*chars = char_buf_ptr(tb, tb->used);
if (~tb->flags & TTYB_NORMAL)
memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
* Returns the number of bytes processed
*/
int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
- char *f, int count)
+ const char *f, int count)
{
if (ld->ops->receive_buf2)
count = ld->ops->receive_buf2(ld->tty, p, f, count);
receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
{
unsigned char *p = char_buf_ptr(head, head->read);
- char *f = NULL;
+ const char *f = NULL;
int n;
if (~head->flags & TTYB_NORMAL)
* -- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
*
* Rewrote canonical mode and added more termios flags.
- * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
+ * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
*
* Reorganized FASYNC support so mouse code can share it.
* -- ctm@ardi.com, 9Sep95
.c_ospeed = 38400,
/* .c_line = N_TTY, */
};
-
EXPORT_SYMBOL(tty_std_termios);
/* This list gets poked at by procfs and various bits of boot up code. This
- could do with some rationalisation such as pulling the tty proc function
- into this file */
+ * could do with some rationalisation such as pulling the tty proc function
+ * into this file.
+ */
LIST_HEAD(tty_drivers); /* linked list of tty drivers */
return "NULL tty";
return tty->name;
}
-
EXPORT_SYMBOL(tty_name);
const char *tty_driver_name(const struct tty_struct *tty)
list_for_each_entry(p, &tty_drivers, tty_drivers) {
dev_t base = MKDEV(p->major, p->minor_start);
+
if (device < base || device >= base + p->num)
continue;
*index = device - base;
}
wake_up_interruptible_poll(&tty->write_wait, EPOLLOUT);
}
-
EXPORT_SYMBOL_GPL(tty_wakeup);
/**
set_bit(TTY_HUPPING, &tty->flags);
/* inuse_filps is protected by the single tty lock,
- this really needs to change if we want to flush the
- workqueue with the lock held */
+ * this really needs to change if we want to flush the
+ * workqueue with the lock held.
+ */
check_tty_count(tty, "tty_hangup");
spin_lock(&tty->files_lock);
tty_ldisc_hangup(tty, cons_filp != NULL);
- spin_lock_irq(&tty->ctrl_lock);
+ spin_lock_irq(&tty->ctrl.lock);
clear_bit(TTY_THROTTLED, &tty->flags);
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- put_pid(tty->session);
- put_pid(tty->pgrp);
- tty->session = NULL;
- tty->pgrp = NULL;
- tty->ctrl_status = 0;
- spin_unlock_irq(&tty->ctrl_lock);
+ put_pid(tty->ctrl.session);
+ put_pid(tty->ctrl.pgrp);
+ tty->ctrl.session = NULL;
+ tty->ctrl.pgrp = NULL;
+ tty->ctrl.pktstatus = 0;
+ spin_unlock_irq(&tty->ctrl.lock);
/*
* If one of the devices matches a console pointer, we
tty_debug_hangup(tty, "hangup\n");
schedule_work(&tty->hangup_work);
}
-
EXPORT_SYMBOL(tty_hangup);
/**
tty_debug_hangup(tty, "vhangup\n");
__tty_hangup(tty, 0);
}
-
EXPORT_SYMBOL(tty_vhangup);
{
return (filp && filp->f_op == &hung_up_tty_fops);
}
-
EXPORT_SYMBOL(tty_hung_up_p);
+void __stop_tty(struct tty_struct *tty)
+{
+ if (tty->flow.stopped)
+ return;
+ tty->flow.stopped = true;
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
+}
+
/**
* stop_tty - propagate flow control
* @tty: tty to stop
* but not always.
*
* Locking:
- * flow_lock
+ * flow.lock
*/
-
-void __stop_tty(struct tty_struct *tty)
-{
- if (tty->stopped)
- return;
- tty->stopped = 1;
- if (tty->ops->stop)
- tty->ops->stop(tty);
-}
-
void stop_tty(struct tty_struct *tty)
{
unsigned long flags;
- spin_lock_irqsave(&tty->flow_lock, flags);
+ spin_lock_irqsave(&tty->flow.lock, flags);
__stop_tty(tty);
- spin_unlock_irqrestore(&tty->flow_lock, flags);
+ spin_unlock_irqrestore(&tty->flow.lock, flags);
}
EXPORT_SYMBOL(stop_tty);
+void __start_tty(struct tty_struct *tty)
+{
+ if (!tty->flow.stopped || tty->flow.tco_stopped)
+ return;
+ tty->flow.stopped = false;
+ if (tty->ops->start)
+ tty->ops->start(tty);
+ tty_wakeup(tty);
+}
+
/**
* start_tty - propagate flow control
* @tty: tty to start
* start method is invoked and the line discipline woken.
*
* Locking:
- * flow_lock
+ * flow.lock
*/
-
-void __start_tty(struct tty_struct *tty)
-{
- if (!tty->stopped || tty->flow_stopped)
- return;
- tty->stopped = 0;
- if (tty->ops->start)
- tty->ops->start(tty);
- tty_wakeup(tty);
-}
-
void start_tty(struct tty_struct *tty)
{
unsigned long flags;
- spin_lock_irqsave(&tty->flow_lock, flags);
+ spin_lock_irqsave(&tty->flow.lock, flags);
__start_tty(tty);
- spin_unlock_irqrestore(&tty->flow_lock, flags);
+ spin_unlock_irqrestore(&tty->flow.lock, flags);
}
EXPORT_SYMBOL(start_tty);
/**
* tty_read - read method for tty device files
- * @file: pointer to tty file
- * @buf: user buffer
- * @count: size of user buffer
- * @ppos: unused
+ * @iocb: kernel I/O control block
+ * @to: destination for the data read
*
* Perform the read system call function on this terminal device. Checks
* for hung up devices before calling the line discipline method.
return -EIO;
/* We want to wait for the line discipline to sort out in this
- situation */
+ * situation.
+ */
ld = tty_ldisc_ref_wait(tty);
if (!ld)
return hung_up_tty_read(iocb, to);
/* Do the write .. */
for (;;) {
size_t size = count;
+
if (size > chunk)
size = chunk;
tty_unlock(tty);
tty_write_unlock(tty);
}
- return;
}
-
-/**
- * tty_write - write method for tty device file
- * @file: tty file pointer
- * @buf: user data to write
- * @count: bytes to write
- * @ppos: unused
- *
- * Write data to a tty device via the line discipline.
- *
- * Locking:
- * Locks the line discipline as required
- * Writes to the tty driver are serialized by the atomic_write_lock
- * and are then processed in chunks to the device. The line discipline
- * write method will not be invoked in parallel for each device.
- */
-
static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_iter *from)
{
struct tty_struct *tty = file_tty(file);
- struct tty_ldisc *ld;
+ struct tty_ldisc *ld;
ssize_t ret;
if (tty_paranoia_check(tty, file_inode(file), "tty_write"))
return -EIO;
if (!tty || !tty->ops->write || tty_io_error(tty))
- return -EIO;
+ return -EIO;
/* Short term debug to catch buggy drivers */
if (tty->ops->write_room == NULL)
tty_err(tty, "missing write_room method\n");
return ret;
}
+/**
+ * tty_write - write method for tty device file
+ * @iocb: kernel I/O control block
+ * @from: iov_iter with data to write
+ *
+ * Write data to a tty device via the line discipline.
+ *
+ * Locking:
+ * Locks the line discipline as required
+ * Writes to the tty driver are serialized by the atomic_write_lock
+ * and are then processed in chunks to the device. The line
+ * discipline write method will not be invoked in parallel for
+ * each device.
+ */
static ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from)
{
return file_tty_write(iocb->ki_filp, iocb, from);
spin_unlock(&redirect_lock);
/*
- * We know the redirected tty is just another tty, we can can
+ * We know the redirected tty is just another tty, we can
* call file_tty_write() directly with that file pointer.
*/
if (p) {
ssize_t res;
+
res = file_tty_write(p, iocb, iter);
fput(p);
return res;
int tty_send_xchar(struct tty_struct *tty, char ch)
{
- int was_stopped = tty->stopped;
+ bool was_stopped = tty->flow.stopped;
if (tty->ops->send_xchar) {
down_read(&tty->termios_rwsem);
list_del_init(&tty->tty_files);
spin_unlock(&tty->files_lock);
- put_pid(tty->pgrp);
- put_pid(tty->session);
+ put_pid(tty->ctrl.pgrp);
+ put_pid(tty->ctrl.session);
free_tty_struct(tty);
}
struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
/* The hangup queue is now free so we can reuse it rather than
- waste a chunk of memory for each port */
+ * waste a chunk of memory for each port.
+ */
INIT_WORK(&tty->hangup_work, release_one_tty);
schedule_work(&tty->hangup_work);
}
*/
if (!tty->count) {
read_lock(&tasklist_lock);
- session_clear_tty(tty->session);
+ session_clear_tty(tty->ctrl.session);
if (o_tty)
- session_clear_tty(o_tty->session);
+ session_clear_tty(o_tty->ctrl.session);
read_unlock(&tasklist_lock);
}
tty_unlock(tty);
/* At this point, the tty->count == 0 should ensure a dead tty
- cannot be re-opened by a racing opener */
+ * cannot be re-opened by a racing opener.
+ */
if (!final)
return 0;
* @index: index for the device in the @return driver
* @return: driver for this inode (with increased refcount)
*
- * If @return is not erroneous, the caller is responsible to decrement the
- * refcount by tty_driver_kref_put.
+ * If @return is not erroneous, the caller is responsible to decrement the
+ * refcount by tty_driver_kref_put.
*
* Locking: tty_mutex protects get_tty_driver
*/
#ifdef CONFIG_VT
case MKDEV(TTY_MAJOR, 0): {
extern struct tty_driver *console_driver;
+
driver = tty_driver_kref_get(console_driver);
*index = fg_console;
break;
#endif
case MKDEV(TTYAUX_MAJOR, 1): {
struct tty_driver *console_driver = console_device(index);
+
if (console_driver) {
driver = tty_driver_kref_get(console_driver);
if (driver && filp) {
enum pid_type type;
struct pid *pid;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- if (tty->pgrp) {
- pid = tty->pgrp;
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ if (tty->ctrl.pgrp) {
+ pid = tty->ctrl.pgrp;
type = PIDTYPE_PGID;
} else {
pid = task_pid(current);
type = PIDTYPE_TGID;
}
get_pid(pid);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
__f_setown(filp, pid, type, 0);
put_pid(pid);
retval = 0;
err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
mutex_unlock(&tty->winsize_mutex);
- return err ? -EFAULT: 0;
+ return err ? -EFAULT : 0;
}
/**
*
* Locking:
* Driver dependent. The default do_resize method takes the
- * tty termios mutex and ctrl_lock. The console takes its own lock
+ * tty termios mutex and ctrl.lock. The console takes its own lock
* then calls into the default method.
*/
static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg)
{
struct winsize tmp_ws;
+
if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
return -EFAULT;
return -EPERM;
if (file->f_op->write_iter == redirected_tty_write) {
struct file *f;
+
spin_lock(&redirect_lock);
f = redirect;
redirect = NULL;
case TIOCGEXCL:
{
int excl = test_bit(TTY_EXCLUSIVE, &tty->flags);
+
return put_user(excl, (int __user *)p);
}
case TIOCGETD:
case TIOCGDEV:
{
unsigned int ret = new_encode_dev(tty_devnum(real_tty));
+
return put_user(ret, (unsigned int __user *)p);
}
/*
return 0;
return file_tty(file) != t ? 0 : fd + 1;
}
-
+
/*
* This implements the "Secure Attention Key" --- the idea is to
* prevent trojan horses by killing all processes associated with this
if (!tty)
return;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- session = get_pid(tty->session);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ session = get_pid(tty->ctrl.session);
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
tty_ldisc_flush(tty);
return;
schedule_work(&tty->SAK_work);
}
-
EXPORT_SYMBOL(do_SAK);
/* Must put_device() after it's unused! */
static struct device *tty_get_device(struct tty_struct *tty)
{
dev_t devt = tty_devnum(tty);
+
return class_find_device_by_devt(tty_class, devt);
}
kfree(tty);
return NULL;
}
- tty->session = NULL;
- tty->pgrp = NULL;
+ tty->ctrl.session = NULL;
+ tty->ctrl.pgrp = NULL;
mutex_init(&tty->legacy_mutex);
mutex_init(&tty->throttle_mutex);
init_rwsem(&tty->termios_rwsem);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup);
mutex_init(&tty->atomic_write_lock);
- spin_lock_init(&tty->ctrl_lock);
- spin_lock_init(&tty->flow_lock);
+ spin_lock_init(&tty->ctrl.lock);
+ spin_lock_init(&tty->flow.lock);
spin_lock_init(&tty->files_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
EXPORT_SYMBOL_GPL(tty_register_device_attr);
/**
- * tty_unregister_device - unregister a tty device
- * @driver: the tty driver that describes the tty device
- * @index: the index in the tty driver for this tty device
+ * tty_unregister_device - unregister a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
*
- * If a tty device is registered with a call to tty_register_device() then
+ * If a tty device is registered with a call to tty_register_device() then
* this function must be called when the tty device is gone.
*
* Locking: ??
* to be no queue on the device.
*/
-int tty_chars_in_buffer(struct tty_struct *tty)
+unsigned int tty_chars_in_buffer(struct tty_struct *tty)
{
if (tty->ops->chars_in_buffer)
return tty->ops->chars_in_buffer(tty);
* returned and data may be lost as there will be no flow control.
*/
-int tty_write_room(struct tty_struct *tty)
+unsigned int tty_write_room(struct tty_struct *tty)
{
if (tty->ops->write_room)
return tty->ops->write_room(tty);
}
EXPORT_SYMBOL(tty_driver_flush_buffer);
-/**
- * tty_throttle - flow control
- * @tty: terminal
- *
- * Indicate that a tty should stop transmitting data down the stack.
- * Takes the termios rwsem to protect against parallel throttle/unthrottle
- * and also to ensure the driver can consistently reference its own
- * termios data at this point when implementing software flow control.
- */
-
-void tty_throttle(struct tty_struct *tty)
-{
- down_write(&tty->termios_rwsem);
- /* check TTY_THROTTLED first so it indicates our state */
- if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
- tty->ops->throttle)
- tty->ops->throttle(tty);
- tty->flow_change = 0;
- up_write(&tty->termios_rwsem);
-}
-EXPORT_SYMBOL(tty_throttle);
-
/**
* tty_unthrottle - flow control
* @tty: terminal
* tty_throttle_safe - flow control
* @tty: terminal
*
- * Similar to tty_throttle() but will only attempt throttle
- * if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
- * throttle due to race conditions when throttling is conditional
- * on factors evaluated prior to throttling.
+ * Indicate that a tty should stop transmitting data down the stack.
+ * tty_throttle_safe will only attempt throttle if tty->flow_change is
+ * TTY_THROTTLE_SAFE. Prevents an accidental throttle due to race
+ * conditions when throttling is conditional on factors evaluated prior to
+ * throttling.
*
* Returns 0 if tty is throttled (or was already throttled)
*/
return retval;
switch (arg) {
case TCOOFF:
- spin_lock_irq(&tty->flow_lock);
- if (!tty->flow_stopped) {
- tty->flow_stopped = 1;
+ spin_lock_irq(&tty->flow.lock);
+ if (!tty->flow.tco_stopped) {
+ tty->flow.tco_stopped = true;
__stop_tty(tty);
}
- spin_unlock_irq(&tty->flow_lock);
+ spin_unlock_irq(&tty->flow.lock);
break;
case TCOON:
- spin_lock_irq(&tty->flow_lock);
- if (tty->flow_stopped) {
- tty->flow_stopped = 0;
+ spin_lock_irq(&tty->flow.lock);
+ if (tty->flow.tco_stopped) {
+ tty->flow.tco_stopped = false;
__start_tty(tty);
}
- spin_unlock_irq(&tty->flow_lock);
+ spin_unlock_irq(&tty->flow.lock);
break;
case TCIOFF:
if (STOP_CHAR(tty) != __DISABLED_CHAR)
}
/**
- * tty_check_change - check for POSIX terminal changes
+ * __tty_check_change - check for POSIX terminal changes
* @tty: tty to check
* @sig: signal to send
*
* not in the foreground, send a SIGTTOU. If the signal is blocked or
* ignored, go ahead and perform the operation. (POSIX 7.2)
*
- * Locking: ctrl_lock
+ * Locking: ctrl.lock
*/
int __tty_check_change(struct tty_struct *tty, int sig)
{
rcu_read_lock();
pgrp = task_pgrp(current);
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- tty_pgrp = tty->pgrp;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ tty_pgrp = tty->ctrl.pgrp;
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
if (tty_pgrp && pgrp != tty_pgrp) {
if (is_ignored(sig)) {
}
/**
- * proc_set_tty - set the controlling terminal
+ * __proc_set_tty - set the controlling terminal
* @tty: tty structure
*
* Only callable by the session leader and only if it does not already have
{
unsigned long flags;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
/*
* The session and fg pgrp references will be non-NULL if
* tiocsctty() is stealing the controlling tty
*/
- put_pid(tty->session);
- put_pid(tty->pgrp);
- tty->pgrp = get_pid(task_pgrp(current));
- tty->session = get_pid(task_session(current));
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ put_pid(tty->ctrl.session);
+ put_pid(tty->ctrl.pgrp);
+ tty->ctrl.pgrp = get_pid(task_pgrp(current));
+ tty->ctrl.session = get_pid(task_session(current));
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
if (current->signal->tty) {
tty_debug(tty, "current tty %s not NULL!!\n",
current->signal->tty->name);
spin_lock_irq(¤t->sighand->siglock);
if (current->signal->leader &&
!current->signal->tty &&
- tty->session == NULL) {
+ tty->ctrl.session == NULL) {
/*
* Don't let a process that only has write access to the tty
* obtain the privileges associated with having a tty as
struct pid *tty_pgrp = NULL;
read_lock(&tasklist_lock);
- if (tty->session) {
- do_each_pid_task(tty->session, PIDTYPE_SID, p) {
+ if (tty->ctrl.session) {
+ do_each_pid_task(tty->ctrl.session, PIDTYPE_SID, p) {
spin_lock_irq(&p->sighand->siglock);
if (p->signal->tty == tty) {
p->signal->tty = NULL;
__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
put_pid(p->signal->tty_old_pgrp); /* A noop */
- spin_lock(&tty->ctrl_lock);
- tty_pgrp = get_pid(tty->pgrp);
- if (tty->pgrp)
- p->signal->tty_old_pgrp = get_pid(tty->pgrp);
- spin_unlock(&tty->ctrl_lock);
+ spin_lock(&tty->ctrl.lock);
+ tty_pgrp = get_pid(tty->ctrl.pgrp);
+ if (tty->ctrl.pgrp)
+ p->signal->tty_old_pgrp =
+ get_pid(tty->ctrl.pgrp);
+ spin_unlock(&tty->ctrl.lock);
spin_unlock_irq(&p->sighand->siglock);
- } while_each_pid_task(tty->session, PIDTYPE_SID, p);
+ } while_each_pid_task(tty->ctrl.session, PIDTYPE_SID, p);
}
read_unlock(&tasklist_lock);
unsigned long flags;
tty_lock(tty);
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- put_pid(tty->session);
- put_pid(tty->pgrp);
- tty->session = NULL;
- tty->pgrp = NULL;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ put_pid(tty->ctrl.session);
+ put_pid(tty->ctrl.pgrp);
+ tty->ctrl.session = NULL;
+ tty->ctrl.pgrp = NULL;
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
tty_unlock(tty);
tty_kref_put(tty);
}
tty_lock(tty);
read_lock(&tasklist_lock);
- if (current->signal->leader && (task_session(current) == tty->session))
+ if (current->signal->leader &&
+ task_session(current) == tty->ctrl.session)
goto unlock;
/*
goto unlock;
}
- if (tty->session) {
+ if (tty->ctrl.session) {
/*
* This tty is already the controlling
* tty for another session group!
/*
* Steal it away
*/
- session_clear_tty(tty->session);
+ session_clear_tty(tty->ctrl.session);
} else {
ret = -EPERM;
goto unlock;
unsigned long flags;
struct pid *pgrp;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- pgrp = get_pid(tty->pgrp);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_lock_irqsave(&tty->ctrl.lock, flags);
+ pgrp = get_pid(tty->ctrl.pgrp);
+ spin_unlock_irqrestore(&tty->ctrl.lock, flags);
return pgrp;
}
if (pgrp_nr < 0)
return -EINVAL;
- spin_lock_irq(&real_tty->ctrl_lock);
+ spin_lock_irq(&real_tty->ctrl.lock);
if (!current->signal->tty ||
(current->signal->tty != real_tty) ||
- (real_tty->session != task_session(current))) {
+ (real_tty->ctrl.session != task_session(current))) {
retval = -ENOTTY;
goto out_unlock_ctrl;
}
if (session_of_pgrp(pgrp) != task_session(current))
goto out_unlock;
retval = 0;
- put_pid(real_tty->pgrp);
- real_tty->pgrp = get_pid(pgrp);
+ put_pid(real_tty->ctrl.pgrp);
+ real_tty->ctrl.pgrp = get_pid(pgrp);
out_unlock:
rcu_read_unlock();
out_unlock_ctrl:
- spin_unlock_irq(&real_tty->ctrl_lock);
+ spin_unlock_irq(&real_tty->ctrl.lock);
return retval;
}
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
- spin_lock_irqsave(&real_tty->ctrl_lock, flags);
- if (!real_tty->session)
+ spin_lock_irqsave(&real_tty->ctrl.lock, flags);
+ if (!real_tty->ctrl.session)
goto err;
- sid = pid_vnr(real_tty->session);
- spin_unlock_irqrestore(&real_tty->ctrl_lock, flags);
+ sid = pid_vnr(real_tty->ctrl.session);
+ spin_unlock_irqrestore(&real_tty->ctrl.lock, flags);
return put_user(sid, p);
err:
- spin_unlock_irqrestore(&real_tty->ctrl_lock, flags);
+ spin_unlock_irqrestore(&real_tty->ctrl.lock, flags);
return -ENOTTY;
}
* takes tty_ldiscs_lock to guard against ldisc races
*/
-int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc)
+int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc)
{
unsigned long flags;
int ret = 0;
- if (disc < N_TTY || disc >= NR_LDISCS)
+ if (new_ldisc->num < N_TTY || new_ldisc->num >= NR_LDISCS)
return -EINVAL;
raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
- tty_ldiscs[disc] = new_ldisc;
- new_ldisc->num = disc;
- new_ldisc->refcount = 0;
+ tty_ldiscs[new_ldisc->num] = new_ldisc;
raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
return ret;
* takes tty_ldiscs_lock to guard against ldisc races
*/
-int tty_unregister_ldisc(int disc)
+void tty_unregister_ldisc(struct tty_ldisc_ops *ldisc)
{
unsigned long flags;
- int ret = 0;
-
- if (disc < N_TTY || disc >= NR_LDISCS)
- return -EINVAL;
raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
- if (tty_ldiscs[disc]->refcount)
- ret = -EBUSY;
- else
- tty_ldiscs[disc] = NULL;
+ tty_ldiscs[ldisc->num] = NULL;
raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
-
- return ret;
}
EXPORT_SYMBOL(tty_unregister_ldisc);
ldops = tty_ldiscs[disc];
if (ldops) {
ret = ERR_PTR(-EAGAIN);
- if (try_module_get(ldops->owner)) {
- ldops->refcount++;
+ if (try_module_get(ldops->owner))
ret = ldops;
- }
}
raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
return ret;
unsigned long flags;
raw_spin_lock_irqsave(&tty_ldiscs_lock, flags);
- ldops->refcount--;
module_put(ldops->owner);
raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
}
DEFINE_WAIT(wait);
/* if non-blocking mode is set we can pass directly to open unless
- the port has just hung up or is in another error state */
+ * the port has just hung up or is in another error state.
+ */
if (tty_io_error(tty)) {
tty_port_set_active(port, 1);
return 0;
do_clocal = 1;
/* Block waiting until we can proceed. We may need to wait for the
- carrier, but we must also wait for any close that is in progress
- before the next open may complete */
+ * carrier, but we must also wait for any close that is in progress
+ * before the next open may complete.
+ */
retval = 0;
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
/* Check for a hangup or uninitialised port.
- Return accordingly */
+ * Return accordingly.
+ */
if (tty_hung_up_p(filp) || !tty_port_initialized(port)) {
if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
finish_wait(&port->open_wait, &wait);
/* Update counts. A parallel hangup will have set count to zero and
- we must not mess that up further */
+ * we must not mess that up further.
+ */
spin_lock_irqsave(&port->lock, flags);
if (!tty_hung_up_p(filp))
port->count++;
if (tty_port_initialized(port)) {
/* Don't block on a stalled port, just pull the chain */
- if (tty->flow_stopped)
+ if (tty->flow.tco_stopped)
tty_driver_flush_buffer(tty);
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->closing_wait);
clear_bit(TTY_IO_ERROR, &tty->flags);
if (port->ops->activate) {
int retval = port->ops->activate(port, tty);
+
if (retval) {
mutex_unlock(&port->mutex);
return retval;
mutex_unlock(&port->mutex);
return tty_port_block_til_ready(port, tty, filp);
}
-
EXPORT_SYMBOL(tty_port_open);
return count;
}
-static int ttynull_write_room(struct tty_struct *tty)
+static unsigned int ttynull_write_room(struct tty_struct *tty)
{
return 65536;
}
return total_sent ? total_sent : rv;
}
-static int vcc_write_room(struct tty_struct *tty)
+static unsigned int vcc_write_room(struct tty_struct *tty)
{
struct vcc_port *port;
- u64 num;
+ unsigned int num;
port = vcc_get_ne(tty->index);
if (unlikely(!port)) {
return num;
}
-static int vcc_chars_in_buffer(struct tty_struct *tty)
+static unsigned int vcc_chars_in_buffer(struct tty_struct *tty)
{
struct vcc_port *port;
- u64 num;
+ unsigned int num;
port = vcc_get_ne(tty->index);
if (unlikely(!port)) {
* these routines are also activated by ^S/^Q.
* (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
*/
- if (tty->stopped)
+ if (tty->flow.stopped)
start_tty(tty);
else
stop_tty(tty);
#include <linux/sched/signal.h>
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
-#define isspace(c) ((c) == ' ')
+#define is_space_on_vt(c) ((c) == ' ')
/* FIXME: all this needs locking */
static struct vc_selection {
}
/**
- * set loadlut - load the LUT table
+ * sel_loadlut() - load the LUT table
* @p: user table
*
* Load the LUT table from user space. The caller must hold the console
bp += store_utf8(c, bp);
else
*bp++ = c;
- if (!isspace(c))
+ if (!is_space_on_vt(c))
obp = bp;
if (!((i + 2) % vc->vc_size_row)) {
/* strip trailing blanks from line and add newline,
new_sel_end = pe;
break;
case TIOCL_SELWORD: /* word-by-word selection */
- spc = isspace(sel_pos(ps, unicode));
+ spc = is_space_on_vt(sel_pos(ps, unicode));
for (new_sel_start = ps; ; ps -= 2) {
- if ((spc && !isspace(sel_pos(ps, unicode))) ||
+ if ((spc && !is_space_on_vt(sel_pos(ps, unicode))) ||
(!spc && !inword(sel_pos(ps, unicode))))
break;
new_sel_start = ps;
break;
}
- spc = isspace(sel_pos(pe, unicode));
+ spc = is_space_on_vt(sel_pos(pe, unicode));
for (new_sel_end = pe; ; pe += 2) {
- if ((spc && !isspace(sel_pos(pe, unicode))) ||
+ if ((spc && !is_space_on_vt(sel_pos(pe, unicode))) ||
(!spc && !inword(sel_pos(pe, unicode))))
break;
new_sel_end = pe;
/* select to end of line if on trailing space */
if (new_sel_end > new_sel_start &&
!atedge(new_sel_end, vc->vc_size_row) &&
- isspace(sel_pos(new_sel_end, unicode))) {
+ is_space_on_vt(sel_pos(new_sel_end, unicode))) {
for (pe = new_sel_end + 2; ; pe += 2)
- if (!isspace(sel_pos(pe, unicode)) ||
+ if (!is_space_on_vt(sel_pos(pe, unicode)) ||
atedge(pe, vc->vc_size_row))
break;
- if (isspace(sel_pos(pe, unicode)))
+ if (is_space_on_vt(sel_pos(pe, unicode)))
new_sel_end = pe;
}
if (vc_sel.start == -1) /* no current selection */
* information and perform any necessary signal handling.
*
* Caller must hold the console semaphore. Takes the termios rwsem and
- * ctrl_lock of the tty IFF a tty is passed.
+ * ctrl.lock of the tty IFF a tty is passed.
*/
static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
* the actual work.
*
* Takes the console sem and the called methods then take the tty
- * termios_rwsem and the tty ctrl_lock in that order.
+ * termios_rwsem and the tty ctrl.lock in that order.
*/
static int vt_resize(struct tty_struct *tty, struct winsize *ws)
{
param.vc = vc;
- while (!tty->stopped && count) {
+ while (!tty->flow.stopped && count) {
int orig = *buf;
buf++;
n++;
static int con_put_char(struct tty_struct *tty, unsigned char ch)
{
- if (in_interrupt())
- return 0; /* n_r3964 calls put_char() from interrupt context */
return do_con_write(tty, &ch, 1);
}
-static int con_write_room(struct tty_struct *tty)
+static unsigned int con_write_room(struct tty_struct *tty)
{
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
return 32768; /* No limit, really; we're not buffering */
}
-static int con_chars_in_buffer(struct tty_struct *tty)
-{
- return 0; /* we're not buffering */
-}
-
/*
* con_throttle and con_unthrottle are only used for
* paste_selection(), which has to stuff in a large number of
.write_room = con_write_room,
.put_char = con_put_char,
.flush_chars = con_flush_chars,
- .chars_in_buffer = con_chars_in_buffer,
.ioctl = vt_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = vt_compat_ioctl,
return count;
}
-static int acm_tty_write_room(struct tty_struct *tty)
+static unsigned int acm_tty_write_room(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
/*
return acm_wb_is_avail(acm) ? acm->writesize : 0;
}
-static int acm_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int acm_tty_chars_in_buffer(struct tty_struct *tty)
{
struct acm *acm = tty->driver_data;
/*
spin_unlock_irqrestore(&port->port_lock, flags);
}
-static int gs_write_room(struct tty_struct *tty)
+static unsigned int gs_write_room(struct tty_struct *tty)
{
struct gs_port *port = tty->driver_data;
unsigned long flags;
- int room = 0;
+ unsigned int room = 0;
spin_lock_irqsave(&port->port_lock, flags);
if (port->port_usb)
room = kfifo_avail(&port->port_write_buf);
spin_unlock_irqrestore(&port->port_lock, flags);
- pr_vdebug("gs_write_room: (%d,%p) room=%d\n",
+ pr_vdebug("gs_write_room: (%d,%p) room=%u\n",
port->port_num, tty, room);
return room;
}
-static int gs_chars_in_buffer(struct tty_struct *tty)
+static unsigned int gs_chars_in_buffer(struct tty_struct *tty)
{
struct gs_port *port = tty->driver_data;
unsigned long flags;
- int chars = 0;
+ unsigned int chars;
spin_lock_irqsave(&port->port_lock, flags);
chars = kfifo_len(&port->port_write_buf);
spin_unlock_irqrestore(&port->port_lock, flags);
- pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%d\n",
+ pr_vdebug("gs_chars_in_buffer: (%d,%p) chars=%u\n",
port->port_num, tty, chars);
return chars;
spin_unlock_irqrestore(&port->port_lock, flags);
}
-static int dbc_tty_write_room(struct tty_struct *tty)
+static unsigned int dbc_tty_write_room(struct tty_struct *tty)
{
struct dbc_port *port = tty->driver_data;
unsigned long flags;
- int room = 0;
+ unsigned int room;
spin_lock_irqsave(&port->port_lock, flags);
room = kfifo_avail(&port->write_fifo);
return room;
}
-static int dbc_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int dbc_tty_chars_in_buffer(struct tty_struct *tty)
{
struct dbc_port *port = tty->driver_data;
unsigned long flags;
- int chars = 0;
+ unsigned int chars;
spin_lock_irqsave(&port->port_lock, flags);
chars = kfifo_len(&port->write_fifo);
return retval;
}
-static int serial_write_room(struct tty_struct *tty)
+static unsigned int serial_write_room(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
return port->serial->type->write_room(tty);
}
-static int serial_chars_in_buffer(struct tty_struct *tty)
+static unsigned int serial_chars_in_buffer(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct usb_serial *serial = port->serial;
+++ /dev/null
-/* r3964 linediscipline for linux
- *
- * -----------------------------------------------------------
- * Copyright by
- * Philips Automation Projects
- * Kassel (Germany)
- * -----------------------------------------------------------
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- *
- * Author:
- * L. Haag
- *
- * $Log: r3964.h,v $
- * Revision 1.4 2005/12/21 19:54:24 Kurt Huwig <kurt huwig de>
- * Fixed HZ usage on 2.6 kernels
- * Removed unnecessary include
- *
- * Revision 1.3 2001/03/18 13:02:24 dwmw2
- * Fix timer usage, use spinlocks properly.
- *
- * Revision 1.2 2001/03/18 12:53:15 dwmw2
- * Merge changes in 2.4.2
- *
- * Revision 1.1.1.1 1998/10/13 16:43:14 dwmw2
- * This'll screw the version control
- *
- * Revision 1.6 1998/09/30 00:40:38 dwmw2
- * Updated to use kernel's N_R3964 if available
- *
- * Revision 1.4 1998/04/02 20:29:44 lhaag
- * select, blocking, ...
- *
- * Revision 1.3 1998/02/12 18:58:43 root
- * fixed some memory leaks
- * calculation of checksum characters
- *
- * Revision 1.2 1998/02/07 13:03:17 root
- * ioctl read_telegram
- *
- * Revision 1.1 1998/02/06 19:19:43 root
- * Initial revision
- *
- *
- */
-#ifndef __LINUX_N_R3964_H__
-#define __LINUX_N_R3964_H__
-
-
-#include <linux/param.h>
-#include <uapi/linux/n_r3964.h>
-
-/*
- * Common ascii handshake characters:
- */
-
-#define STX 0x02
-#define ETX 0x03
-#define DLE 0x10
-#define NAK 0x15
-
-/*
- * Timeouts (from milliseconds to jiffies)
- */
-
-#define R3964_TO_QVZ ((550)*HZ/1000)
-#define R3964_TO_ZVZ ((220)*HZ/1000)
-#define R3964_TO_NO_BUF ((400)*HZ/1000)
-#define R3964_NO_TX_ROOM ((100)*HZ/1000)
-#define R3964_TO_RX_PANIC ((4000)*HZ/1000)
-#define R3964_MAX_RETRIES 5
-
-
-enum { R3964_IDLE,
- R3964_TX_REQUEST, R3964_TRANSMITTING,
- R3964_WAIT_ZVZ_BEFORE_TX_RETRY, R3964_WAIT_FOR_TX_ACK,
- R3964_WAIT_FOR_RX_BUF,
- R3964_RECEIVING, R3964_WAIT_FOR_BCC, R3964_WAIT_FOR_RX_REPEAT
- };
-
-/*
- * All open file-handles are 'clients' and are stored in a linked list:
- */
-
-struct r3964_message;
-
-struct r3964_client_info {
- spinlock_t lock;
- struct pid *pid;
- unsigned int sig_flags;
-
- struct r3964_client_info *next;
-
- struct r3964_message *first_msg;
- struct r3964_message *last_msg;
- struct r3964_block_header *next_block_to_read;
- int msg_count;
-};
-
-
-
-struct r3964_block_header;
-
-/* internal version of client_message: */
-struct r3964_message {
- int msg_id;
- int arg;
- int error_code;
- struct r3964_block_header *block;
- struct r3964_message *next;
-};
-
-/*
- * Header of received block in rx_buf/tx_buf:
- */
-
-struct r3964_block_header
-{
- unsigned int length; /* length in chars without header */
- unsigned char *data; /* usually data is located
- immediately behind this struct */
- unsigned int locks; /* only used in rx_buffer */
-
- struct r3964_block_header *next;
- struct r3964_client_info *owner; /* =NULL in rx_buffer */
-};
-
-/*
- * If rx_buf hasn't enough space to store R3964_MTU chars,
- * we will reject all incoming STX-requests by sending NAK.
- */
-
-#define RX_BUF_SIZE 4000
-#define TX_BUF_SIZE 4000
-#define R3964_MAX_BLOCKS_IN_RX_QUEUE 100
-
-#define R3964_PARITY 0x0001
-#define R3964_FRAME 0x0002
-#define R3964_OVERRUN 0x0004
-#define R3964_UNKNOWN 0x0008
-#define R3964_BREAK 0x0010
-#define R3964_CHECKSUM 0x0020
-#define R3964_ERROR 0x003f
-#define R3964_BCC 0x4000
-#define R3964_DEBUG 0x8000
-
-
-struct r3964_info {
- spinlock_t lock;
- struct tty_struct *tty;
- unsigned char priority;
- unsigned char *rx_buf; /* ring buffer */
- unsigned char *tx_buf;
-
- struct r3964_block_header *rx_first;
- struct r3964_block_header *rx_last;
- struct r3964_block_header *tx_first;
- struct r3964_block_header *tx_last;
- unsigned int tx_position;
- unsigned int rx_position;
- unsigned char last_rx;
- unsigned char bcc;
- unsigned int blocks_in_rx_queue;
-
- struct mutex read_lock; /* serialize r3964_read */
-
- struct r3964_client_info *firstClient;
- unsigned int state;
- unsigned int flags;
-
- struct timer_list tmr;
- int nRetry;
-};
-
-#endif
return container_of(up, struct uart_8250_port, port);
}
-int serial8250_register_8250_port(struct uart_8250_port *);
+int serial8250_register_8250_port(const struct uart_8250_port *);
void serial8250_unregister_port(int line);
void serial8250_suspend_port(int line);
void serial8250_resume_port(int line);
void uart_unregister_driver(struct uart_driver *uart);
int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
-int uart_match_port(struct uart_port *port1, struct uart_port *port2);
+bool uart_match_port(const struct uart_port *port1,
+ const struct uart_port *port2);
/*
* Power Management
static inline int uart_tx_stopped(struct uart_port *port)
{
struct tty_struct *tty = port->state->port.tty;
- if ((tty && tty->stopped) || port->hw_stopped)
+ if ((tty && tty->flow.stopped) || port->hw_stopped)
return 1;
return 0;
}
#define TTY_PORT_KOPENED 5 /* device exclusively opened by
kernel */
-/*
- * Where all of the state associated with a tty is kept while the tty
- * is open. Since the termios state should be kept even if the tty
- * has been closed --- for things like the baud rate, etc --- it is
- * not stored here, but rather a pointer to the real state is stored
- * here. Possible the winsize structure should have the same
- * treatment, but (1) the default 80x24 is usually right and (2) it's
- * most often used by a windowing system, which will set the correct
- * size each time the window is created or resized anyway.
- * - TYT, 9/14/92
- */
-
struct tty_operations;
+/**
+ * struct tty_struct - state associated with a tty while open
+ *
+ * @flow.lock: lock for flow members
+ * @flow.stopped: tty stopped/started by tty_stop/tty_start
+ * @flow.tco_stopped: tty stopped/started by TCOOFF/TCOON ioctls (it has
+ * precedense over @flow.stopped)
+ * @flow.unused: alignment for Alpha, so that no members other than @flow.* are
+ * modified by the same 64b word store. The @flow's __aligned is
+ * there for the very same reason.
+ * @ctrl.lock: lock for ctrl members
+ * @ctrl.pgrp: process group of this tty (setpgrp(2))
+ * @ctrl.session: session of this tty (setsid(2)). Writes are protected by both
+ * @ctrl.lock and legacy mutex, readers must use at least one of
+ * them.
+ * @ctrl.pktstatus: packet mode status (bitwise OR of TIOCPKT_* constants)
+ * @ctrl.packet: packet mode enabled
+ *
+ * All of the state associated with a tty while the tty is open. Persistent
+ * storage for tty devices is referenced here as @port in struct tty_port.
+ */
struct tty_struct {
int magic;
struct kref kref;
struct mutex throttle_mutex;
struct rw_semaphore termios_rwsem;
struct mutex winsize_mutex;
- spinlock_t ctrl_lock;
- spinlock_t flow_lock;
/* Termios values are protected by the termios rwsem */
struct ktermios termios, termios_locked;
char name[64];
- struct pid *pgrp; /* Protected by ctrl lock */
- /*
- * Writes protected by both ctrl lock and legacy mutex, readers must use
- * at least one of them.
- */
- struct pid *session;
unsigned long flags;
int count;
struct winsize winsize; /* winsize_mutex */
- unsigned long stopped:1, /* flow_lock */
- flow_stopped:1,
- unused:BITS_PER_LONG - 2;
+
+ struct {
+ spinlock_t lock;
+ bool stopped;
+ bool tco_stopped;
+ unsigned long unused[0];
+ } __aligned(sizeof(unsigned long)) flow;
+
+ struct {
+ spinlock_t lock;
+ struct pid *pgrp;
+ struct pid *session;
+ unsigned char pktstatus;
+ bool packet;
+ unsigned long unused[0];
+ } __aligned(sizeof(unsigned long)) ctrl;
+
int hw_stopped;
- unsigned long ctrl_status:8, /* ctrl_lock */
- packet:1,
- unused_ctrl:BITS_PER_LONG - 9;
unsigned int receive_room; /* Bytes free for queue */
int flow_change;
extern void tty_write_message(struct tty_struct *tty, char *msg);
extern int tty_send_xchar(struct tty_struct *tty, char ch);
extern int tty_put_char(struct tty_struct *tty, unsigned char c);
-extern int tty_chars_in_buffer(struct tty_struct *tty);
-extern int tty_write_room(struct tty_struct *tty);
+extern unsigned int tty_chars_in_buffer(struct tty_struct *tty);
+extern unsigned int tty_write_room(struct tty_struct *tty);
extern void tty_driver_flush_buffer(struct tty_struct *tty);
-extern void tty_throttle(struct tty_struct *tty);
extern void tty_unthrottle(struct tty_struct *tty);
extern int tty_throttle_safe(struct tty_struct *tty);
extern int tty_unthrottle_safe(struct tty_struct *tty);
return port->count + port->blocked_open;
}
-extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc);
-extern int tty_unregister_ldisc(int disc);
+extern int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc);
+extern void tty_unregister_ldisc(struct tty_ldisc_ops *ldisc);
extern int tty_set_ldisc(struct tty_struct *tty, int disc);
extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
- char *f, int count);
+ const char *f, int count);
/* n_tty.c */
extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops);
*
* Note: Do not call this function directly, call tty_driver_flush_chars
*
- * int (*write_room)(struct tty_struct *tty);
+ * unsigned int (*write_room)(struct tty_struct *tty);
*
* This routine returns the numbers of characters the tty driver
* will accept for queuing to be written. This number is subject
* the line discipline are close to full, and it should somehow
* signal that no more characters should be sent to the tty.
*
- * Optional: Always invoke via tty_throttle(), called under the
+ * Optional: Always invoke via tty_throttle_safe(), called under the
* termios lock.
*
* void (*unthrottle)(struct tty_struct * tty);
* This routine notifies the tty driver that it should stop
* outputting characters to the tty device.
*
- * Called with ->flow_lock held. Serialized with start() method.
+ * Called with ->flow.lock held. Serialized with start() method.
*
* Optional:
*
* This routine notifies the tty driver that it resume sending
* characters to the tty device.
*
- * Called with ->flow_lock held. Serialized with stop() method.
+ * Called with ->flow.lock held. Serialized with stop() method.
*
* Optional:
*
const unsigned char *buf, int count);
int (*put_char)(struct tty_struct *tty, unsigned char ch);
void (*flush_chars)(struct tty_struct *tty);
- int (*write_room)(struct tty_struct *tty);
- int (*chars_in_buffer)(struct tty_struct *tty);
+ unsigned int (*write_room)(struct tty_struct *tty);
+ unsigned int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty,
unsigned int cmd, unsigned long arg);
long (*compat_ioctl)(struct tty_struct *tty,
#define _LINUX_TTY_FLIP_H
extern int tty_buffer_set_limit(struct tty_port *port, int limit);
-extern int tty_buffer_space_avail(struct tty_port *port);
+extern unsigned int tty_buffer_space_avail(struct tty_port *port);
extern int tty_buffer_request_room(struct tty_port *port, size_t size);
extern int tty_insert_flip_string_flags(struct tty_port *port,
const unsigned char *chars, const char *flags, size_t size);
* The following routines are called from below.
*/
void (*receive_buf)(struct tty_struct *, const unsigned char *cp,
- char *fp, int count);
+ const char *fp, int count);
void (*write_wakeup)(struct tty_struct *);
void (*dcd_change)(struct tty_struct *, unsigned int);
int (*receive_buf2)(struct tty_struct *, const unsigned char *cp,
- char *fp, int count);
+ const char *fp, int count);
struct module *owner;
-
- int refcount;
};
struct tty_ldisc {
+++ /dev/null
-/* SPDX-License-Identifier: GPL-1.0+ WITH Linux-syscall-note */
-/* r3964 linediscipline for linux
- *
- * -----------------------------------------------------------
- * Copyright by
- * Philips Automation Projects
- * Kassel (Germany)
- * -----------------------------------------------------------
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- *
- * Author:
- * L. Haag
- *
- * $Log: r3964.h,v $
- * Revision 1.4 2005/12/21 19:54:24 Kurt Huwig <kurt huwig de>
- * Fixed HZ usage on 2.6 kernels
- * Removed unnecessary include
- *
- * Revision 1.3 2001/03/18 13:02:24 dwmw2
- * Fix timer usage, use spinlocks properly.
- *
- * Revision 1.2 2001/03/18 12:53:15 dwmw2
- * Merge changes in 2.4.2
- *
- * Revision 1.1.1.1 1998/10/13 16:43:14 dwmw2
- * This'll screw the version control
- *
- * Revision 1.6 1998/09/30 00:40:38 dwmw2
- * Updated to use kernel's N_R3964 if available
- *
- * Revision 1.4 1998/04/02 20:29:44 lhaag
- * select, blocking, ...
- *
- * Revision 1.3 1998/02/12 18:58:43 root
- * fixed some memory leaks
- * calculation of checksum characters
- *
- * Revision 1.2 1998/02/07 13:03:17 root
- * ioctl read_telegram
- *
- * Revision 1.1 1998/02/06 19:19:43 root
- * Initial revision
- *
- *
- */
-
-#ifndef _UAPI__LINUX_N_R3964_H__
-#define _UAPI__LINUX_N_R3964_H__
-
-/* line disciplines for r3964 protocol */
-
-
-/*
- * Ioctl-commands
- */
-
-#define R3964_ENABLE_SIGNALS 0x5301
-#define R3964_SETPRIORITY 0x5302
-#define R3964_USE_BCC 0x5303
-#define R3964_READ_TELEGRAM 0x5304
-
-/* Options for R3964_SETPRIORITY */
-#define R3964_MASTER 0
-#define R3964_SLAVE 1
-
-/* Options for R3964_ENABLE_SIGNALS */
-#define R3964_SIG_ACK 0x0001
-#define R3964_SIG_DATA 0x0002
-#define R3964_SIG_ALL 0x000f
-#define R3964_SIG_NONE 0x0000
-#define R3964_USE_SIGIO 0x1000
-
-/*
- * r3964 operation states:
- */
-
-/* types for msg_id: */
-enum {R3964_MSG_ACK=1, R3964_MSG_DATA };
-
-#define R3964_MAX_MSG_COUNT 32
-
-/* error codes for client messages */
-#define R3964_OK 0 /* no error. */
-#define R3964_TX_FAIL -1 /* transmission error, block NOT sent */
-#define R3964_OVERFLOW -2 /* msg queue overflow */
-
-/* the client gets this struct when calling read(fd,...): */
-struct r3964_client_message {
- int msg_id;
- int arg;
- int error_code;
-};
-
-#define R3964_MTU 256
-
-
-
-#endif /* _UAPI__LINUX_N_R3964_H__ */
return sent;
}
-static int rfcomm_tty_write_room(struct tty_struct *tty)
+static unsigned int rfcomm_tty_write_room(struct tty_struct *tty)
{
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
int room = 0;
rfcomm_dlc_unthrottle(dev->dlc);
}
-static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
+static unsigned int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
{
struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
* Return Value: None
*/
static void nci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
- char *flags, int count)
+ const char *flags, int count)
{
struct nci_uart *nu = (void *)tty->disc_data;
static struct tty_ldisc_ops nci_uart_ldisc = {
.owner = THIS_MODULE,
+ .num = N_NCI,
.name = "n_nci",
.open = nci_uart_tty_open,
.close = nci_uart_tty_close,
static int __init nci_uart_init(void)
{
- return tty_register_ldisc(N_NCI, &nci_uart_ldisc);
+ return tty_register_ldisc(&nci_uart_ldisc);
}
static void __exit nci_uart_exit(void)
{
- tty_unregister_ldisc(N_NCI);
+ tty_unregister_ldisc(&nci_uart_ldisc);
}
module_init(nci_uart_init);
}
/* Line discipline .receive_buf() */
-static void v253_receive(struct tty_struct *tty,
- const unsigned char *cp, char *fp, int count)
+static void v253_receive(struct tty_struct *tty, const unsigned char *cp,
+ const char *fp, int count)
{
struct snd_soc_component *component = tty->disc_data;
struct cx20442_priv *cx20442;
}
/* Line discipline .receive_buf() */
-static void cx81801_receive(struct tty_struct *tty,
- const unsigned char *cp, char *fp, int count)
+static void cx81801_receive(struct tty_struct *tty, const unsigned char *cp,
+ const char *fp, int count)
{
struct snd_soc_component *component = tty->disc_data;
const unsigned char *c;
static struct tty_ldisc_ops cx81801_ops = {
.name = "cx81801",
+ .num = N_V253,
.owner = THIS_MODULE,
.open = cx81801_open,
.close = cx81801_close,
}
/* Register optional line discipline for over the modem control */
- ret = tty_register_ldisc(N_V253, &cx81801_ops);
+ ret = tty_register_ldisc(&cx81801_ops);
if (ret) {
dev_warn(card->dev,
"Failed to register line discipline, "
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
- if (tty_unregister_ldisc(N_V253) != 0)
- dev_warn(&pdev->dev,
- "failed to unregister V253 line discipline\n");
+ tty_unregister_ldisc(&cx81801_ops);
snd_soc_unregister_card(card);
card->dev = NULL;