From 4ea3cd65e0d47c4d3fc0c86d2d93d97457dc86fb Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 18 Dec 2020 11:42:44 +0100 Subject: tty: rename tty_kopen() and add new function tty_kopen_shared() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a new function tty_kopen_shared() that yields a struct tty_struct. The semantic difference to tty_kopen() is that the tty is expected to be used already. So rename tty_kopen() to tty_kopen_exclusive() for clearness, adapt the single user and put the common code in a new static helper function. tty_kopen_shared is to be used to implement an LED trigger for tty devices in one of the next patches. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20201218104246.591315-2-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tty.h b/include/linux/tty.h index c873f475f0a7..df707a5abfac 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -416,7 +416,8 @@ extern struct tty_struct *get_current_tty(void); /* tty_io.c */ extern int __init tty_init(void); extern const char *tty_name(const struct tty_struct *tty); -extern struct tty_struct *tty_kopen(dev_t device); +extern struct tty_struct *tty_kopen_exclusive(dev_t device); +extern struct tty_struct *tty_kopen_shared(dev_t device); extern void tty_kclose(struct tty_struct *tty); extern int tty_dev_name_to_number(const char *name, dev_t *number); extern int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout); @@ -441,7 +442,7 @@ static inline int __init tty_init(void) { return 0; } static inline const char *tty_name(const struct tty_struct *tty) { return "(none)"; } -static inline struct tty_struct *tty_kopen(dev_t device) +static inline struct tty_struct *tty_kopen_exclusive(dev_t device) { return ERR_PTR(-ENODEV); } static inline void tty_kclose(struct tty_struct *tty) { } -- cgit v1.2.3-59-g8ed1b From d20c219c7317843cec7f03eba15bfeae54f29654 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 18 Dec 2020 11:42:45 +0100 Subject: tty: new helper function tty_get_icount() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For a given struct tty_struct this yields the corresponding statistics about sent and received characters (and some more) which is needed to implement an LED trigger for tty devices. The new function is then used to simplify tty_tiocgicount(). Reviewed-by: Pavel Machek Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20201218104246.591315-3-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 29 +++++++++++++++++++++++++---- include/linux/tty.h | 2 ++ 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 62ccd021102d..95ba028ef668 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2488,15 +2488,36 @@ static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd, return tty->ops->tiocmset(tty, set, clear); } +/** + * tty_get_icount - get tty statistics + * @tty: tty device + * @icount: output parameter + * + * Gets a copy of the tty's icount statistics. + * + * Locking: none (up to the driver) + */ +int tty_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + memset(icount, 0, sizeof(*icount)); + + if (tty->ops->get_icount) + return tty->ops->get_icount(tty, icount); + else + return -EINVAL; +} +EXPORT_SYMBOL_GPL(tty_get_icount); + static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) { - int retval = -EINVAL; struct serial_icounter_struct icount; - memset(&icount, 0, sizeof(icount)); - if (tty->ops->get_icount) - retval = tty->ops->get_icount(tty, &icount); + int retval; + + retval = tty_get_icount(tty, &icount); if (retval != 0) return retval; + if (copy_to_user(arg, &icount, sizeof(icount))) return -EFAULT; return 0; diff --git a/include/linux/tty.h b/include/linux/tty.h index df707a5abfac..12be8b16cdef 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -500,6 +500,8 @@ 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); extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws); +extern int tty_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount); extern int is_current_pgrp_orphaned(void); extern void tty_hangup(struct tty_struct *tty); extern void tty_vhangup(struct tty_struct *tty); -- cgit v1.2.3-59-g8ed1b From 63f24a7fafd44899f001b8467b38fac5a534f63e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 5 Jan 2021 13:02:28 +0100 Subject: vt: move set_leds to keyboard.c set_leds and compute_shiftstate are called from a single place in vt.c. Let's combine these two into vt_set_leds_compute_shiftstate. This allows for making keyboard_tasklet local in the next patch. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210105120239.28031-1-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/keyboard.c | 11 ++++++++++- drivers/tty/vt/vt.c | 3 +-- include/linux/kbd_kern.h | 8 +------- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 52922d21a49f..32ec4242b1f2 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -372,6 +372,12 @@ static void to_utf8(struct vc_data *vc, uint c) } } +/* FIXME: review locking for vt.c callers */ +static void set_leds(void) +{ + tasklet_schedule(&keyboard_tasklet); +} + /* * Called after returning from RAW mode or when changing consoles - recompute * shift_down[] and shift_state from key_down[] maybe called when keymap is @@ -401,9 +407,12 @@ static void do_compute_shiftstate(void) } /* We still have to export this method to vt.c */ -void compute_shiftstate(void) +void vt_set_leds_compute_shiftstate(void) { unsigned long flags; + + set_leds(); + spin_lock_irqsave(&kbd_event_lock, flags); do_compute_shiftstate(); spin_unlock_irqrestore(&kbd_event_lock, flags); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index d04a162939a4..fe4fedbc0386 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1036,8 +1036,7 @@ void redraw_screen(struct vc_data *vc, int is_switch) } set_cursor(vc); if (is_switch) { - set_leds(); - compute_shiftstate(); + vt_set_leds_compute_shiftstate(); notify_update(vc); } } diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index 82f29aa35062..adf98004624b 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -71,12 +71,6 @@ extern void (*kbd_ledfunc)(unsigned int led); extern int set_console(int nr); extern void schedule_console_callback(void); -/* FIXME: review locking for vt.c callers */ -static inline void set_leds(void) -{ - tasklet_schedule(&keyboard_tasklet); -} - static inline int vc_kbd_mode(struct kbd_struct * kbd, int flag) { return ((kbd->modeflags >> flag) & 1); @@ -135,7 +129,7 @@ static inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag) struct console; -void compute_shiftstate(void); +void vt_set_leds_compute_shiftstate(void); /* defkeymap.c */ -- cgit v1.2.3-59-g8ed1b From a18a9da82c57804ce5977ea0e01b72ee3f40a51b Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 5 Jan 2021 13:02:29 +0100 Subject: vt: keyboard, make keyboard_tasklet local Now that the last extern user of the tasklet (set_leds) is in keyboard.c, we can make keyboard_tasklet local to this unit too. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210105120239.28031-2-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/keyboard.c | 5 +++-- include/linux/kbd_kern.h | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 32ec4242b1f2..9f2eaa104ebc 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -131,6 +131,9 @@ static const unsigned char max_vals[] = { static const int NR_TYPES = ARRAY_SIZE(max_vals); +static void kbd_bh(unsigned long dummy); +static DECLARE_TASKLET_DISABLED_OLD(keyboard_tasklet, kbd_bh); + static struct input_handler kbd_handler; static DEFINE_SPINLOCK(kbd_event_lock); static DEFINE_SPINLOCK(led_lock); @@ -1258,8 +1261,6 @@ static void kbd_bh(unsigned long dummy) } } -DECLARE_TASKLET_DISABLED_OLD(keyboard_tasklet, kbd_bh); - #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index adf98004624b..c40811d79769 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h @@ -6,8 +6,6 @@ #include #include -extern struct tasklet_struct keyboard_tasklet; - extern char *func_table[MAX_NR_FUNC]; /* -- cgit v1.2.3-59-g8ed1b From ff2047fb755d4415ec3c70ac799889371151796d Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 5 Jan 2021 13:02:35 +0100 Subject: vt: drop old FONT ioctls Drop support for these ioctls: * PIO_FONT, PIO_FONTX * GIO_FONT, GIO_FONTX * PIO_FONTRESET As was demonstrated by commit 90bfdeef83f1 (tty: make FONTX ioctl use the tty pointer they were actually passed), these ioctls are not used from userspace, as: 1) they used to be broken (set up font on current console, not the open one) and racy (before the commit above) 2) KDFONTOP ioctl is used for years instead Note that PIO_FONTRESET is defunct on most systems as VGA_CONSOLE is set on them for ages. That turns on BROKEN_GRAPHICS_PROGRAMS which makes PIO_FONTRESET just return an error. We are removing KD_FONT_FLAG_OLD here as it was used only by these removed ioctls. kd.h header exists both in kernel and uapi headers, so we can remove the kernel one completely. Everyone includeing kd.h will now automatically get the uapi one. There are now unused definitions of the ioctl numbers and "struct consolefontdesc" in kd.h, but as it is a uapi header, I am not touching these. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210105120239.28031-8-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 39 +----------- drivers/tty/vt/vt_ioctl.c | 151 ---------------------------------------------- include/linux/kd.h | 8 --- 3 files changed, 3 insertions(+), 195 deletions(-) delete mode 100644 include/linux/kd.h (limited to 'include/linux') diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index fe4fedbc0386..284b07224c55 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4583,16 +4583,8 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op) if (op->data && font.charcount > op->charcount) rc = -ENOSPC; - if (!(op->flags & KD_FONT_FLAG_OLD)) { - if (font.width > op->width || font.height > op->height) - rc = -ENOSPC; - } else { - if (font.width != 8) - rc = -EIO; - else if ((op->height && font.height > op->height) || - font.height > 32) - rc = -ENOSPC; - } + if (font.width > op->width || font.height > op->height) + rc = -ENOSPC; if (rc) goto out; @@ -4620,7 +4612,7 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op) return -EINVAL; if (op->charcount > 512) return -EINVAL; - if (op->width <= 0 || op->width > 32 || op->height > 32) + if (op->width <= 0 || op->width > 32 || !op->height || op->height > 32) return -EINVAL; size = (op->width+7)/8 * 32 * op->charcount; if (size > max_font_size) @@ -4630,31 +4622,6 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op) if (IS_ERR(font.data)) return PTR_ERR(font.data); - if (!op->height) { /* Need to guess font height [compat] */ - int h, i; - u8 *charmap = font.data; - - /* - * If from KDFONTOP ioctl, don't allow things which can be done - * in userland,so that we can get rid of this soon - */ - if (!(op->flags & KD_FONT_FLAG_OLD)) { - kfree(font.data); - return -EINVAL; - } - - for (h = 32; h > 0; h--) - for (i = 0; i < op->charcount; i++) - if (charmap[32*i+h-1]) - goto nonzero; - - kfree(font.data); - return -EINVAL; - - nonzero: - op->height = h; - } - font.charcount = op->charcount; font.width = op->width; font.height = op->height; diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 3813c40f1b48..4a4cbd4a5f37 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -484,70 +484,6 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd, return 0; } -static inline int do_fontx_ioctl(struct vc_data *vc, int cmd, - struct consolefontdesc __user *user_cfd, - struct console_font_op *op) -{ - struct consolefontdesc cfdarg; - int i; - - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc))) - return -EFAULT; - - switch (cmd) { - case PIO_FONTX: - op->op = KD_FONT_OP_SET; - op->flags = KD_FONT_FLAG_OLD; - op->width = 8; - op->height = cfdarg.charheight; - op->charcount = cfdarg.charcount; - op->data = cfdarg.chardata; - return con_font_op(vc, op); - - case GIO_FONTX: - op->op = KD_FONT_OP_GET; - op->flags = KD_FONT_FLAG_OLD; - op->width = 8; - op->height = cfdarg.charheight; - op->charcount = cfdarg.charcount; - op->data = cfdarg.chardata; - i = con_font_op(vc, op); - if (i) - return i; - cfdarg.charheight = op->height; - cfdarg.charcount = op->charcount; - if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc))) - return -EFAULT; - return 0; - } - return -EINVAL; -} - -static int vt_io_fontreset(struct vc_data *vc, struct console_font_op *op) -{ - int ret; - - if (__is_defined(BROKEN_GRAPHICS_PROGRAMS)) { - /* - * With BROKEN_GRAPHICS_PROGRAMS defined, the default font is - * not saved. - */ - return -ENOSYS; - } - - op->op = KD_FONT_OP_SET_DEFAULT; - op->data = NULL; - ret = con_font_op(vc, op); - if (ret) - return ret; - - console_lock(); - con_set_default_unimap(vc); - console_unlock(); - - return 0; -} - static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, bool perm, struct vc_data *vc) { @@ -572,29 +508,7 @@ static inline int do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up, bool perm) { - struct console_font_op op; /* used in multiple places here */ - switch (cmd) { - case PIO_FONT: - if (!perm) - return -EPERM; - op.op = KD_FONT_OP_SET; - op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ - op.width = 8; - op.height = 0; - op.charcount = 256; - op.data = up; - return con_font_op(vc, &op); - - case GIO_FONT: - op.op = KD_FONT_OP_GET; - op.flags = KD_FONT_FLAG_OLD; - op.width = 8; - op.height = 32; - op.charcount = 256; - op.data = up; - return con_font_op(vc, &op); - case PIO_CMAP: if (!perm) return -EPERM; @@ -603,20 +517,6 @@ static int vt_io_ioctl(struct vc_data *vc, unsigned int cmd, void __user *up, case GIO_CMAP: return con_get_cmap(up); - case PIO_FONTX: - if (!perm) - return -EPERM; - - fallthrough; - case GIO_FONTX: - return do_fontx_ioctl(vc, cmd, up, &op); - - case PIO_FONTRESET: - if (!perm) - return -EPERM; - - return vt_io_fontreset(vc, &op); - case PIO_SCRNMAP: if (!perm) return -EPERM; @@ -1059,54 +959,6 @@ void vc_SAK(struct work_struct *work) #ifdef CONFIG_COMPAT -struct compat_consolefontdesc { - unsigned short charcount; /* characters in font (256 or 512) */ - unsigned short charheight; /* scan lines per character (1-32) */ - compat_caddr_t chardata; /* font data in expanded form */ -}; - -static inline int -compat_fontx_ioctl(struct vc_data *vc, int cmd, - struct compat_consolefontdesc __user *user_cfd, - int perm, struct console_font_op *op) -{ - struct compat_consolefontdesc cfdarg; - int i; - - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct compat_consolefontdesc))) - return -EFAULT; - - switch (cmd) { - case PIO_FONTX: - if (!perm) - return -EPERM; - op->op = KD_FONT_OP_SET; - op->flags = KD_FONT_FLAG_OLD; - op->width = 8; - op->height = cfdarg.charheight; - op->charcount = cfdarg.charcount; - op->data = compat_ptr(cfdarg.chardata); - return con_font_op(vc, op); - - case GIO_FONTX: - op->op = KD_FONT_OP_GET; - op->flags = KD_FONT_FLAG_OLD; - op->width = 8; - op->height = cfdarg.charheight; - op->charcount = cfdarg.charcount; - op->data = compat_ptr(cfdarg.chardata); - i = con_font_op(vc, op); - if (i) - return i; - cfdarg.charheight = op->height; - cfdarg.charcount = op->charcount; - if (copy_to_user(user_cfd, &cfdarg, sizeof(struct compat_consolefontdesc))) - return -EFAULT; - return 0; - } - return -EINVAL; -} - struct compat_console_font_op { compat_uint_t op; /* operation code KD_FONT_OP_* */ compat_uint_t flags; /* KD_FONT_FLAG_* */ @@ -1183,9 +1035,6 @@ long vt_compat_ioctl(struct tty_struct *tty, /* * these need special handlers for incompatible data structures */ - case PIO_FONTX: - case GIO_FONTX: - return compat_fontx_ioctl(vc, cmd, up, perm, &op); case KDFONTOP: return compat_kdfontop_ioctl(up, perm, &op, vc); diff --git a/include/linux/kd.h b/include/linux/kd.h deleted file mode 100644 index b130a18f860f..000000000000 --- a/include/linux/kd.h +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _LINUX_KD_H -#define _LINUX_KD_H - -#include - -#define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface [compat] */ -#endif /* _LINUX_KD_H */ -- cgit v1.2.3-59-g8ed1b From cac8a63063e33606c4b8419ef34ef7644d7c2fc4 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 5 Jan 2021 13:02:36 +0100 Subject: vgacon: drop BROKEN_GRAPHICS_PROGRAMS BROKEN_GRAPHICS_PROGRAMS is defined when CONFIG_VGA_CONSOLE=y. And vgacon.c is built exclusively in that case too. So the check for BROKEN_GRAPHICS_PROGRAMS is pointless in vgacon.c as it is always true. So remove the test and BROKEN_GRAPHICS_PROGRAMS completely. This also eliminates the need for vga_font_is_default global as it is only set and never read. Cc: dri-devel@lists.freedesktop.org Cc: linux-fbdev@vger.kernel.org Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210105120239.28031-9-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- drivers/video/console/vgacon.c | 19 ------------------- include/linux/vt_kern.h | 12 ------------ 2 files changed, 31 deletions(-) (limited to 'include/linux') diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 17876f0179b5..962c12be9774 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -90,7 +90,6 @@ static unsigned int vga_video_num_lines; /* Number of text lines */ static bool vga_can_do_color; /* Do we support colors? */ static unsigned int vga_default_font_height __read_mostly; /* Height of default screen font */ static unsigned char vga_video_type __read_mostly; /* Card type */ -static bool vga_font_is_default = true; static int vga_vesa_blanked; static bool vga_palette_blanked; static bool vga_is_gfx; @@ -878,7 +877,6 @@ static int vgacon_do_font_op(struct vgastate *state, char *arg, int set, beg = 0x0a; } -#ifdef BROKEN_GRAPHICS_PROGRAMS /* * All fonts are loaded in slot 0 (0:1 for 512 ch) */ @@ -886,24 +884,7 @@ static int vgacon_do_font_op(struct vgastate *state, char *arg, int set, if (!arg) return -EINVAL; /* Return to default font not supported */ - vga_font_is_default = false; font_select = ch512 ? 0x04 : 0x00; -#else - /* - * The default font is kept in slot 0 and is never touched. - * A custom font is loaded in slot 2 (256 ch) or 2:3 (512 ch) - */ - - if (set) { - vga_font_is_default = !arg; - if (!arg) - ch512 = false; /* Default font is always 256 */ - font_select = arg ? (ch512 ? 0x0e : 0x0a) : 0x00; - } - - if (!vga_font_is_default) - charmap += 4 * cmapsz; -#endif raw_spin_lock_irq(&vga_lock); /* First, the Sequencer */ diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 349e39c3ab60..94e7a315479c 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -16,18 +16,6 @@ #include #include -/* - * Presently, a lot of graphics programs do not restore the contents of - * the higher font pages. Defining this flag will avoid use of them, but - * will lose support for PIO_FONTRESET. Note that many font operations are - * not likely to work with these programs anyway; they need to be - * fixed. The linux/Documentation directory includes a code snippet - * to save and restore the text font. - */ -#ifdef CONFIG_VGA_CONSOLE -#define BROKEN_GRAPHICS_PROGRAMS 1 -#endif - void kd_mksound(unsigned int hz, unsigned int ticks); int kbd_rate(struct kbd_repeat *rep); -- cgit v1.2.3-59-g8ed1b From 0bc1bd092af3c7c0b025ece93c3a86916f89f3ca Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 5 Jan 2021 13:02:38 +0100 Subject: tty_port: drop last traces of low_latency The main purpose of tty_port::low_latency was removed in commit a9c3f68f3cd8 (tty: Fix low_latency BUG) back in 2014. It was left in place for drivers as an optional tune knob. But only one driver has been using it until the previous commit. So remove this misconcept completely, given there are no users. Signed-off-by: Jiri Slaby Link: https://lore.kernel.org/r/20210105120239.28031-11-jslaby@suse.cz Signed-off-by: Greg Kroah-Hartman --- Documentation/networking/caif/caif.rst | 1 - drivers/char/pcmcia/synclink_cs.c | 2 -- drivers/net/caif/caif_serial.c | 3 +-- drivers/s390/char/con3215.c | 1 - drivers/s390/char/sclp_tty.c | 1 - drivers/s390/char/sclp_vt220.c | 1 - drivers/s390/char/tty3270.c | 2 -- drivers/tty/amiserial.c | 3 --- drivers/tty/hvc/hvcs.c | 2 +- drivers/tty/ipwireless/tty.c | 1 - drivers/tty/mxser.c | 1 - drivers/tty/serial/ifx6x60.c | 3 --- drivers/tty/serial/max3100.c | 3 --- drivers/tty/serial/serial_core.c | 3 --- drivers/tty/synclink_gt.c | 1 - include/linux/tty.h | 3 +-- 16 files changed, 3 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/Documentation/networking/caif/caif.rst b/Documentation/networking/caif/caif.rst index a07213030ccf..81a14373d780 100644 --- a/Documentation/networking/caif/caif.rst +++ b/Documentation/networking/caif/caif.rst @@ -68,7 +68,6 @@ There are debugfs parameters provided for serial communication. * tty_status: Prints the bit-mask tty status information - 0x01 - tty->warned is on. - - 0x02 - tty->low_latency is on. - 0x04 - tty->packed is on. - 0x08 - tty->flow_stopped is on. - 0x10 - tty->hw_stopped is on. diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index e342daa73d1b..2be8d9a8eec5 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2494,8 +2494,6 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) printk("%s(%d):mgslpc_open(%s), old ref count = %d\n", __FILE__, __LINE__, tty->driver->name, port->count); - port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - spin_lock_irqsave(&info->netlock, flags); if (info->netcount) { retval = -EBUSY; diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index bcc14c5875bf..8215cd77301f 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -89,8 +89,7 @@ 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->port->low_latency << 1; + ser->tty->packet << 2; } static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty) { diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 1354c42d95aa..671efee612af 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -914,7 +914,6 @@ static int tty3215_open(struct tty_struct *tty, struct file * filp) tty_port_tty_set(&raw->port, tty); - raw->port.low_latency = 0; /* don't use bottom half for pushing chars */ /* * Start up 3215 device */ diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 5aff8b684eb2..013bcc331305 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -65,7 +65,6 @@ sclp_tty_open(struct tty_struct *tty, struct file *filp) { tty_port_tty_set(&sclp_port, tty); tty->driver_data = NULL; - sclp_port.low_latency = 0; return 0; } diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 3f9a6ef650fa..047f812d1a1c 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -560,7 +560,6 @@ sclp_vt220_open(struct tty_struct *tty, struct file *filp) { if (tty->count == 1) { tty_port_tty_set(&sclp_vt220_port, tty); - sclp_vt220_port.low_latency = 0; if (!tty->winsize.ws_row && !tty->winsize.ws_col) { tty->winsize.ws_row = 24; tty->winsize.ws_col = 80; diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index aec996de44d9..15692449a1c3 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -967,7 +967,6 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) tty->driver_data = tp; tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_col = tp->view.cols; - tp->port.low_latency = 0; tp->inattr = TF_INPUT; goto port_install; } @@ -996,7 +995,6 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) return rc; } - tp->port.low_latency = 0; tty->winsize.ws_row = tp->view.rows - 2; tty->winsize.ws_col = tp->view.cols; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 13f63c01c589..18b78ea110ef 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -998,7 +998,6 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) state->custom_divisor = ss->custom_divisor; port->close_delay = ss->close_delay * HZ/100; port->closing_wait = ss->closing_wait * HZ/100; - port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; check_and_exit: if (tty_port_initialized(port)) { @@ -1386,8 +1385,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp) tty->driver_data = info; tty->port = port; - port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - retval = startup(tty, info); if (retval) { return retval; diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 509d1042825a..dfe02283ed23 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -605,7 +605,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd) hvcsd->todo_mask |= HVCS_QUICK_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); - /* This is synch because tty->low_latency == 1 */ + /* This is synch -- FIXME :js: it is not! */ if(got) tty_flip_buffer_push(&hvcsd->port); diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 23584769fc29..6dacbc5e286c 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -101,7 +101,6 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) tty->port.tty = linux_tty; linux_tty->driver_data = tty; - tty->port.low_latency = 1; if (tty->tty_type == TTYTYPE_MODEM) ipwireless_ppp_open(tty->network); diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 3703987c4666..4203b64bccdb 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1273,7 +1273,6 @@ static int mxser_set_serial_info(struct tty_struct *tty, (ss->flags & ASYNC_FLAGS)); port->close_delay = ss->close_delay * HZ / 100; port->closing_wait = ss->closing_wait * HZ / 100; - port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && (ss->baud_base != info->baud_base || ss->custom_divisor != diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c index 182e0ccd60b2..d4ef88ee22d0 100644 --- a/drivers/tty/serial/ifx6x60.c +++ b/drivers/tty/serial/ifx6x60.c @@ -565,9 +565,6 @@ static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty) /* put port data into this tty */ tty->driver_data = ifx_dev; - /* allows flip string push from int context */ - port->low_latency = 1; - /* set flag to allows data transfer */ set_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags); diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 371569a0fd00..3c92d4e01488 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -521,9 +521,6 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios, MAX3100_STATUS_PE | MAX3100_STATUS_FE | MAX3100_STATUS_OE; - /* we are sending char from a workqueue so enable */ - s->port.state->port.low_latency = 1; - if (s->poll_time > 0) del_timer_sync(&s->timer); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 828f9ad1be49..7dacdb6a8534 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -975,7 +975,6 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, port->closing_wait = closing_wait; if (new_info->xmit_fifo_size) uport->fifosize = new_info->xmit_fifo_size; - port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; check_and_exit: retval = 0; @@ -1795,8 +1794,6 @@ static int uart_port_activate(struct tty_port *port, struct tty_struct *tty) if (!uport || uport->flags & UPF_DEAD) return -ENXIO; - port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0; - /* * Start up the serial port. */ diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index c0b384e3ed4d..644173786bf0 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -672,7 +672,6 @@ static int open(struct tty_struct *tty, struct file *filp) DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count)); mutex_lock(&info->port.mutex); - info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; spin_lock_irqsave(&info->netlock, flags); if (info->netcount) { diff --git a/include/linux/tty.h b/include/linux/tty.h index 12be8b16cdef..b57f6812b3ba 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -240,8 +240,7 @@ struct tty_port { wait_queue_head_t delta_msr_wait; /* Modem status change */ unsigned long flags; /* User TTY flags ASYNC_ */ unsigned long iflags; /* Internal flags TTY_PORT_ */ - unsigned char console:1, /* port is a console */ - low_latency:1; /* optional: tune for latency */ + unsigned char console:1; /* port is a console */ struct mutex mutex; /* Locking */ struct mutex buf_mutex; /* Buffer alloc lock */ unsigned char *xmit_buf; /* Optional buffer */ -- cgit v1.2.3-59-g8ed1b From f446776ebffb9d3fb145b8d84f7f358f64cb54d6 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 23 Nov 2020 18:49:01 -0600 Subject: tty: Export redirect release This will be required by the pty code when it removes tty_vhangup() on master close. Signed-off-by: Corey Minyard Link: https://lore.kernel.org/r/20201124004902.1398477-2-minyard@acm.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 32 ++++++++++++++++++++++++-------- include/linux/tty.h | 1 + 2 files changed, 25 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 95ba028ef668..225f4933fbde 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -540,6 +540,28 @@ void tty_wakeup(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_wakeup); +/** + * tty_release_redirect - Release a redirect on a pty if present + * @tty: tty device + * + * This is available to the pty code so if the master closes, if the + * slave is a redirect it can release the redirect. + */ +struct file *tty_release_redirect(struct tty_struct *tty) +{ + struct file *f = NULL; + + spin_lock(&redirect_lock); + if (redirect && file_tty(redirect) == tty) { + f = redirect; + redirect = NULL; + } + spin_unlock(&redirect_lock); + + return f; +} +EXPORT_SYMBOL_GPL(tty_release_redirect); + /** * __tty_hangup - actual handler for hangup events * @tty: tty device @@ -566,7 +588,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup); static void __tty_hangup(struct tty_struct *tty, int exit_session) { struct file *cons_filp = NULL; - struct file *filp, *f = NULL; + struct file *filp, *f; struct tty_file_private *priv; int closecount = 0, n; int refs; @@ -574,13 +596,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) if (!tty) return; - - spin_lock(&redirect_lock); - if (redirect && file_tty(redirect) == tty) { - f = redirect; - redirect = NULL; - } - spin_unlock(&redirect_lock); + f = tty_release_redirect(tty); tty_lock(tty); diff --git a/include/linux/tty.h b/include/linux/tty.h index b57f6812b3ba..dd6ded6138f7 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -421,6 +421,7 @@ extern void tty_kclose(struct tty_struct *tty); extern int tty_dev_name_to_number(const char *name, dev_t *number); extern int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout); extern void tty_ldisc_unlock(struct tty_struct *tty); +extern struct file *tty_release_redirect(struct tty_struct *tty); #else static inline void tty_kref_put(struct tty_struct *tty) { } -- cgit v1.2.3-59-g8ed1b From 429b29aef7f841086949c7359f9c3ccb051e7ea3 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 15 Jan 2021 16:51:29 +0100 Subject: tty: serial: Drop unused efm32 serial driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support for this machine was just removed, so drop the now unused UART driver, too. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20210115155130.185010-7-u.kleine-koenig@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 13 - drivers/tty/serial/Makefile | 1 - drivers/tty/serial/efm32-uart.c | 852 ------------------------------- include/linux/platform_data/efm32-uart.h | 19 - include/uapi/linux/serial_core.h | 3 - 5 files changed, 888 deletions(-) delete mode 100644 drivers/tty/serial/efm32-uart.c delete mode 100644 include/linux/platform_data/efm32-uart.h (limited to 'include/linux') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 34a2899e69c0..83f6ca4bf210 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1295,14 +1295,6 @@ config SERIAL_AR933X_NR_UARTS Set this to the number of serial ports you want the driver to support. -config SERIAL_EFM32_UART - tristate "EFM32 UART/USART port" - depends on ARM && (ARCH_EFM32 || COMPILE_TEST) - select SERIAL_CORE - help - This driver support the USART and UART ports on - Energy Micro's efm32 SoCs. - config SERIAL_MPS2_UART_CONSOLE bool "MPS2 UART console support" depends on SERIAL_MPS2_UART @@ -1316,11 +1308,6 @@ config SERIAL_MPS2_UART help This driver support the UART ports on ARM MPS2. -config SERIAL_EFM32_UART_CONSOLE - bool "EFM32 UART/USART console support" - depends on SERIAL_EFM32_UART=y - select SERIAL_CORE_CONSOLE - config SERIAL_ARC tristate "ARC UART driver support" select SERIAL_CORE diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index b85d53f9e9ff..ec2b74091f0c 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -73,7 +73,6 @@ obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o -obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o obj-$(CONFIG_SERIAL_ARC) += arc_uart.o obj-$(CONFIG_SERIAL_RP2) += rp2.o obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c deleted file mode 100644 index f12f29cf4f31..000000000000 --- a/drivers/tty/serial/efm32-uart.c +++ /dev/null @@ -1,852 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define DRIVER_NAME "efm32-uart" -#define DEV_NAME "ttyefm" - -#define UARTn_CTRL 0x00 -#define UARTn_CTRL_SYNC 0x0001 -#define UARTn_CTRL_TXBIL 0x1000 - -#define UARTn_FRAME 0x04 -#define UARTn_FRAME_DATABITS__MASK 0x000f -#define UARTn_FRAME_DATABITS(n) ((n) - 3) -#define UARTn_FRAME_PARITY__MASK 0x0300 -#define UARTn_FRAME_PARITY_NONE 0x0000 -#define UARTn_FRAME_PARITY_EVEN 0x0200 -#define UARTn_FRAME_PARITY_ODD 0x0300 -#define UARTn_FRAME_STOPBITS_HALF 0x0000 -#define UARTn_FRAME_STOPBITS_ONE 0x1000 -#define UARTn_FRAME_STOPBITS_TWO 0x3000 - -#define UARTn_CMD 0x0c -#define UARTn_CMD_RXEN 0x0001 -#define UARTn_CMD_RXDIS 0x0002 -#define UARTn_CMD_TXEN 0x0004 -#define UARTn_CMD_TXDIS 0x0008 - -#define UARTn_STATUS 0x10 -#define UARTn_STATUS_TXENS 0x0002 -#define UARTn_STATUS_TXC 0x0020 -#define UARTn_STATUS_TXBL 0x0040 -#define UARTn_STATUS_RXDATAV 0x0080 - -#define UARTn_CLKDIV 0x14 - -#define UARTn_RXDATAX 0x18 -#define UARTn_RXDATAX_RXDATA__MASK 0x01ff -#define UARTn_RXDATAX_PERR 0x4000 -#define UARTn_RXDATAX_FERR 0x8000 -/* - * This is a software only flag used for ignore_status_mask and - * read_status_mask! It's used for breaks that the hardware doesn't report - * explicitly. - */ -#define SW_UARTn_RXDATAX_BERR 0x2000 - -#define UARTn_TXDATA 0x34 - -#define UARTn_IF 0x40 -#define UARTn_IF_TXC 0x0001 -#define UARTn_IF_TXBL 0x0002 -#define UARTn_IF_RXDATAV 0x0004 -#define UARTn_IF_RXOF 0x0010 - -#define UARTn_IFS 0x44 -#define UARTn_IFC 0x48 -#define UARTn_IEN 0x4c - -#define UARTn_ROUTE 0x54 -#define UARTn_ROUTE_LOCATION__MASK 0x0700 -#define UARTn_ROUTE_LOCATION(n) (((n) << 8) & UARTn_ROUTE_LOCATION__MASK) -#define UARTn_ROUTE_RXPEN 0x0001 -#define UARTn_ROUTE_TXPEN 0x0002 - -struct efm32_uart_port { - struct uart_port port; - unsigned int txirq; - struct clk *clk; - struct efm32_uart_pdata pdata; -}; -#define to_efm_port(_port) container_of(_port, struct efm32_uart_port, port) -#define efm_debug(efm_port, format, arg...) \ - dev_dbg(efm_port->port.dev, format, ##arg) - -static void efm32_uart_write32(struct efm32_uart_port *efm_port, - u32 value, unsigned offset) -{ - writel_relaxed(value, efm_port->port.membase + offset); -} - -static u32 efm32_uart_read32(struct efm32_uart_port *efm_port, - unsigned offset) -{ - return readl_relaxed(efm_port->port.membase + offset); -} - -static unsigned int efm32_uart_tx_empty(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - u32 status = efm32_uart_read32(efm_port, UARTn_STATUS); - - if (status & UARTn_STATUS_TXC) - return TIOCSER_TEMT; - else - return 0; -} - -static void efm32_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - /* sorry, neither handshaking lines nor loop functionallity */ -} - -static unsigned int efm32_uart_get_mctrl(struct uart_port *port) -{ - /* sorry, no handshaking lines available */ - return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR; -} - -static void efm32_uart_stop_tx(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - u32 ien = efm32_uart_read32(efm_port, UARTn_IEN); - - efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD); - ien &= ~(UARTn_IF_TXC | UARTn_IF_TXBL); - efm32_uart_write32(efm_port, ien, UARTn_IEN); -} - -static void efm32_uart_tx_chars(struct efm32_uart_port *efm_port) -{ - struct uart_port *port = &efm_port->port; - struct circ_buf *xmit = &port->state->xmit; - - while (efm32_uart_read32(efm_port, UARTn_STATUS) & - UARTn_STATUS_TXBL) { - if (port->x_char) { - port->icount.tx++; - efm32_uart_write32(efm_port, port->x_char, - UARTn_TXDATA); - port->x_char = 0; - continue; - } - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { - port->icount.tx++; - efm32_uart_write32(efm_port, xmit->buf[xmit->tail], - UARTn_TXDATA); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - } else - break; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (!port->x_char && uart_circ_empty(xmit) && - efm32_uart_read32(efm_port, UARTn_STATUS) & - UARTn_STATUS_TXC) - efm32_uart_stop_tx(port); -} - -static void efm32_uart_start_tx(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - u32 ien; - - efm32_uart_write32(efm_port, - UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IFC); - ien = efm32_uart_read32(efm_port, UARTn_IEN); - efm32_uart_write32(efm_port, - ien | UARTn_IF_TXBL | UARTn_IF_TXC, UARTn_IEN); - efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD); - - efm32_uart_tx_chars(efm_port); -} - -static void efm32_uart_stop_rx(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - - efm32_uart_write32(efm_port, UARTn_CMD_RXDIS, UARTn_CMD); -} - -static void efm32_uart_break_ctl(struct uart_port *port, int ctl) -{ - /* not possible without fiddling with gpios */ -} - -static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port) -{ - struct uart_port *port = &efm_port->port; - - while (efm32_uart_read32(efm_port, UARTn_STATUS) & - UARTn_STATUS_RXDATAV) { - u32 rxdata = efm32_uart_read32(efm_port, UARTn_RXDATAX); - int flag = 0; - - /* - * This is a reserved bit and I only saw it read as 0. But to be - * sure not to be confused too much by new devices adhere to the - * warning in the reference manual that reserved bits might - * read as 1 in the future. - */ - rxdata &= ~SW_UARTn_RXDATAX_BERR; - - port->icount.rx++; - - if ((rxdata & UARTn_RXDATAX_FERR) && - !(rxdata & UARTn_RXDATAX_RXDATA__MASK)) { - rxdata |= SW_UARTn_RXDATAX_BERR; - port->icount.brk++; - if (uart_handle_break(port)) - continue; - } else if (rxdata & UARTn_RXDATAX_PERR) - port->icount.parity++; - else if (rxdata & UARTn_RXDATAX_FERR) - port->icount.frame++; - - rxdata &= port->read_status_mask; - - if (rxdata & SW_UARTn_RXDATAX_BERR) - flag = TTY_BREAK; - else if (rxdata & UARTn_RXDATAX_PERR) - flag = TTY_PARITY; - else if (rxdata & UARTn_RXDATAX_FERR) - flag = TTY_FRAME; - else if (uart_handle_sysrq_char(port, - rxdata & UARTn_RXDATAX_RXDATA__MASK)) - continue; - - if ((rxdata & port->ignore_status_mask) == 0) - tty_insert_flip_char(&port->state->port, - rxdata & UARTn_RXDATAX_RXDATA__MASK, flag); - } -} - -static irqreturn_t efm32_uart_rxirq(int irq, void *data) -{ - struct efm32_uart_port *efm_port = data; - u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF); - int handled = IRQ_NONE; - struct uart_port *port = &efm_port->port; - struct tty_port *tport = &port->state->port; - - spin_lock(&port->lock); - - if (irqflag & UARTn_IF_RXDATAV) { - efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC); - efm32_uart_rx_chars(efm_port); - - handled = IRQ_HANDLED; - } - - if (irqflag & UARTn_IF_RXOF) { - efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC); - port->icount.overrun++; - tty_insert_flip_char(tport, 0, TTY_OVERRUN); - - handled = IRQ_HANDLED; - } - - spin_unlock(&port->lock); - - tty_flip_buffer_push(tport); - - return handled; -} - -static irqreturn_t efm32_uart_txirq(int irq, void *data) -{ - struct efm32_uart_port *efm_port = data; - u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF); - - /* TXBL doesn't need to be cleared */ - if (irqflag & UARTn_IF_TXC) - efm32_uart_write32(efm_port, UARTn_IF_TXC, UARTn_IFC); - - if (irqflag & (UARTn_IF_TXC | UARTn_IF_TXBL)) { - efm32_uart_tx_chars(efm_port); - return IRQ_HANDLED; - } else - return IRQ_NONE; -} - -static int efm32_uart_startup(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - int ret; - - ret = clk_enable(efm_port->clk); - if (ret) { - efm_debug(efm_port, "failed to enable clk\n"); - goto err_clk_enable; - } - port->uartclk = clk_get_rate(efm_port->clk); - - /* Enable pins at configured location */ - efm32_uart_write32(efm_port, - UARTn_ROUTE_LOCATION(efm_port->pdata.location) | - UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN, - UARTn_ROUTE); - - ret = request_irq(port->irq, efm32_uart_rxirq, 0, - DRIVER_NAME, efm_port); - if (ret) { - efm_debug(efm_port, "failed to register rxirq\n"); - goto err_request_irq_rx; - } - - /* disable all irqs */ - efm32_uart_write32(efm_port, 0, UARTn_IEN); - - ret = request_irq(efm_port->txirq, efm32_uart_txirq, 0, - DRIVER_NAME, efm_port); - if (ret) { - efm_debug(efm_port, "failed to register txirq\n"); - free_irq(port->irq, efm_port); -err_request_irq_rx: - - clk_disable(efm_port->clk); - } else { - efm32_uart_write32(efm_port, - UARTn_IF_RXDATAV | UARTn_IF_RXOF, UARTn_IEN); - efm32_uart_write32(efm_port, UARTn_CMD_RXEN, UARTn_CMD); - } - -err_clk_enable: - return ret; -} - -static void efm32_uart_shutdown(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - - efm32_uart_write32(efm_port, 0, UARTn_IEN); - free_irq(port->irq, efm_port); - - clk_disable(efm_port->clk); -} - -static void efm32_uart_set_termios(struct uart_port *port, - struct ktermios *new, struct ktermios *old) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - unsigned long flags; - unsigned baud; - u32 clkdiv; - u32 frame = 0; - - /* no modem control lines */ - new->c_cflag &= ~(CRTSCTS | CMSPAR); - - baud = uart_get_baud_rate(port, new, old, - DIV_ROUND_CLOSEST(port->uartclk, 16 * 8192), - DIV_ROUND_CLOSEST(port->uartclk, 16)); - - switch (new->c_cflag & CSIZE) { - case CS5: - frame |= UARTn_FRAME_DATABITS(5); - break; - case CS6: - frame |= UARTn_FRAME_DATABITS(6); - break; - case CS7: - frame |= UARTn_FRAME_DATABITS(7); - break; - case CS8: - frame |= UARTn_FRAME_DATABITS(8); - break; - } - - if (new->c_cflag & CSTOPB) - /* the receiver only verifies the first stop bit */ - frame |= UARTn_FRAME_STOPBITS_TWO; - else - frame |= UARTn_FRAME_STOPBITS_ONE; - - if (new->c_cflag & PARENB) { - if (new->c_cflag & PARODD) - frame |= UARTn_FRAME_PARITY_ODD; - else - frame |= UARTn_FRAME_PARITY_EVEN; - } else - frame |= UARTn_FRAME_PARITY_NONE; - - /* - * the 6 lowest bits of CLKDIV are dc, bit 6 has value 0.25. - * port->uartclk <= 14e6, so 4 * port->uartclk doesn't overflow. - */ - clkdiv = (DIV_ROUND_CLOSEST(4 * port->uartclk, 16 * baud) - 4) << 6; - - spin_lock_irqsave(&port->lock, flags); - - efm32_uart_write32(efm_port, - UARTn_CMD_TXDIS | UARTn_CMD_RXDIS, UARTn_CMD); - - port->read_status_mask = UARTn_RXDATAX_RXDATA__MASK; - if (new->c_iflag & INPCK) - port->read_status_mask |= - UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR; - if (new->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= SW_UARTn_RXDATAX_BERR; - - port->ignore_status_mask = 0; - if (new->c_iflag & IGNPAR) - port->ignore_status_mask |= - UARTn_RXDATAX_FERR | UARTn_RXDATAX_PERR; - if (new->c_iflag & IGNBRK) - port->ignore_status_mask |= SW_UARTn_RXDATAX_BERR; - - uart_update_timeout(port, new->c_cflag, baud); - - efm32_uart_write32(efm_port, UARTn_CTRL_TXBIL, UARTn_CTRL); - efm32_uart_write32(efm_port, frame, UARTn_FRAME); - efm32_uart_write32(efm_port, clkdiv, UARTn_CLKDIV); - - efm32_uart_write32(efm_port, UARTn_CMD_TXEN | UARTn_CMD_RXEN, - UARTn_CMD); - - spin_unlock_irqrestore(&port->lock, flags); -} - -static const char *efm32_uart_type(struct uart_port *port) -{ - return port->type == PORT_EFMUART ? "efm32-uart" : NULL; -} - -static void efm32_uart_release_port(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - - clk_unprepare(efm_port->clk); - clk_put(efm_port->clk); - iounmap(port->membase); -} - -static int efm32_uart_request_port(struct uart_port *port) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - int ret; - - port->membase = ioremap(port->mapbase, 60); - if (!efm_port->port.membase) { - ret = -ENOMEM; - efm_debug(efm_port, "failed to remap\n"); - goto err_ioremap; - } - - efm_port->clk = clk_get(port->dev, NULL); - if (IS_ERR(efm_port->clk)) { - ret = PTR_ERR(efm_port->clk); - efm_debug(efm_port, "failed to get clock\n"); - goto err_clk_get; - } - - ret = clk_prepare(efm_port->clk); - if (ret) { - clk_put(efm_port->clk); -err_clk_get: - - iounmap(port->membase); -err_ioremap: - return ret; - } - return 0; -} - -static void efm32_uart_config_port(struct uart_port *port, int type) -{ - if (type & UART_CONFIG_TYPE && - !efm32_uart_request_port(port)) - port->type = PORT_EFMUART; -} - -static int efm32_uart_verify_port(struct uart_port *port, - struct serial_struct *serinfo) -{ - int ret = 0; - - if (serinfo->type != PORT_UNKNOWN && serinfo->type != PORT_EFMUART) - ret = -EINVAL; - - return ret; -} - -static const struct uart_ops efm32_uart_pops = { - .tx_empty = efm32_uart_tx_empty, - .set_mctrl = efm32_uart_set_mctrl, - .get_mctrl = efm32_uart_get_mctrl, - .stop_tx = efm32_uart_stop_tx, - .start_tx = efm32_uart_start_tx, - .stop_rx = efm32_uart_stop_rx, - .break_ctl = efm32_uart_break_ctl, - .startup = efm32_uart_startup, - .shutdown = efm32_uart_shutdown, - .set_termios = efm32_uart_set_termios, - .type = efm32_uart_type, - .release_port = efm32_uart_release_port, - .request_port = efm32_uart_request_port, - .config_port = efm32_uart_config_port, - .verify_port = efm32_uart_verify_port, -}; - -static struct efm32_uart_port *efm32_uart_ports[5]; - -#ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE -static void efm32_uart_console_putchar(struct uart_port *port, int ch) -{ - struct efm32_uart_port *efm_port = to_efm_port(port); - unsigned int timeout = 0x400; - u32 status; - - while (1) { - status = efm32_uart_read32(efm_port, UARTn_STATUS); - - if (status & UARTn_STATUS_TXBL) - break; - if (!timeout--) - return; - } - efm32_uart_write32(efm_port, ch, UARTn_TXDATA); -} - -static void efm32_uart_console_write(struct console *co, const char *s, - unsigned int count) -{ - struct efm32_uart_port *efm_port = efm32_uart_ports[co->index]; - u32 status = efm32_uart_read32(efm_port, UARTn_STATUS); - unsigned int timeout = 0x400; - - if (!(status & UARTn_STATUS_TXENS)) - efm32_uart_write32(efm_port, UARTn_CMD_TXEN, UARTn_CMD); - - uart_console_write(&efm_port->port, s, count, - efm32_uart_console_putchar); - - /* Wait for the transmitter to become empty */ - while (1) { - u32 status = efm32_uart_read32(efm_port, UARTn_STATUS); - if (status & UARTn_STATUS_TXC) - break; - if (!timeout--) - break; - } - - if (!(status & UARTn_STATUS_TXENS)) - efm32_uart_write32(efm_port, UARTn_CMD_TXDIS, UARTn_CMD); -} - -static void efm32_uart_console_get_options(struct efm32_uart_port *efm_port, - int *baud, int *parity, int *bits) -{ - u32 ctrl = efm32_uart_read32(efm_port, UARTn_CTRL); - u32 route, clkdiv, frame; - - if (ctrl & UARTn_CTRL_SYNC) - /* not operating in async mode */ - return; - - route = efm32_uart_read32(efm_port, UARTn_ROUTE); - if (!(route & UARTn_ROUTE_TXPEN)) - /* tx pin not routed */ - return; - - clkdiv = efm32_uart_read32(efm_port, UARTn_CLKDIV); - - *baud = DIV_ROUND_CLOSEST(4 * efm_port->port.uartclk, - 16 * (4 + (clkdiv >> 6))); - - frame = efm32_uart_read32(efm_port, UARTn_FRAME); - switch (frame & UARTn_FRAME_PARITY__MASK) { - case UARTn_FRAME_PARITY_ODD: - *parity = 'o'; - break; - case UARTn_FRAME_PARITY_EVEN: - *parity = 'e'; - break; - default: - *parity = 'n'; - } - - *bits = (frame & UARTn_FRAME_DATABITS__MASK) - - UARTn_FRAME_DATABITS(4) + 4; - - efm_debug(efm_port, "get_opts: options=%d%c%d\n", - *baud, *parity, *bits); -} - -static int efm32_uart_console_setup(struct console *co, char *options) -{ - struct efm32_uart_port *efm_port; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int ret; - - if (co->index < 0 || co->index >= ARRAY_SIZE(efm32_uart_ports)) { - unsigned i; - for (i = 0; i < ARRAY_SIZE(efm32_uart_ports); ++i) { - if (efm32_uart_ports[i]) { - pr_warn("efm32-console: fall back to console index %u (from %hhi)\n", - i, co->index); - co->index = i; - break; - } - } - } - - efm_port = efm32_uart_ports[co->index]; - if (!efm_port) { - pr_warn("efm32-console: No port at %d\n", co->index); - return -ENODEV; - } - - ret = clk_prepare(efm_port->clk); - if (ret) { - dev_warn(efm_port->port.dev, - "console: clk_prepare failed: %d\n", ret); - return ret; - } - - efm_port->port.uartclk = clk_get_rate(efm_port->clk); - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - efm32_uart_console_get_options(efm_port, - &baud, &parity, &bits); - - return uart_set_options(&efm_port->port, co, baud, parity, bits, flow); -} - -static struct uart_driver efm32_uart_reg; - -static struct console efm32_uart_console = { - .name = DEV_NAME, - .write = efm32_uart_console_write, - .device = uart_console_device, - .setup = efm32_uart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &efm32_uart_reg, -}; - -#else -#define efm32_uart_console (*(struct console *)NULL) -#endif /* ifdef CONFIG_SERIAL_EFM32_UART_CONSOLE / else */ - -static struct uart_driver efm32_uart_reg = { - .owner = THIS_MODULE, - .driver_name = DRIVER_NAME, - .dev_name = DEV_NAME, - .nr = ARRAY_SIZE(efm32_uart_ports), - .cons = &efm32_uart_console, -}; - -static int efm32_uart_probe_dt(struct platform_device *pdev, - struct efm32_uart_port *efm_port) -{ - struct device_node *np = pdev->dev.of_node; - u32 location; - int ret; - - if (!np) - return 1; - - ret = of_property_read_u32(np, "energymicro,location", &location); - - if (ret) - /* fall back to wrongly namespaced property */ - ret = of_property_read_u32(np, "efm32,location", &location); - - if (ret) - /* fall back to old and (wrongly) generic property "location" */ - ret = of_property_read_u32(np, "location", &location); - - if (!ret) { - if (location > 5) { - dev_err(&pdev->dev, "invalid location\n"); - return -EINVAL; - } - efm_debug(efm_port, "using location %u\n", location); - efm_port->pdata.location = location; - } else { - efm_debug(efm_port, "fall back to location 0\n"); - } - - ret = of_alias_get_id(np, "serial"); - if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias id: %d\n", ret); - return ret; - } else { - efm_port->port.line = ret; - return 0; - } - -} - -static int efm32_uart_probe(struct platform_device *pdev) -{ - struct efm32_uart_port *efm_port; - struct resource *res; - unsigned int line; - int ret; - - efm_port = kzalloc(sizeof(*efm_port), GFP_KERNEL); - if (!efm_port) { - dev_dbg(&pdev->dev, "failed to allocate private data\n"); - return -ENOMEM; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - ret = -ENODEV; - dev_dbg(&pdev->dev, "failed to determine base address\n"); - goto err_get_base; - } - - if (resource_size(res) < 60) { - ret = -EINVAL; - dev_dbg(&pdev->dev, "memory resource too small\n"); - goto err_too_small; - } - - ret = platform_get_irq(pdev, 0); - if (ret <= 0) { - dev_dbg(&pdev->dev, "failed to get rx irq\n"); - goto err_get_rxirq; - } - - efm_port->port.irq = ret; - - ret = platform_get_irq(pdev, 1); - if (ret <= 0) - ret = efm_port->port.irq + 1; - - efm_port->txirq = ret; - - efm_port->port.dev = &pdev->dev; - efm_port->port.mapbase = res->start; - efm_port->port.type = PORT_EFMUART; - efm_port->port.iotype = UPIO_MEM32; - efm_port->port.fifosize = 2; - efm_port->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_EFM32_UART_CONSOLE); - efm_port->port.ops = &efm32_uart_pops; - efm_port->port.flags = UPF_BOOT_AUTOCONF; - - ret = efm32_uart_probe_dt(pdev, efm_port); - if (ret > 0) { - /* not created by device tree */ - const struct efm32_uart_pdata *pdata = dev_get_platdata(&pdev->dev); - - efm_port->port.line = pdev->id; - - if (pdata) - efm_port->pdata = *pdata; - } else if (ret < 0) - goto err_probe_dt; - - line = efm_port->port.line; - - if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports)) - efm32_uart_ports[line] = efm_port; - - ret = uart_add_one_port(&efm32_uart_reg, &efm_port->port); - if (ret) { - dev_dbg(&pdev->dev, "failed to add port: %d\n", ret); - - if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports)) - efm32_uart_ports[line] = NULL; -err_probe_dt: -err_get_rxirq: -err_too_small: -err_get_base: - kfree(efm_port); - } else { - platform_set_drvdata(pdev, efm_port); - dev_dbg(&pdev->dev, "\\o/\n"); - } - - return ret; -} - -static int efm32_uart_remove(struct platform_device *pdev) -{ - struct efm32_uart_port *efm_port = platform_get_drvdata(pdev); - unsigned int line = efm_port->port.line; - - uart_remove_one_port(&efm32_uart_reg, &efm_port->port); - - if (line >= 0 && line < ARRAY_SIZE(efm32_uart_ports)) - efm32_uart_ports[line] = NULL; - - kfree(efm_port); - - return 0; -} - -static const struct of_device_id efm32_uart_dt_ids[] = { - { - .compatible = "energymicro,efm32-uart", - }, { - /* doesn't follow the "vendor,device" scheme, don't use */ - .compatible = "efm32,uart", - }, { - /* sentinel */ - } -}; -MODULE_DEVICE_TABLE(of, efm32_uart_dt_ids); - -static struct platform_driver efm32_uart_driver = { - .probe = efm32_uart_probe, - .remove = efm32_uart_remove, - - .driver = { - .name = DRIVER_NAME, - .of_match_table = efm32_uart_dt_ids, - }, -}; - -static int __init efm32_uart_init(void) -{ - int ret; - - ret = uart_register_driver(&efm32_uart_reg); - if (ret) - return ret; - - ret = platform_driver_register(&efm32_uart_driver); - if (ret) - uart_unregister_driver(&efm32_uart_reg); - - pr_info("EFM32 UART/USART driver\n"); - - return ret; -} -module_init(efm32_uart_init); - -static void __exit efm32_uart_exit(void) -{ - platform_driver_unregister(&efm32_uart_driver); - uart_unregister_driver(&efm32_uart_reg); -} -module_exit(efm32_uart_exit); - -MODULE_AUTHOR("Uwe Kleine-Koenig "); -MODULE_DESCRIPTION("EFM32 UART/USART driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/include/linux/platform_data/efm32-uart.h b/include/linux/platform_data/efm32-uart.h deleted file mode 100644 index ccbb8f11db75..000000000000 --- a/include/linux/platform_data/efm32-uart.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * - * - */ -#ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__ -#define __LINUX_PLATFORM_DATA_EFM32_UART_H__ - -#include - -/** - * struct efm32_uart_pdata - * @location: pinmux location for the I/O pins (to be written to the ROUTE - * register) - */ -struct efm32_uart_pdata { - u8 location; -}; -#endif /* ifndef __LINUX_PLATFORM_DATA_EFM32_UART_H__ */ diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 62c22045fe65..c4042dcfdc0c 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -208,9 +208,6 @@ /* Atheros AR933X SoC */ #define PORT_AR933X 99 -/* Energy Micro efm32 SoC */ -#define PORT_EFMUART 100 - /* ARC (Synopsys) on-chip UART */ #define PORT_ARC 101 -- cgit v1.2.3-59-g8ed1b From 3b830a9c34d5897be07176ce4e6f2d75e2c8cfd7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 18 Jan 2021 13:31:30 -0800 Subject: tty: convert tty_ldisc_ops 'read()' function to take a kernel pointer The tty line discipline .read() function was passed the final user pointer destination as an argument, which doesn't match the 'write()' function, and makes it very inconvenient to do a splice method for ttys. This is a conversion to use a kernel buffer instead. NOTE! It does this by passing the tty line discipline ->read() function an additional "cookie" to fill in, and an offset into the cookie data. The line discipline can fill in the cookie data with its own private information, and then the reader will repeat the read until either the cookie is cleared or it runs out of data. The only real user of this is N_HDLC, which can use this to handle big packets, even if the kernel buffer is smaller than the whole packet. Cc: Christoph Hellwig Cc: Greg Kroah-Hartman Cc: Al Viro Signed-off-by: Linus Torvalds --- drivers/bluetooth/hci_ldisc.c | 34 +++++++++--------- drivers/input/serio/serport.c | 4 ++- drivers/net/ppp/ppp_async.c | 3 +- drivers/net/ppp/ppp_synctty.c | 3 +- drivers/tty/n_gsm.c | 3 +- drivers/tty/n_hdlc.c | 60 +++++++++++++++++++++---------- drivers/tty/n_null.c | 3 +- drivers/tty/n_r3964.c | 10 +++--- drivers/tty/n_tracerouter.c | 4 ++- drivers/tty/n_tracesink.c | 4 ++- drivers/tty/n_tty.c | 82 ++++++++++++++++++------------------------- drivers/tty/tty_io.c | 64 +++++++++++++++++++++++++++++++-- include/linux/tty_ldisc.h | 3 +- net/nfc/nci/uart.c | 3 +- 14 files changed, 178 insertions(+), 102 deletions(-) (limited to 'include/linux') diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index f83d67eafc9f..dd92aea15b8b 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -802,7 +802,8 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, * We don't provide read/write/poll interface for user space. */ static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) + unsigned char *buf, size_t nr, + void **cookie, unsigned long offset) { return 0; } @@ -819,29 +820,28 @@ static __poll_t hci_uart_tty_poll(struct tty_struct *tty, return 0; } +static struct tty_ldisc_ops hci_uart_ldisc = { + .owner = THIS_MODULE, + .magic = TTY_LDISC_MAGIC, + .name = "n_hci", + .open = hci_uart_tty_open, + .close = hci_uart_tty_close, + .read = hci_uart_tty_read, + .write = hci_uart_tty_write, + .ioctl = hci_uart_tty_ioctl, + .compat_ioctl = hci_uart_tty_ioctl, + .poll = hci_uart_tty_poll, + .receive_buf = hci_uart_tty_receive, + .write_wakeup = hci_uart_tty_wakeup, +}; + static int __init hci_uart_init(void) { - static struct tty_ldisc_ops hci_uart_ldisc; int err; BT_INFO("HCI UART driver ver %s", VERSION); /* Register the tty discipline */ - - memset(&hci_uart_ldisc, 0, sizeof(hci_uart_ldisc)); - hci_uart_ldisc.magic = TTY_LDISC_MAGIC; - hci_uart_ldisc.name = "n_hci"; - hci_uart_ldisc.open = hci_uart_tty_open; - hci_uart_ldisc.close = hci_uart_tty_close; - hci_uart_ldisc.read = hci_uart_tty_read; - hci_uart_ldisc.write = hci_uart_tty_write; - hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; - hci_uart_ldisc.compat_ioctl = hci_uart_tty_ioctl; - hci_uart_ldisc.poll = hci_uart_tty_poll; - hci_uart_ldisc.receive_buf = hci_uart_tty_receive; - hci_uart_ldisc.write_wakeup = hci_uart_tty_wakeup; - hci_uart_ldisc.owner = THIS_MODULE; - err = tty_register_ldisc(N_HCI, &hci_uart_ldisc); if (err) { BT_ERR("HCI line discipline registration failed. (%d)", err); diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 8ac970a423de..33e9d9bfd036 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -156,7 +156,9 @@ out: * returning 0 characters. */ -static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr) +static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, + unsigned char *kbuf, size_t nr, + void **cookie, unsigned long offset) { struct serport *serport = (struct serport*) tty->disc_data; struct serio *serio; diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index 29a0917a81e6..f14a9d190de9 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -259,7 +259,8 @@ static int ppp_asynctty_hangup(struct tty_struct *tty) */ static ssize_t ppp_asynctty_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t count) + unsigned char *buf, size_t count, + void **cookie, unsigned long offset) { return -EAGAIN; } diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index 0f338752c38b..f774b7e52da4 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -257,7 +257,8 @@ static int ppp_sync_hangup(struct tty_struct *tty) */ static ssize_t ppp_sync_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t count) + unsigned char *buf, size_t count, + void **cookie, unsigned long offset) { return -EAGAIN; } diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 25f3152089c2..fea1eeac5b90 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2557,7 +2557,8 @@ static void gsmld_write_wakeup(struct tty_struct *tty) */ static ssize_t gsmld_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) + unsigned char *buf, size_t nr, + void **cookie, unsigned long offset) { return -EOPNOTSUPP; } diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 12557ee1edb6..1363e659dc1d 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -416,13 +416,19 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, * Returns the number of bytes returned or error code. */ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, - __u8 __user *buf, size_t nr) + __u8 *kbuf, size_t nr, + void **cookie, unsigned long offset) { struct n_hdlc *n_hdlc = tty->disc_data; int ret = 0; struct n_hdlc_buf *rbuf; DECLARE_WAITQUEUE(wait, current); + /* Is this a repeated call for an rbuf we already found earlier? */ + rbuf = *cookie; + if (rbuf) + goto have_rbuf; + add_wait_queue(&tty->read_wait, &wait); for (;;) { @@ -436,25 +442,8 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, set_current_state(TASK_INTERRUPTIBLE); rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); - if (rbuf) { - if (rbuf->count > nr) { - /* too large for caller's buffer */ - ret = -EOVERFLOW; - } else { - __set_current_state(TASK_RUNNING); - if (copy_to_user(buf, rbuf->buf, rbuf->count)) - ret = -EFAULT; - else - ret = rbuf->count; - } - - if (n_hdlc->rx_free_buf_list.count > - DEFAULT_RX_BUF_COUNT) - kfree(rbuf); - else - n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf); + if (rbuf) break; - } /* no data */ if (tty_io_nonblock(tty, file)) { @@ -473,6 +462,39 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, remove_wait_queue(&tty->read_wait, &wait); __set_current_state(TASK_RUNNING); + if (!rbuf) + return ret; + *cookie = rbuf; + +have_rbuf: + /* Have we used it up entirely? */ + if (offset >= rbuf->count) + goto done_with_rbuf; + + /* More data to go, but can't copy any more? EOVERFLOW */ + ret = -EOVERFLOW; + if (!nr) + goto done_with_rbuf; + + /* Copy as much data as possible */ + ret = rbuf->count - offset; + if (ret > nr) + ret = nr; + memcpy(kbuf, rbuf->buf+offset, ret); + offset += ret; + + /* If we still have data left, we leave the rbuf in the cookie */ + if (offset < rbuf->count) + return ret; + +done_with_rbuf: + *cookie = NULL; + + if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) + kfree(rbuf); + else + n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf); + return ret; } /* end of n_hdlc_tty_read() */ diff --git a/drivers/tty/n_null.c b/drivers/tty/n_null.c index 96feabae4740..ce03ae78f5c6 100644 --- a/drivers/tty/n_null.c +++ b/drivers/tty/n_null.c @@ -20,7 +20,8 @@ static void n_null_close(struct tty_struct *tty) } static ssize_t n_null_read(struct tty_struct *tty, struct file *file, - unsigned char __user * buf, size_t nr) + unsigned char *buf, size_t nr, + void **cookie, unsigned long offset) { return -EOPNOTSUPP; } diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 934dd2fb2ec8..3161f0a535e3 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -129,7 +129,7 @@ static void remove_client_block(struct r3964_info *pInfo, 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, - unsigned char __user * buf, size_t nr); + 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, @@ -1058,7 +1058,8 @@ static void r3964_close(struct tty_struct *tty) } static ssize_t r3964_read(struct tty_struct *tty, struct file *file, - unsigned char __user * buf, size_t nr) + unsigned char *kbuf, size_t nr, + void **cookie, unsigned long offset) { struct r3964_info *pInfo = tty->disc_data; struct r3964_client_info *pClient; @@ -1109,10 +1110,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, kfree(pMsg); TRACE_M("r3964_read - msg kfree %p", pMsg); - if (copy_to_user(buf, &theMsg, ret)) { - ret = -EFAULT; - goto unlock; - } + memcpy(kbuf, &theMsg, ret); TRACE_PS("read - return %d", ret); goto unlock; diff --git a/drivers/tty/n_tracerouter.c b/drivers/tty/n_tracerouter.c index 4479af4d2fa5..3490ed51b1a3 100644 --- a/drivers/tty/n_tracerouter.c +++ b/drivers/tty/n_tracerouter.c @@ -118,7 +118,9 @@ static void n_tracerouter_close(struct tty_struct *tty) * -EINVAL */ static ssize_t n_tracerouter_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) { + unsigned char *buf, size_t nr, + void **cookie, unsigned long offset) +{ return -EINVAL; } diff --git a/drivers/tty/n_tracesink.c b/drivers/tty/n_tracesink.c index d96ba82cc356..1d9931041fd8 100644 --- a/drivers/tty/n_tracesink.c +++ b/drivers/tty/n_tracesink.c @@ -115,7 +115,9 @@ static void n_tracesink_close(struct tty_struct *tty) * -EINVAL */ static ssize_t n_tracesink_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) { + unsigned char *buf, size_t nr, + void **cookie, unsigned long offset) +{ return -EINVAL; } diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 7e5e36315260..4a34a9f43b29 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -164,29 +164,24 @@ static void zero_buffer(struct tty_struct *tty, u8 *buffer, int size) memset(buffer, 0x00, size); } -static int tty_copy_to_user(struct tty_struct *tty, void __user *to, - size_t tail, size_t n) +static void tty_copy(struct tty_struct *tty, void *to, size_t tail, size_t n) { struct n_tty_data *ldata = tty->disc_data; size_t size = N_TTY_BUF_SIZE - tail; void *from = read_buf_addr(ldata, tail); - int uncopied; if (n > size) { tty_audit_add_data(tty, from, size); - uncopied = copy_to_user(to, from, size); - zero_buffer(tty, from, size - uncopied); - if (uncopied) - return uncopied; + memcpy(to, from, size); + zero_buffer(tty, from, size); to += size; n -= size; from = ldata->read_buf; } tty_audit_add_data(tty, from, n); - uncopied = copy_to_user(to, from, n); - zero_buffer(tty, from, n - uncopied); - return uncopied; + memcpy(to, from, n); + zero_buffer(tty, from, n); } /** @@ -1942,15 +1937,16 @@ static inline int input_available_p(struct tty_struct *tty, int poll) /** * copy_from_read_buf - copy read data directly * @tty: terminal device - * @b: user data + * @kbp: data * @nr: size of data * * Helper function to speed up n_tty_read. It is only called when - * ICANON is off; it copies characters straight from the tty queue to - * user space directly. It can be profitably called twice; once to - * drain the space from the tail pointer to the (physical) end of the - * buffer, and once to drain the space from the (physical) beginning of - * the buffer to head pointer. + * ICANON is off; it copies characters straight from the tty queue. + * + * It can be profitably called twice; once to drain the space from + * the tail pointer to the (physical) end of the buffer, and once + * to drain the space from the (physical) beginning of the buffer + * to head pointer. * * Called under the ldata->atomic_read_lock sem * @@ -1960,7 +1956,7 @@ static inline int input_available_p(struct tty_struct *tty, int poll) */ static int copy_from_read_buf(struct tty_struct *tty, - unsigned char __user **b, + unsigned char **kbp, size_t *nr) { @@ -1976,8 +1972,7 @@ static int copy_from_read_buf(struct tty_struct *tty, n = min(*nr, n); if (n) { unsigned char *from = read_buf_addr(ldata, tail); - retval = copy_to_user(*b, from, n); - n -= retval; + memcpy(*kbp, from, n); is_eof = n == 1 && *from == EOF_CHAR(tty); tty_audit_add_data(tty, from, n); zero_buffer(tty, from, n); @@ -1986,7 +1981,7 @@ static int copy_from_read_buf(struct tty_struct *tty, if (L_EXTPROC(tty) && ldata->icanon && is_eof && (head == ldata->read_tail)) n = 0; - *b += n; + *kbp += n; *nr -= n; } return retval; @@ -1995,12 +1990,12 @@ static int copy_from_read_buf(struct tty_struct *tty, /** * canon_copy_from_read_buf - copy read data in canonical mode * @tty: terminal device - * @b: user data + * @kbp: data * @nr: size of data * * Helper function for n_tty_read. It is only called when ICANON is on; * it copies one line of input up to and including the line-delimiting - * character into the user-space buffer. + * character into the result buffer. * * NB: When termios is changed from non-canonical to canonical mode and * the read buffer contains data, n_tty_set_termios() simulates an EOF @@ -2016,14 +2011,14 @@ static int copy_from_read_buf(struct tty_struct *tty, */ static int canon_copy_from_read_buf(struct tty_struct *tty, - unsigned char __user **b, + unsigned char **kbp, size_t *nr) { struct n_tty_data *ldata = tty->disc_data; size_t n, size, more, c; size_t eol; size_t tail; - int ret, found = 0; + int found = 0; /* N.B. avoid overrun if nr == 0 */ if (!*nr) @@ -2059,10 +2054,8 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n", __func__, eol, found, n, c, tail, more); - ret = tty_copy_to_user(tty, *b, tail, n); - if (ret) - return -EFAULT; - *b += n; + tty_copy(tty, *kbp, tail, n); + *kbp += n; *nr -= n; if (found) @@ -2130,10 +2123,11 @@ static int job_control(struct tty_struct *tty, struct file *file) */ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) + unsigned char *kbuf, size_t nr, + void **cookie, unsigned long offset) { struct n_tty_data *ldata = tty->disc_data; - unsigned char __user *b = buf; + unsigned char *kb = kbuf; DEFINE_WAIT_FUNC(wait, woken_wake_function); int c; int minimum, time; @@ -2179,17 +2173,13 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, /* First test for status change. */ if (packet && tty->link->ctrl_status) { unsigned char cs; - if (b != buf) + 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); - if (put_user(cs, b)) { - retval = -EFAULT; - break; - } - b++; + *kb++ = cs; nr--; break; } @@ -2232,24 +2222,20 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, } if (ldata->icanon && !L_EXTPROC(tty)) { - retval = canon_copy_from_read_buf(tty, &b, &nr); + retval = canon_copy_from_read_buf(tty, &kb, &nr); if (retval) break; } else { int uncopied; /* Deal with packet mode. */ - if (packet && b == buf) { - if (put_user(TIOCPKT_DATA, b)) { - retval = -EFAULT; - break; - } - b++; + if (packet && kb == kbuf) { + *kb++ = TIOCPKT_DATA; nr--; } - uncopied = copy_from_read_buf(tty, &b, &nr); - uncopied += copy_from_read_buf(tty, &b, &nr); + uncopied = copy_from_read_buf(tty, &kb, &nr); + uncopied += copy_from_read_buf(tty, &kb, &nr); if (uncopied) { retval = -EFAULT; break; @@ -2258,7 +2244,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, n_tty_check_unthrottle(tty); - if (b - buf >= minimum) + if (kb - kbuf >= minimum) break; if (time) timeout = time; @@ -2270,8 +2256,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, remove_wait_queue(&tty->read_wait, &wait); mutex_unlock(&ldata->atomic_read_lock); - if (b - buf) - retval = b - buf; + if (kb - kbuf) + retval = kb - kbuf; return retval; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 338bc4ef5549..a34f8bcf875e 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -833,6 +833,65 @@ static void tty_update_time(struct timespec64 *time) time->tv_sec = sec; } +/* + * Iterate on the ldisc ->read() function until we've gotten all + * the data the ldisc has for us. + * + * The "cookie" is something that the ldisc read function can fill + * in to let us know that there is more data to be had. + * + * We promise to continue to call the ldisc until it stops returning + * data or clears the cookie. The cookie may be something that the + * ldisc maintains state for and needs to free. + */ +static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, struct file *file, + char __user *buf, size_t count) +{ + int retval = 0; + void *cookie = NULL; + unsigned long offset = 0; + char kernel_buf[64]; + + do { + int size, uncopied; + + size = count > sizeof(kernel_buf) ? sizeof(kernel_buf) : count; + size = ld->ops->read(tty, file, kernel_buf, size, &cookie, offset); + if (!size) + break; + + /* + * A ldisc read error return will override any previously copied + * data (eg -EOVERFLOW from HDLC) + */ + if (size < 0) { + memzero_explicit(kernel_buf, sizeof(kernel_buf)); + return size; + } + + uncopied = copy_to_user(buf+offset, kernel_buf, size); + size -= uncopied; + offset += size; + count -= size; + + /* + * If the user copy failed, we still need to do another ->read() + * call if we had a cookie to let the ldisc clear up. + * + * But make sure size is zeroed. + */ + if (unlikely(uncopied)) { + count = 0; + retval = -EFAULT; + } + } while (cookie); + + /* We always clear tty buffer in case they contained passwords */ + memzero_explicit(kernel_buf, sizeof(kernel_buf)); + return offset ? offset : retval; +} + + /** * tty_read - read method for tty device files * @file: pointer to tty file @@ -866,10 +925,9 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, ld = tty_ldisc_ref_wait(tty); if (!ld) return hung_up_tty_read(file, buf, count, ppos); + i = -EIO; if (ld->ops->read) - i = ld->ops->read(tty, file, buf, count); - else - i = -EIO; + i = iterate_tty_read(ld, tty, file, buf, count); tty_ldisc_deref(ld); if (i > 0) diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index b1e6043e9917..572a07976116 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -185,7 +185,8 @@ struct tty_ldisc_ops { void (*close)(struct tty_struct *); void (*flush_buffer)(struct tty_struct *tty); ssize_t (*read)(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr); + unsigned char *buf, size_t nr, + void **cookie, unsigned long offset); ssize_t (*write)(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr); int (*ioctl)(struct tty_struct *tty, struct file *file, diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index 11b554ce07ff..1204c438e87d 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -292,7 +292,8 @@ static int nci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, /* We don't provide read/write/poll interface for user space. */ static ssize_t nci_uart_tty_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) + unsigned char *buf, size_t nr, + void **cookie, unsigned long offset) { return 0; } -- cgit v1.2.3-59-g8ed1b From e9103f47bf1a1bbf0ab0ea90eda3e208653a5f57 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 25 Jan 2021 17:02:38 +0200 Subject: serial: ifx6x60: Remove driver for deprecated platform Intel Moorestown and Medfield are quite old Intel Atom based 32-bit platforms, which were in limited use in some Android phones, tablets and consumer electronics more than eight years ago. There are no bugs or problems ever reported outside from Intel for breaking any of that platforms for years. It seems no real users exists who run more or less fresh kernel on it. The commit 05f4434bc130 ("ASoC: Intel: remove mfld_machine") also in align with this theory. Due to above and to reduce a burden of supporting outdated drivers we remove the support of outdated platforms completely. Signed-off-by: Andy Shevchenko Acked-by: Linus Walleij Link: https://lore.kernel.org/r/20210125150238.16980-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 7 - drivers/tty/serial/Makefile | 1 - drivers/tty/serial/ifx6x60.c | 1387 ----------------------------------------- drivers/tty/serial/ifx6x60.h | 118 ---- include/linux/spi/ifx_modem.h | 15 - 5 files changed, 1528 deletions(-) delete mode 100644 drivers/tty/serial/ifx6x60.c delete mode 100644 drivers/tty/serial/ifx6x60.h delete mode 100644 include/linux/spi/ifx_modem.h (limited to 'include/linux') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 22e86ba4f827..0c4cd4a348f4 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1182,13 +1182,6 @@ config SERIAL_ALTERA_UART_CONSOLE help Enable a Altera UART port to be the system console. -config SERIAL_IFX6X60 - tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)" - depends on GPIOLIB || COMPILE_TEST - depends on SPI && HAS_DMA - help - Support for the IFX6x60 modem devices on Intel MID platforms. - config SERIAL_PCH_UART tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART" depends on PCI && (X86_32 || MIPS || COMPILE_TEST) diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 931dc1d6885e..7da0856cd198 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -64,7 +64,6 @@ obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o -obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o diff --git a/drivers/tty/serial/ifx6x60.c b/drivers/tty/serial/ifx6x60.c deleted file mode 100644 index d4ef88ee22d0..000000000000 --- a/drivers/tty/serial/ifx6x60.c +++ /dev/null @@ -1,1387 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/**************************************************************************** - * - * Driver for the IFX 6x60 spi modem. - * - * Copyright (C) 2008 Option International - * Copyright (C) 2008 Filip Aben - * Denis Joseph Barrow - * Jan Dumon - * - * Copyright (C) 2009, 2010 Intel Corp - * Russ Gorby - * - * Driver modified by Intel from Option gtm501l_spi.c - * - * Notes - * o The driver currently assumes a single device only. If you need to - * change this then look for saved_ifx_dev and add a device lookup - * o The driver is intended to be big-endian safe but has never been - * tested that way (no suitable hardware). There are a couple of FIXME - * notes by areas that may need addressing - * o Some of the GPIO naming/setup assumptions may need revisiting if - * you need to use this driver for another platform. - * - *****************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ifx6x60.h" - -#define IFX_SPI_MORE_MASK 0x10 -#define IFX_SPI_MORE_BIT 4 /* bit position in u8 */ -#define IFX_SPI_CTS_BIT 6 /* bit position in u8 */ -#define IFX_SPI_MODE SPI_MODE_1 -#define IFX_SPI_TTY_ID 0 -#define IFX_SPI_TIMEOUT_SEC 2 -#define IFX_SPI_HEADER_0 (-1) -#define IFX_SPI_HEADER_F (-2) - -#define PO_POST_DELAY 200 - -/* forward reference */ -static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev); -static int ifx_modem_reboot_callback(struct notifier_block *nfb, - unsigned long event, void *data); -static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev); - -/* local variables */ -static int spi_bpw = 16; /* 8, 16 or 32 bit word length */ -static struct tty_driver *tty_drv; -static struct ifx_spi_device *saved_ifx_dev; -static struct lock_class_key ifx_spi_key; - -static struct notifier_block ifx_modem_reboot_notifier_block = { - .notifier_call = ifx_modem_reboot_callback, -}; - -static int ifx_modem_power_off(struct ifx_spi_device *ifx_dev) -{ - gpiod_set_value(ifx_dev->gpio.pmu_reset, 1); - msleep(PO_POST_DELAY); - - return 0; -} - -static int ifx_modem_reboot_callback(struct notifier_block *nfb, - unsigned long event, void *data) -{ - if (saved_ifx_dev) - ifx_modem_power_off(saved_ifx_dev); - else - pr_warn("no ifx modem active;\n"); - - return NOTIFY_OK; -} - -/* GPIO/GPE settings */ - -/** - * mrdy_set_high - set MRDY GPIO - * @ifx: device we are controlling - * - */ -static inline void mrdy_set_high(struct ifx_spi_device *ifx) -{ - gpiod_set_value(ifx->gpio.mrdy, 1); -} - -/** - * mrdy_set_low - clear MRDY GPIO - * @ifx: device we are controlling - * - */ -static inline void mrdy_set_low(struct ifx_spi_device *ifx) -{ - gpiod_set_value(ifx->gpio.mrdy, 0); -} - -/** - * ifx_spi_power_state_set - * @ifx_dev: our SPI device - * @val: bits to set - * - * Set bit in power status and signal power system if status becomes non-0 - */ -static void -ifx_spi_power_state_set(struct ifx_spi_device *ifx_dev, unsigned char val) -{ - unsigned long flags; - - spin_lock_irqsave(&ifx_dev->power_lock, flags); - - /* - * if power status is already non-0, just update, else - * tell power system - */ - if (!ifx_dev->power_status) - pm_runtime_get(&ifx_dev->spi_dev->dev); - ifx_dev->power_status |= val; - - spin_unlock_irqrestore(&ifx_dev->power_lock, flags); -} - -/** - * ifx_spi_power_state_clear - clear power bit - * @ifx_dev: our SPI device - * @val: bits to clear - * - * clear bit in power status and signal power system if status becomes 0 - */ -static void -ifx_spi_power_state_clear(struct ifx_spi_device *ifx_dev, unsigned char val) -{ - unsigned long flags; - - spin_lock_irqsave(&ifx_dev->power_lock, flags); - - if (ifx_dev->power_status) { - ifx_dev->power_status &= ~val; - if (!ifx_dev->power_status) - pm_runtime_put(&ifx_dev->spi_dev->dev); - } - - spin_unlock_irqrestore(&ifx_dev->power_lock, flags); -} - -/** - * swap_buf_8 - * @buf: our buffer - * @len : number of bytes (not words) in the buffer - * @end: end of buffer - * - * Swap the contents of a buffer into big endian format - */ -static inline void swap_buf_8(unsigned char *buf, int len, void *end) -{ - /* don't swap buffer if SPI word width is 8 bits */ - return; -} - -/** - * swap_buf_16 - * @buf: our buffer - * @len : number of bytes (not words) in the buffer - * @end: end of buffer - * - * Swap the contents of a buffer into big endian format - */ -static inline void swap_buf_16(unsigned char *buf, int len, void *end) -{ - int n; - - u16 *buf_16 = (u16 *)buf; - len = ((len + 1) >> 1); - if ((void *)&buf_16[len] > end) { - pr_err("swap_buf_16: swap exceeds boundary (%p > %p)!", - &buf_16[len], end); - return; - } - for (n = 0; n < len; n++) { - *buf_16 = cpu_to_be16(*buf_16); - buf_16++; - } -} - -/** - * swap_buf_32 - * @buf: our buffer - * @len : number of bytes (not words) in the buffer - * @end: end of buffer - * - * Swap the contents of a buffer into big endian format - */ -static inline void swap_buf_32(unsigned char *buf, int len, void *end) -{ - int n; - - u32 *buf_32 = (u32 *)buf; - len = (len + 3) >> 2; - - if ((void *)&buf_32[len] > end) { - pr_err("swap_buf_32: swap exceeds boundary (%p > %p)!\n", - &buf_32[len], end); - return; - } - for (n = 0; n < len; n++) { - *buf_32 = cpu_to_be32(*buf_32); - buf_32++; - } -} - -/** - * mrdy_assert - assert MRDY line - * @ifx_dev: our SPI device - * - * Assert mrdy and set timer to wait for SRDY interrupt, if SRDY is low - * now. - * - * FIXME: Can SRDY even go high as we are running this code ? - */ -static void mrdy_assert(struct ifx_spi_device *ifx_dev) -{ - int val = gpiod_get_value(ifx_dev->gpio.srdy); - if (!val) { - if (!test_and_set_bit(IFX_SPI_STATE_TIMER_PENDING, - &ifx_dev->flags)) { - mod_timer(&ifx_dev->spi_timer,jiffies + IFX_SPI_TIMEOUT_SEC*HZ); - - } - } - ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_DATA_PENDING); - mrdy_set_high(ifx_dev); -} - -/** - * ifx_spi_timeout - SPI timeout - * @t: timer in our SPI device - * - * The SPI has timed out: hang up the tty. Users will then see a hangup - * and error events. - */ -static void ifx_spi_timeout(struct timer_list *t) -{ - struct ifx_spi_device *ifx_dev = from_timer(ifx_dev, t, spi_timer); - - dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***"); - tty_port_tty_hangup(&ifx_dev->tty_port, false); - mrdy_set_low(ifx_dev); - clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); -} - -/* char/tty operations */ - -/** - * ifx_spi_tiocmget - get modem lines - * @tty: our tty device - * - * Map the signal state into Linux modem flags and report the value - * in Linux terms - */ -static int ifx_spi_tiocmget(struct tty_struct *tty) -{ - unsigned int value; - struct ifx_spi_device *ifx_dev = tty->driver_data; - - value = - (test_bit(IFX_SPI_RTS, &ifx_dev->signal_state) ? TIOCM_RTS : 0) | - (test_bit(IFX_SPI_DTR, &ifx_dev->signal_state) ? TIOCM_DTR : 0) | - (test_bit(IFX_SPI_CTS, &ifx_dev->signal_state) ? TIOCM_CTS : 0) | - (test_bit(IFX_SPI_DSR, &ifx_dev->signal_state) ? TIOCM_DSR : 0) | - (test_bit(IFX_SPI_DCD, &ifx_dev->signal_state) ? TIOCM_CAR : 0) | - (test_bit(IFX_SPI_RI, &ifx_dev->signal_state) ? TIOCM_RNG : 0); - return value; -} - -/** - * ifx_spi_tiocmset - set modem bits - * @tty: the tty structure - * @set: bits to set - * @clear: bits to clear - * - * The IFX6x60 only supports DTR and RTS. Set them accordingly - * and flag that an update to the modem is needed. - * - * FIXME: do we need to kick the tranfers when we do this ? - */ -static int ifx_spi_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - - if (set & TIOCM_RTS) - set_bit(IFX_SPI_RTS, &ifx_dev->signal_state); - if (set & TIOCM_DTR) - set_bit(IFX_SPI_DTR, &ifx_dev->signal_state); - if (clear & TIOCM_RTS) - clear_bit(IFX_SPI_RTS, &ifx_dev->signal_state); - if (clear & TIOCM_DTR) - clear_bit(IFX_SPI_DTR, &ifx_dev->signal_state); - - set_bit(IFX_SPI_UPDATE, &ifx_dev->signal_state); - return 0; -} - -/** - * ifx_spi_open - called on tty open - * @tty: our tty device - * @filp: file handle being associated with the tty - * - * Open the tty interface. We let the tty_port layer do all the work - * for us. - * - * FIXME: Remove single device assumption and saved_ifx_dev - */ -static int ifx_spi_open(struct tty_struct *tty, struct file *filp) -{ - return tty_port_open(&saved_ifx_dev->tty_port, tty, filp); -} - -/** - * ifx_spi_close - called when our tty closes - * @tty: the tty being closed - * @filp: the file handle being closed - * - * Perform the close of the tty. We use the tty_port layer to do all - * our hard work. - */ -static void ifx_spi_close(struct tty_struct *tty, struct file *filp) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - tty_port_close(&ifx_dev->tty_port, tty, filp); - /* FIXME: should we do an ifx_spi_reset here ? */ -} - -/** - * ifx_decode_spi_header - decode received header - * @buffer: the received data - * @length: decoded length - * @more: decoded more flag - * @received_cts: status of cts we received - * - * Note how received_cts is handled -- if header is all F it is left - * the same as it was, if header is all 0 it is set to 0 otherwise it is - * taken from the incoming header. - * - * FIXME: endianness - */ -static int ifx_spi_decode_spi_header(unsigned char *buffer, int *length, - unsigned char *more, unsigned char *received_cts) -{ - u16 h1; - u16 h2; - u16 *in_buffer = (u16 *)buffer; - - h1 = *in_buffer; - h2 = *(in_buffer+1); - - if (h1 == 0 && h2 == 0) { - *received_cts = 0; - *more = 0; - return IFX_SPI_HEADER_0; - } else if (h1 == 0xffff && h2 == 0xffff) { - *more = 0; - /* spi_slave_cts remains as it was */ - return IFX_SPI_HEADER_F; - } - - *length = h1 & 0xfff; /* upper bits of byte are flags */ - *more = (buffer[1] >> IFX_SPI_MORE_BIT) & 1; - *received_cts = (buffer[3] >> IFX_SPI_CTS_BIT) & 1; - return 0; -} - -/** - * ifx_setup_spi_header - set header fields - * @txbuffer: pointer to start of SPI buffer - * @tx_count: bytes - * @more: indicate if more to follow - * - * Format up an SPI header for a transfer - * - * FIXME: endianness? - */ -static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count, - unsigned char more) -{ - *(u16 *)(txbuffer) = tx_count; - *(u16 *)(txbuffer+2) = IFX_SPI_PAYLOAD_SIZE; - txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK; -} - -/** - * ifx_spi_prepare_tx_buffer - prepare transmit frame - * @ifx_dev: our SPI device - * - * The transmit buffr needs a header and various other bits of - * information followed by as much data as we can pull from the FIFO - * and transfer. This function formats up a suitable buffer in the - * ifx_dev->tx_buffer - * - * FIXME: performance - should we wake the tty when the queue is half - * empty ? - */ -static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev) -{ - int temp_count; - int queue_length; - int tx_count; - unsigned char *tx_buffer; - - tx_buffer = ifx_dev->tx_buffer; - - /* make room for required SPI header */ - tx_buffer += IFX_SPI_HEADER_OVERHEAD; - tx_count = IFX_SPI_HEADER_OVERHEAD; - - /* clear to signal no more data if this turns out to be the - * last buffer sent in a sequence */ - ifx_dev->spi_more = 0; - - /* if modem cts is set, just send empty buffer */ - if (!ifx_dev->spi_slave_cts) { - /* see if there's tx data */ - queue_length = kfifo_len(&ifx_dev->tx_fifo); - if (queue_length != 0) { - /* data to mux -- see if there's room for it */ - temp_count = min(queue_length, IFX_SPI_PAYLOAD_SIZE); - temp_count = kfifo_out_locked(&ifx_dev->tx_fifo, - tx_buffer, temp_count, - &ifx_dev->fifo_lock); - - /* update buffer pointer and data count in message */ - tx_buffer += temp_count; - tx_count += temp_count; - if (temp_count == queue_length) - /* poke port to get more data */ - tty_port_tty_wakeup(&ifx_dev->tty_port); - else /* more data in port, use next SPI message */ - ifx_dev->spi_more = 1; - } - } - /* have data and info for header -- set up SPI header in buffer */ - /* spi header needs payload size, not entire buffer size */ - ifx_spi_setup_spi_header(ifx_dev->tx_buffer, - tx_count-IFX_SPI_HEADER_OVERHEAD, - ifx_dev->spi_more); - /* swap actual data in the buffer */ - ifx_dev->swap_buf((ifx_dev->tx_buffer), tx_count, - &ifx_dev->tx_buffer[IFX_SPI_TRANSFER_SIZE]); - return tx_count; -} - -/** - * ifx_spi_write - line discipline write - * @tty: our tty device - * @buf: pointer to buffer to write (kernel space) - * @count: size of buffer - * - * Write the characters we have been given into the FIFO. If the device - * is not active then activate it, when the SRDY line is asserted back - * this will commence I/O - */ -static int ifx_spi_write(struct tty_struct *tty, const unsigned char *buf, - int count) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - unsigned char *tmp_buf = (unsigned char *)buf; - unsigned long flags; - bool is_fifo_empty; - int tx_count; - - spin_lock_irqsave(&ifx_dev->fifo_lock, flags); - is_fifo_empty = kfifo_is_empty(&ifx_dev->tx_fifo); - tx_count = kfifo_in(&ifx_dev->tx_fifo, tmp_buf, count); - spin_unlock_irqrestore(&ifx_dev->fifo_lock, flags); - if (is_fifo_empty) - mrdy_assert(ifx_dev); - - return tx_count; -} - -/** - * ifx_spi_chars_in_buffer - line discipline helper - * @tty: our tty device - * - * Report how much data we can accept before we drop bytes. As we use - * a simple FIFO this is nice and easy. - */ -static int ifx_spi_write_room(struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - return IFX_SPI_FIFO_SIZE - kfifo_len(&ifx_dev->tx_fifo); -} - -/** - * ifx_spi_chars_in_buffer - line discipline helper - * @tty: our tty device - * - * Report how many characters we have buffered. In our case this is the - * number of bytes sitting in our transmit FIFO. - */ -static int ifx_spi_chars_in_buffer(struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - return kfifo_len(&ifx_dev->tx_fifo); -} - -/** - * ifx_port_hangup - * @tty: our tty - * - * tty port hang up. Called when tty_hangup processing is invoked either - * by loss of carrier, or by software (eg vhangup). Serialized against - * activate/shutdown by the tty layer. - */ -static void ifx_spi_hangup(struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = tty->driver_data; - tty_port_hangup(&ifx_dev->tty_port); -} - -/** - * ifx_port_activate - * @port: our tty port - * @tty: our tty device - * - * tty port activate method - called for first open. Serialized - * with hangup and shutdown by the tty layer. - */ -static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty) -{ - struct ifx_spi_device *ifx_dev = - container_of(port, struct ifx_spi_device, tty_port); - - /* clear any old data; can't do this in 'close' */ - kfifo_reset(&ifx_dev->tx_fifo); - - /* clear any flag which may be set in port shutdown procedure */ - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags); - clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags); - - /* put port data into this tty */ - tty->driver_data = ifx_dev; - - /* set flag to allows data transfer */ - set_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags); - - return 0; -} - -/** - * ifx_port_shutdown - * @port: our tty port - * - * tty port shutdown method - called for last port close. Serialized - * with hangup and activate by the tty layer. - */ -static void ifx_port_shutdown(struct tty_port *port) -{ - struct ifx_spi_device *ifx_dev = - container_of(port, struct ifx_spi_device, tty_port); - - clear_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags); - mrdy_set_low(ifx_dev); - del_timer(&ifx_dev->spi_timer); - clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); - tasklet_kill(&ifx_dev->io_work_tasklet); -} - -static const struct tty_port_operations ifx_tty_port_ops = { - .activate = ifx_port_activate, - .shutdown = ifx_port_shutdown, -}; - -static const struct tty_operations ifx_spi_serial_ops = { - .open = ifx_spi_open, - .close = ifx_spi_close, - .write = ifx_spi_write, - .hangup = ifx_spi_hangup, - .write_room = ifx_spi_write_room, - .chars_in_buffer = ifx_spi_chars_in_buffer, - .tiocmget = ifx_spi_tiocmget, - .tiocmset = ifx_spi_tiocmset, -}; - -/** - * ifx_spi_insert_fip_string - queue received data - * @ifx_dev: our SPI device - * @chars: buffer we have received - * @size: number of chars reeived - * - * Queue bytes to the tty assuming the tty side is currently open. If - * not the discard the data. - */ -static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev, - unsigned char *chars, size_t size) -{ - tty_insert_flip_string(&ifx_dev->tty_port, chars, size); - tty_flip_buffer_push(&ifx_dev->tty_port); -} - -/** - * ifx_spi_complete - SPI transfer completed - * @ctx: our SPI device - * - * An SPI transfer has completed. Process any received data and kick off - * any further transmits we can commence. - */ -static void ifx_spi_complete(void *ctx) -{ - struct ifx_spi_device *ifx_dev = ctx; - int length; - int actual_length; - unsigned char more = 0; - unsigned char cts; - int local_write_pending = 0; - int queue_length; - int srdy; - int decode_result; - - mrdy_set_low(ifx_dev); - - if (!ifx_dev->spi_msg.status) { - /* check header validity, get comm flags */ - ifx_dev->swap_buf(ifx_dev->rx_buffer, IFX_SPI_HEADER_OVERHEAD, - &ifx_dev->rx_buffer[IFX_SPI_HEADER_OVERHEAD]); - decode_result = ifx_spi_decode_spi_header(ifx_dev->rx_buffer, - &length, &more, &cts); - if (decode_result == IFX_SPI_HEADER_0) { - dev_dbg(&ifx_dev->spi_dev->dev, - "ignore input: invalid header 0"); - ifx_dev->spi_slave_cts = 0; - goto complete_exit; - } else if (decode_result == IFX_SPI_HEADER_F) { - dev_dbg(&ifx_dev->spi_dev->dev, - "ignore input: invalid header F"); - goto complete_exit; - } - - ifx_dev->spi_slave_cts = cts; - - actual_length = min((unsigned int)length, - ifx_dev->spi_msg.actual_length); - ifx_dev->swap_buf( - (ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD), - actual_length, - &ifx_dev->rx_buffer[IFX_SPI_TRANSFER_SIZE]); - ifx_spi_insert_flip_string( - ifx_dev, - ifx_dev->rx_buffer + IFX_SPI_HEADER_OVERHEAD, - (size_t)actual_length); - } else { - more = 0; - dev_dbg(&ifx_dev->spi_dev->dev, "SPI transfer error %d", - ifx_dev->spi_msg.status); - } - -complete_exit: - if (ifx_dev->write_pending) { - ifx_dev->write_pending = 0; - local_write_pending = 1; - } - - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &(ifx_dev->flags)); - - queue_length = kfifo_len(&ifx_dev->tx_fifo); - srdy = gpiod_get_value(ifx_dev->gpio.srdy); - if (!srdy) - ifx_spi_power_state_clear(ifx_dev, IFX_SPI_POWER_SRDY); - - /* schedule output if there is more to do */ - if (test_and_clear_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags)) - tasklet_schedule(&ifx_dev->io_work_tasklet); - else { - if (more || ifx_dev->spi_more || queue_length > 0 || - local_write_pending) { - if (ifx_dev->spi_slave_cts) { - if (more) - mrdy_assert(ifx_dev); - } else - mrdy_assert(ifx_dev); - } else { - /* - * poke line discipline driver if any for more data - * may or may not get more data to write - * for now, say not busy - */ - ifx_spi_power_state_clear(ifx_dev, - IFX_SPI_POWER_DATA_PENDING); - tty_port_tty_wakeup(&ifx_dev->tty_port); - } - } -} - -/** - * ifx_spio_io - I/O tasklet - * @t: tasklet construct used to fetch the SPI device - * - * Queue data for transmission if possible and then kick off the - * transfer. - */ -static void ifx_spi_io(struct tasklet_struct *t) -{ - int retval; - struct ifx_spi_device *ifx_dev = from_tasklet(ifx_dev, t, - io_work_tasklet); - - if (!test_and_set_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags) && - test_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags)) { - if (ifx_dev->gpio.unack_srdy_int_nb > 0) - ifx_dev->gpio.unack_srdy_int_nb--; - - ifx_spi_prepare_tx_buffer(ifx_dev); - - spi_message_init(&ifx_dev->spi_msg); - INIT_LIST_HEAD(&ifx_dev->spi_msg.queue); - - ifx_dev->spi_msg.context = ifx_dev; - ifx_dev->spi_msg.complete = ifx_spi_complete; - - /* set up our spi transfer */ - /* note len is BYTES, not transfers */ - ifx_dev->spi_xfer.len = IFX_SPI_TRANSFER_SIZE; - ifx_dev->spi_xfer.cs_change = 0; - ifx_dev->spi_xfer.speed_hz = ifx_dev->spi_dev->max_speed_hz; - /* ifx_dev->spi_xfer.speed_hz = 390625; */ - ifx_dev->spi_xfer.bits_per_word = - ifx_dev->spi_dev->bits_per_word; - - ifx_dev->spi_xfer.tx_buf = ifx_dev->tx_buffer; - ifx_dev->spi_xfer.rx_buf = ifx_dev->rx_buffer; - - /* - * setup dma pointers - */ - if (ifx_dev->use_dma) { - ifx_dev->spi_msg.is_dma_mapped = 1; - ifx_dev->tx_dma = ifx_dev->tx_bus; - ifx_dev->rx_dma = ifx_dev->rx_bus; - ifx_dev->spi_xfer.tx_dma = ifx_dev->tx_dma; - ifx_dev->spi_xfer.rx_dma = ifx_dev->rx_dma; - } else { - ifx_dev->spi_msg.is_dma_mapped = 0; - ifx_dev->tx_dma = (dma_addr_t)0; - ifx_dev->rx_dma = (dma_addr_t)0; - ifx_dev->spi_xfer.tx_dma = (dma_addr_t)0; - ifx_dev->spi_xfer.rx_dma = (dma_addr_t)0; - } - - spi_message_add_tail(&ifx_dev->spi_xfer, &ifx_dev->spi_msg); - - /* Assert MRDY. This may have already been done by the write - * routine. - */ - mrdy_assert(ifx_dev); - - retval = spi_async(ifx_dev->spi_dev, &ifx_dev->spi_msg); - if (retval) { - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, - &ifx_dev->flags); - tasklet_schedule(&ifx_dev->io_work_tasklet); - return; - } - } else - ifx_dev->write_pending = 1; -} - -/** - * ifx_spi_free_port - free up the tty side - * @ifx_dev: IFX device going away - * - * Unregister and free up a port when the device goes away - */ -static void ifx_spi_free_port(struct ifx_spi_device *ifx_dev) -{ - if (ifx_dev->tty_dev) - tty_unregister_device(tty_drv, ifx_dev->minor); - tty_port_destroy(&ifx_dev->tty_port); - kfifo_free(&ifx_dev->tx_fifo); -} - -/** - * ifx_spi_create_port - create a new port - * @ifx_dev: our spi device - * - * Allocate and initialise the tty port that goes with this interface - * and add it to the tty layer so that it can be opened. - */ -static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev) -{ - int ret = 0; - struct tty_port *pport = &ifx_dev->tty_port; - - spin_lock_init(&ifx_dev->fifo_lock); - lockdep_set_class_and_subclass(&ifx_dev->fifo_lock, - &ifx_spi_key, 0); - - if (kfifo_alloc(&ifx_dev->tx_fifo, IFX_SPI_FIFO_SIZE, GFP_KERNEL)) { - ret = -ENOMEM; - goto error_ret; - } - - tty_port_init(pport); - pport->ops = &ifx_tty_port_ops; - ifx_dev->minor = IFX_SPI_TTY_ID; - ifx_dev->tty_dev = tty_port_register_device(pport, tty_drv, - ifx_dev->minor, &ifx_dev->spi_dev->dev); - if (IS_ERR(ifx_dev->tty_dev)) { - dev_dbg(&ifx_dev->spi_dev->dev, - "%s: registering tty device failed", __func__); - ret = PTR_ERR(ifx_dev->tty_dev); - goto error_port; - } - return 0; - -error_port: - tty_port_destroy(pport); -error_ret: - ifx_spi_free_port(ifx_dev); - return ret; -} - -/** - * ifx_spi_handle_srdy - handle SRDY - * @ifx_dev: device asserting SRDY - * - * Check our device state and see what we need to kick off when SRDY - * is asserted. This usually means killing the timer and firing off the - * I/O processing. - */ -static void ifx_spi_handle_srdy(struct ifx_spi_device *ifx_dev) -{ - if (test_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags)) { - del_timer(&ifx_dev->spi_timer); - clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags); - } - - ifx_spi_power_state_set(ifx_dev, IFX_SPI_POWER_SRDY); - - if (!test_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags)) - tasklet_schedule(&ifx_dev->io_work_tasklet); - else - set_bit(IFX_SPI_STATE_IO_READY, &ifx_dev->flags); -} - -/** - * ifx_spi_srdy_interrupt - SRDY asserted - * @irq: our IRQ number - * @dev: our ifx device - * - * The modem asserted SRDY. Handle the srdy event - */ -static irqreturn_t ifx_spi_srdy_interrupt(int irq, void *dev) -{ - struct ifx_spi_device *ifx_dev = dev; - ifx_dev->gpio.unack_srdy_int_nb++; - ifx_spi_handle_srdy(ifx_dev); - return IRQ_HANDLED; -} - -/** - * ifx_spi_reset_interrupt - Modem has changed reset state - * @irq: interrupt number - * @dev: our device pointer - * - * The modem has either entered or left reset state. Check the GPIO - * line to see which. - * - * FIXME: review locking on MR_INPROGRESS versus - * parallel unsolicited reset/solicited reset - */ -static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev) -{ - struct ifx_spi_device *ifx_dev = dev; - int val = gpiod_get_value(ifx_dev->gpio.reset_out); - int solreset = test_bit(MR_START, &ifx_dev->mdm_reset_state); - - if (val == 0) { - /* entered reset */ - set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state); - if (!solreset) { - /* unsolicited reset */ - tty_port_tty_hangup(&ifx_dev->tty_port, false); - } - } else { - /* exited reset */ - clear_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state); - if (solreset) { - set_bit(MR_COMPLETE, &ifx_dev->mdm_reset_state); - wake_up(&ifx_dev->mdm_reset_wait); - } - } - return IRQ_HANDLED; -} - -/** - * ifx_spi_free_device - free device - * @ifx_dev: device to free - * - * Free the IFX device - */ -static void ifx_spi_free_device(struct ifx_spi_device *ifx_dev) -{ - ifx_spi_free_port(ifx_dev); - dma_free_coherent(&ifx_dev->spi_dev->dev, - IFX_SPI_TRANSFER_SIZE, - ifx_dev->tx_buffer, - ifx_dev->tx_bus); - dma_free_coherent(&ifx_dev->spi_dev->dev, - IFX_SPI_TRANSFER_SIZE, - ifx_dev->rx_buffer, - ifx_dev->rx_bus); -} - -/** - * ifx_spi_reset - reset modem - * @ifx_dev: modem to reset - * - * Perform a reset on the modem - */ -static int ifx_spi_reset(struct ifx_spi_device *ifx_dev) -{ - int ret; - /* - * set up modem power, reset - * - * delays are required on some platforms for the modem - * to reset properly - */ - set_bit(MR_START, &ifx_dev->mdm_reset_state); - gpiod_set_value(ifx_dev->gpio.po, 0); - gpiod_set_value(ifx_dev->gpio.reset, 0); - msleep(25); - gpiod_set_value(ifx_dev->gpio.reset, 1); - msleep(1); - gpiod_set_value(ifx_dev->gpio.po, 1); - msleep(1); - gpiod_set_value(ifx_dev->gpio.po, 0); - ret = wait_event_timeout(ifx_dev->mdm_reset_wait, - test_bit(MR_COMPLETE, - &ifx_dev->mdm_reset_state), - IFX_RESET_TIMEOUT); - if (!ret) - dev_warn(&ifx_dev->spi_dev->dev, "Modem reset timeout: (state:%lx)", - ifx_dev->mdm_reset_state); - - ifx_dev->mdm_reset_state = 0; - return ret; -} - -/** - * ifx_spi_spi_probe - probe callback - * @spi: our possible matching SPI device - * - * Probe for a 6x60 modem on SPI bus. Perform any needed device and - * GPIO setup. - * - * FIXME: - * - Support for multiple devices - * - Split out MID specific GPIO handling eventually - */ - -static int ifx_spi_spi_probe(struct spi_device *spi) -{ - int ret; - int srdy; - struct ifx_modem_platform_data *pl_data; - struct ifx_spi_device *ifx_dev; - struct device *dev = &spi->dev; - - if (saved_ifx_dev) { - dev_dbg(dev, "ignoring subsequent detection"); - return -ENODEV; - } - - pl_data = dev_get_platdata(dev); - if (!pl_data) { - dev_err(dev, "missing platform data!"); - return -ENODEV; - } - - /* initialize structure to hold our device variables */ - ifx_dev = kzalloc(sizeof(struct ifx_spi_device), GFP_KERNEL); - if (!ifx_dev) { - dev_err(dev, "spi device allocation failed"); - return -ENOMEM; - } - saved_ifx_dev = ifx_dev; - ifx_dev->spi_dev = spi; - clear_bit(IFX_SPI_STATE_IO_IN_PROGRESS, &ifx_dev->flags); - spin_lock_init(&ifx_dev->write_lock); - spin_lock_init(&ifx_dev->power_lock); - ifx_dev->power_status = 0; - timer_setup(&ifx_dev->spi_timer, ifx_spi_timeout, 0); - ifx_dev->modem = pl_data->modem_type; - ifx_dev->use_dma = pl_data->use_dma; - ifx_dev->max_hz = pl_data->max_hz; - /* initialize spi mode, etc */ - spi->max_speed_hz = ifx_dev->max_hz; - spi->mode = IFX_SPI_MODE | (SPI_LOOP & spi->mode); - spi->bits_per_word = spi_bpw; - ret = spi_setup(spi); - if (ret) { - dev_err(dev, "SPI setup wasn't successful %d", ret); - kfree(ifx_dev); - return -ENODEV; - } - - /* init swap_buf function according to word width configuration */ - if (spi->bits_per_word == 32) - ifx_dev->swap_buf = swap_buf_32; - else if (spi->bits_per_word == 16) - ifx_dev->swap_buf = swap_buf_16; - else - ifx_dev->swap_buf = swap_buf_8; - - /* ensure SPI protocol flags are initialized to enable transfer */ - ifx_dev->spi_more = 0; - ifx_dev->spi_slave_cts = 0; - - /*initialize transfer and dma buffers */ - ifx_dev->tx_buffer = dma_alloc_coherent(ifx_dev->spi_dev->dev.parent, - IFX_SPI_TRANSFER_SIZE, - &ifx_dev->tx_bus, - GFP_KERNEL); - if (!ifx_dev->tx_buffer) { - dev_err(dev, "DMA-TX buffer allocation failed"); - ret = -ENOMEM; - goto error_ret; - } - ifx_dev->rx_buffer = dma_alloc_coherent(ifx_dev->spi_dev->dev.parent, - IFX_SPI_TRANSFER_SIZE, - &ifx_dev->rx_bus, - GFP_KERNEL); - if (!ifx_dev->rx_buffer) { - dev_err(dev, "DMA-RX buffer allocation failed"); - ret = -ENOMEM; - goto error_ret; - } - - /* initialize waitq for modem reset */ - init_waitqueue_head(&ifx_dev->mdm_reset_wait); - - spi_set_drvdata(spi, ifx_dev); - tasklet_setup(&ifx_dev->io_work_tasklet, ifx_spi_io); - - set_bit(IFX_SPI_STATE_PRESENT, &ifx_dev->flags); - - /* create our tty port */ - ret = ifx_spi_create_port(ifx_dev); - if (ret != 0) { - dev_err(dev, "create default tty port failed"); - goto error_ret; - } - - ifx_dev->gpio.reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ifx_dev->gpio.reset)) { - dev_err(dev, "could not obtain reset GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.reset); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.reset, "ifxModem reset"); - ifx_dev->gpio.po = devm_gpiod_get(dev, "power", GPIOD_OUT_LOW); - if (IS_ERR(ifx_dev->gpio.po)) { - dev_err(dev, "could not obtain power GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.po); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.po, "ifxModem power"); - ifx_dev->gpio.mrdy = devm_gpiod_get(dev, "mrdy", GPIOD_OUT_LOW); - if (IS_ERR(ifx_dev->gpio.mrdy)) { - dev_err(dev, "could not obtain mrdy GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.mrdy); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.mrdy, "ifxModem mrdy"); - ifx_dev->gpio.srdy = devm_gpiod_get(dev, "srdy", GPIOD_IN); - if (IS_ERR(ifx_dev->gpio.srdy)) { - dev_err(dev, "could not obtain srdy GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.srdy); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.srdy, "ifxModem srdy"); - ifx_dev->gpio.reset_out = devm_gpiod_get(dev, "rst_out", GPIOD_IN); - if (IS_ERR(ifx_dev->gpio.reset_out)) { - dev_err(dev, "could not obtain rst_out GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.reset_out); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.reset_out, "ifxModem reset out"); - ifx_dev->gpio.pmu_reset = devm_gpiod_get(dev, "pmu_reset", GPIOD_ASIS); - if (IS_ERR(ifx_dev->gpio.pmu_reset)) { - dev_err(dev, "could not obtain pmu_reset GPIO\n"); - ret = PTR_ERR(ifx_dev->gpio.pmu_reset); - goto error_ret; - } - gpiod_set_consumer_name(ifx_dev->gpio.pmu_reset, "ifxModem PMU reset"); - - ret = request_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), - ifx_spi_reset_interrupt, - IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME, - ifx_dev); - if (ret) { - dev_err(dev, "Unable to get irq %x\n", - gpiod_to_irq(ifx_dev->gpio.reset_out)); - goto error_ret; - } - - ret = ifx_spi_reset(ifx_dev); - - ret = request_irq(gpiod_to_irq(ifx_dev->gpio.srdy), - ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME, - ifx_dev); - if (ret) { - dev_err(dev, "Unable to get irq %x", - gpiod_to_irq(ifx_dev->gpio.srdy)); - goto error_ret2; - } - - /* set pm runtime power state and register with power system */ - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - - /* handle case that modem is already signaling SRDY */ - /* no outgoing tty open at this point, this just satisfies the - * modem's read and should reset communication properly - */ - srdy = gpiod_get_value(ifx_dev->gpio.srdy); - - if (srdy) { - mrdy_assert(ifx_dev); - ifx_spi_handle_srdy(ifx_dev); - } else - mrdy_set_low(ifx_dev); - return 0; - -error_ret2: - free_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), ifx_dev); -error_ret: - ifx_spi_free_device(ifx_dev); - saved_ifx_dev = NULL; - return ret; -} - -/** - * ifx_spi_spi_remove - SPI device was removed - * @spi: SPI device - * - * FIXME: We should be shutting the device down here not in - * the module unload path. - */ - -static int ifx_spi_spi_remove(struct spi_device *spi) -{ - struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); - /* stop activity */ - tasklet_kill(&ifx_dev->io_work_tasklet); - - pm_runtime_disable(&spi->dev); - - /* free irq */ - free_irq(gpiod_to_irq(ifx_dev->gpio.reset_out), ifx_dev); - free_irq(gpiod_to_irq(ifx_dev->gpio.srdy), ifx_dev); - - /* free allocations */ - ifx_spi_free_device(ifx_dev); - - saved_ifx_dev = NULL; - return 0; -} - -/** - * ifx_spi_spi_shutdown - called on SPI shutdown - * @spi: SPI device - * - * No action needs to be taken here - */ - -static void ifx_spi_spi_shutdown(struct spi_device *spi) -{ - struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); - - ifx_modem_power_off(ifx_dev); -} - -/* - * various suspends and resumes have nothing to do - * no hardware to save state for - */ - -/** - * ifx_spi_pm_suspend - suspend modem on system suspend - * @dev: device being suspended - * - * Suspend the modem. No action needed on Intel MID platforms, may - * need extending for other systems. - */ -static int ifx_spi_pm_suspend(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_resume - resume modem on system resume - * @dev: device being suspended - * - * Allow the modem to resume. No action needed. - * - * FIXME: do we need to reset anything here ? - */ -static int ifx_spi_pm_resume(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_runtime_resume - suspend modem - * @dev: device being suspended - * - * Allow the modem to resume. No action needed. - */ -static int ifx_spi_pm_runtime_resume(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_runtime_suspend - suspend modem - * @dev: device being suspended - * - * Allow the modem to suspend and thus suspend to continue up the - * device tree. - */ -static int ifx_spi_pm_runtime_suspend(struct device *dev) -{ - return 0; -} - -/** - * ifx_spi_pm_runtime_idle - check if modem idle - * @dev: our device - * - * Check conditions and queue runtime suspend if idle. - */ -static int ifx_spi_pm_runtime_idle(struct device *dev) -{ - struct spi_device *spi = to_spi_device(dev); - struct ifx_spi_device *ifx_dev = spi_get_drvdata(spi); - - if (!ifx_dev->power_status) - pm_runtime_suspend(dev); - - return 0; -} - -static const struct dev_pm_ops ifx_spi_pm = { - .resume = ifx_spi_pm_resume, - .suspend = ifx_spi_pm_suspend, - .runtime_resume = ifx_spi_pm_runtime_resume, - .runtime_suspend = ifx_spi_pm_runtime_suspend, - .runtime_idle = ifx_spi_pm_runtime_idle -}; - -static const struct spi_device_id ifx_id_table[] = { - {"ifx6160", 0}, - {"ifx6260", 0}, - { } -}; -MODULE_DEVICE_TABLE(spi, ifx_id_table); - -/* spi operations */ -static struct spi_driver ifx_spi_driver = { - .driver = { - .name = DRVNAME, - .pm = &ifx_spi_pm, - }, - .probe = ifx_spi_spi_probe, - .shutdown = ifx_spi_spi_shutdown, - .remove = ifx_spi_spi_remove, - .id_table = ifx_id_table -}; - -/** - * ifx_spi_exit - module exit - * - * Unload the module. - */ - -static void __exit ifx_spi_exit(void) -{ - /* unregister */ - spi_unregister_driver(&ifx_spi_driver); - tty_unregister_driver(tty_drv); - put_tty_driver(tty_drv); - unregister_reboot_notifier(&ifx_modem_reboot_notifier_block); -} - -/** - * ifx_spi_init - module entry point - * - * Initialise the SPI and tty interfaces for the IFX SPI driver - * We need to initialize upper-edge spi driver after the tty - * driver because otherwise the spi probe will race - */ - -static int __init ifx_spi_init(void) -{ - int result; - - tty_drv = alloc_tty_driver(1); - if (!tty_drv) { - pr_err("%s: alloc_tty_driver failed", DRVNAME); - return -ENOMEM; - } - - tty_drv->driver_name = DRVNAME; - tty_drv->name = TTYNAME; - tty_drv->minor_start = IFX_SPI_TTY_ID; - tty_drv->type = TTY_DRIVER_TYPE_SERIAL; - tty_drv->subtype = SERIAL_TYPE_NORMAL; - tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_drv->init_termios = tty_std_termios; - - tty_set_operations(tty_drv, &ifx_spi_serial_ops); - - result = tty_register_driver(tty_drv); - if (result) { - pr_err("%s: tty_register_driver failed(%d)", - DRVNAME, result); - goto err_free_tty; - } - - result = spi_register_driver(&ifx_spi_driver); - if (result) { - pr_err("%s: spi_register_driver failed(%d)", - DRVNAME, result); - goto err_unreg_tty; - } - - result = register_reboot_notifier(&ifx_modem_reboot_notifier_block); - if (result) { - pr_err("%s: register ifx modem reboot notifier failed(%d)", - DRVNAME, result); - goto err_unreg_spi; - } - - return 0; -err_unreg_spi: - spi_unregister_driver(&ifx_spi_driver); -err_unreg_tty: - tty_unregister_driver(tty_drv); -err_free_tty: - put_tty_driver(tty_drv); - - return result; -} - -module_init(ifx_spi_init); -module_exit(ifx_spi_exit); - -MODULE_AUTHOR("Intel"); -MODULE_DESCRIPTION("IFX6x60 spi driver"); -MODULE_LICENSE("GPL"); -MODULE_INFO(Version, "0.1-IFX6x60"); diff --git a/drivers/tty/serial/ifx6x60.h b/drivers/tty/serial/ifx6x60.h deleted file mode 100644 index ecb841d928a7..000000000000 --- a/drivers/tty/serial/ifx6x60.h +++ /dev/null @@ -1,118 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/**************************************************************************** - * - * Driver for the IFX spi modem. - * - * Copyright (C) 2009, 2010 Intel Corp - * Jim Stanley - * - *****************************************************************************/ -#ifndef _IFX6X60_H -#define _IFX6X60_H - -struct gpio_desc; - -#define DRVNAME "ifx6x60" -#define TTYNAME "ttyIFX" - -#define IFX_SPI_MAX_MINORS 1 -#define IFX_SPI_TRANSFER_SIZE 2048 -#define IFX_SPI_FIFO_SIZE 4096 - -#define IFX_SPI_HEADER_OVERHEAD 4 -#define IFX_RESET_TIMEOUT msecs_to_jiffies(50) - -/* device flags bitfield definitions */ -#define IFX_SPI_STATE_PRESENT 0 -#define IFX_SPI_STATE_IO_IN_PROGRESS 1 -#define IFX_SPI_STATE_IO_READY 2 -#define IFX_SPI_STATE_TIMER_PENDING 3 -#define IFX_SPI_STATE_IO_AVAILABLE 4 - -/* flow control bitfields */ -#define IFX_SPI_DCD 0 -#define IFX_SPI_CTS 1 -#define IFX_SPI_DSR 2 -#define IFX_SPI_RI 3 -#define IFX_SPI_DTR 4 -#define IFX_SPI_RTS 5 -#define IFX_SPI_TX_FC 6 -#define IFX_SPI_RX_FC 7 -#define IFX_SPI_UPDATE 8 - -#define IFX_SPI_PAYLOAD_SIZE (IFX_SPI_TRANSFER_SIZE - \ - IFX_SPI_HEADER_OVERHEAD) - -#define IFX_SPI_IRQ_TYPE DETECT_EDGE_RISING -#define IFX_SPI_GPIO_TARGET 0 -#define IFX_SPI_GPIO0 0x105 - -#define IFX_SPI_STATUS_TIMEOUT (2000*HZ) - -/* values for bits in power status byte */ -#define IFX_SPI_POWER_DATA_PENDING 1 -#define IFX_SPI_POWER_SRDY 2 - -struct ifx_spi_device { - /* Our SPI device */ - struct spi_device *spi_dev; - - /* Port specific data */ - struct kfifo tx_fifo; - spinlock_t fifo_lock; - unsigned long signal_state; - - /* TTY Layer logic */ - struct tty_port tty_port; - struct device *tty_dev; - int minor; - - /* Low level I/O work */ - struct tasklet_struct io_work_tasklet; - unsigned long flags; - dma_addr_t rx_dma; - dma_addr_t tx_dma; - - int modem; /* Modem type */ - int use_dma; /* provide dma-able addrs in SPI msg */ - long max_hz; /* max SPI frequency */ - - spinlock_t write_lock; - int write_pending; - spinlock_t power_lock; - unsigned char power_status; - - unsigned char *rx_buffer; - unsigned char *tx_buffer; - dma_addr_t rx_bus; - dma_addr_t tx_bus; - unsigned char spi_more; - unsigned char spi_slave_cts; - - struct timer_list spi_timer; - - struct spi_message spi_msg; - struct spi_transfer spi_xfer; - - struct { - /* gpio lines */ - struct gpio_desc *srdy; /* slave-ready gpio */ - struct gpio_desc *mrdy; /* master-ready gpio */ - struct gpio_desc *reset; /* modem-reset gpio */ - struct gpio_desc *po; /* modem-on gpio */ - struct gpio_desc *reset_out; /* modem-in-reset gpio */ - struct gpio_desc *pmu_reset; /* PMU reset gpio */ - /* state/stats */ - int unack_srdy_int_nb; - } gpio; - - /* modem reset */ - unsigned long mdm_reset_state; -#define MR_START 0 -#define MR_INPROGRESS 1 -#define MR_COMPLETE 2 - wait_queue_head_t mdm_reset_wait; - void (*swap_buf)(unsigned char *buf, int len, void *end); -}; - -#endif /* _IFX6X60_H */ diff --git a/include/linux/spi/ifx_modem.h b/include/linux/spi/ifx_modem.h deleted file mode 100644 index 6d19b09139d0..000000000000 --- a/include/linux/spi/ifx_modem.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef LINUX_IFX_MODEM_H -#define LINUX_IFX_MODEM_H - -struct ifx_modem_platform_data { - unsigned short tx_pwr; /* modem power threshold */ - unsigned char modem_type; /* Modem type */ - unsigned long max_hz; /* max SPI frequency */ - unsigned short use_dma:1; /* spi protocol driver supplies - dma-able addrs */ -}; -#define IFX_MODEM_6160 1 -#define IFX_MODEM_6260 2 - -#endif -- cgit v1.2.3-59-g8ed1b