Merge tag 'tty-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial patches from Greg Kroah-Hartman: "Here's the big tty/serial driver patches for 3.9-rc1. More tty port rework and fixes from Jiri here, as well as lots of individual serial driver updates and fixes. All of these have been in the linux-next tree for a while." * tag 'tty-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (140 commits) tty: mxser: improve error handling in mxser_probe() and mxser_module_init() serial: imx: fix uninitialized variable warning serial: tegra: assume CONFIG_OF TTY: do not update atime/mtime on read/write lguest: select CONFIG_TTY to build properly. ARM defconfigs: add missing inclusions of linux/platform_device.h fb/exynos: include platform_device.h ARM: sa1100/assabet: include platform_device.h directly serial: imx: Fix recursive locking bug pps: Fix build breakage from decoupling pps from tty tty: Remove ancient hardpps() pps: Additional cleanups in uart_handle_dcd_change pps: Move timestamp read into PPS code proper pps: Don't crash the machine when exiting will do pps: Fix a use-after free bug when unregistering a source. pps: Use pps_lookup_dev to reduce ldisc coupling pps: Add pps_lookup_dev() function tty: serial: uartlite: Support uartlite on big and little endian systems tty: serial: uartlite: Fix sparse and checkpatch warnings serial/arc-uart: Miscll DT related updates (Grant's review comments) ... Fix up trivial conflicts, mostly just due to the TTY config option clashing with the EXPERIMENTAL removal.
This commit is contained in:
@@ -1,3 +1,14 @@
|
||||
config TTY
|
||||
bool "Enable TTY" if EXPERT
|
||||
default y
|
||||
---help---
|
||||
Allows you to remove TTY support which can save space, and
|
||||
blocks features that require TTY from inclusion in the kernel.
|
||||
TTY is required for any text terminals or serial port
|
||||
communication. Most users should leave this enabled.
|
||||
|
||||
if TTY
|
||||
|
||||
config VT
|
||||
bool "Virtual terminal" if EXPERT
|
||||
depends on !S390 && !UML
|
||||
@@ -388,3 +399,24 @@ config PPC_EARLY_DEBUG_EHV_BC_HANDLE
|
||||
If the number you specify is not a valid byte channel handle, then
|
||||
there simply will be no early console output. This is true also
|
||||
if you don't boot under a hypervisor at all.
|
||||
|
||||
config GOLDFISH_TTY
|
||||
tristate "Goldfish TTY Driver"
|
||||
depends on GOLDFISH
|
||||
help
|
||||
Console and system TTY driver for the Goldfish virtual platform.
|
||||
|
||||
config DA_TTY
|
||||
bool "DA TTY"
|
||||
depends on METAG_DA
|
||||
select SERIAL_NONSTANDARD
|
||||
help
|
||||
This enables a TTY on a Dash channel.
|
||||
|
||||
config DA_CONSOLE
|
||||
bool "DA Console"
|
||||
depends on DA_TTY
|
||||
help
|
||||
This enables a console on a Dash channel.
|
||||
|
||||
endif # TTY
|
||||
|
@@ -1,4 +1,4 @@
|
||||
obj-y += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
|
||||
obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \
|
||||
tty_buffer.o tty_port.o tty_mutex.o
|
||||
obj-$(CONFIG_LEGACY_PTYS) += pty.o
|
||||
obj-$(CONFIG_UNIX98_PTYS) += pty.o
|
||||
@@ -27,5 +27,7 @@ obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
|
||||
obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
|
||||
obj-$(CONFIG_SYNCLINK) += synclink.o
|
||||
obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o
|
||||
obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o
|
||||
obj-$(CONFIG_DA_TTY) += metag_da.o
|
||||
|
||||
obj-y += ipwireless/
|
||||
|
@@ -251,7 +251,6 @@ static void receive_chars(struct serial_state *info)
|
||||
{
|
||||
int status;
|
||||
int serdatr;
|
||||
struct tty_struct *tty = info->tport.tty;
|
||||
unsigned char ch, flag;
|
||||
struct async_icount *icount;
|
||||
int oe = 0;
|
||||
@@ -314,7 +313,7 @@ static void receive_chars(struct serial_state *info)
|
||||
#endif
|
||||
flag = TTY_BREAK;
|
||||
if (info->tport.flags & ASYNC_SAK)
|
||||
do_SAK(tty);
|
||||
do_SAK(info->tport.tty);
|
||||
} else if (status & UART_LSR_PE)
|
||||
flag = TTY_PARITY;
|
||||
else if (status & UART_LSR_FE)
|
||||
@@ -328,10 +327,10 @@ static void receive_chars(struct serial_state *info)
|
||||
oe = 1;
|
||||
}
|
||||
}
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(&info->tport, ch, flag);
|
||||
if (oe == 1)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_char(&info->tport, 0, TTY_OVERRUN);
|
||||
tty_flip_buffer_push(&info->tport);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
@@ -394,11 +393,6 @@ static void check_modem_status(struct serial_state *info)
|
||||
icount->dsr++;
|
||||
if (dstatus & SER_DCD) {
|
||||
icount->dcd++;
|
||||
#ifdef CONFIG_HARD_PPS
|
||||
if ((port->flags & ASYNC_HARDPPS_CD) &&
|
||||
!(status & SER_DCD))
|
||||
hardpps();
|
||||
#endif
|
||||
}
|
||||
if (dstatus & SER_CTS)
|
||||
icount->cts++;
|
||||
@@ -1099,7 +1093,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
|
||||
state->custom_divisor = new_serial.custom_divisor;
|
||||
port->close_delay = new_serial.close_delay * HZ/100;
|
||||
port->closing_wait = new_serial.closing_wait * HZ/100;
|
||||
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
check_and_exit:
|
||||
if (port->flags & ASYNC_INITIALIZED) {
|
||||
@@ -1528,7 +1522,7 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
|
||||
if (serial_paranoia_check(info, tty->name, "rs_open"))
|
||||
return -ENODEV;
|
||||
|
||||
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
retval = startup(tty, info);
|
||||
if (retval) {
|
||||
|
@@ -95,18 +95,16 @@ bfin_jc_emudat_manager(void *arg)
|
||||
|
||||
/* if incoming data is ready, eat it */
|
||||
if (bfin_read_DBGSTAT() & EMUDIF) {
|
||||
if (tty != NULL) {
|
||||
uint32_t emudat = bfin_read_emudat();
|
||||
if (inbound_len == 0) {
|
||||
pr_debug("incoming length: 0x%08x\n", emudat);
|
||||
inbound_len = emudat;
|
||||
} else {
|
||||
size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
|
||||
pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
|
||||
inbound_len -= num_chars;
|
||||
tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars);
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
uint32_t emudat = bfin_read_emudat();
|
||||
if (inbound_len == 0) {
|
||||
pr_debug("incoming length: 0x%08x\n", emudat);
|
||||
inbound_len = emudat;
|
||||
} else {
|
||||
size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
|
||||
pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
|
||||
inbound_len -= num_chars;
|
||||
tty_insert_flip_string(&port, (unsigned char *)&emudat, num_chars);
|
||||
tty_flip_buffer_push(&port);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -441,7 +441,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
|
||||
void __iomem *base_addr)
|
||||
{
|
||||
struct cyclades_port *info;
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port;
|
||||
int len, index = cinfo->bus_index;
|
||||
u8 ivr, save_xir, channel, save_car, data, char_count;
|
||||
|
||||
@@ -452,22 +452,11 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
|
||||
save_xir = readb(base_addr + (CyRIR << index));
|
||||
channel = save_xir & CyIRChannel;
|
||||
info = &cinfo->ports[channel + chip * 4];
|
||||
port = &info->port;
|
||||
save_car = cyy_readb(info, CyCAR);
|
||||
cyy_writeb(info, CyCAR, save_xir);
|
||||
ivr = cyy_readb(info, CyRIVR) & CyIVRMask;
|
||||
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
/* if there is nowhere to put the data, discard it */
|
||||
if (tty == NULL) {
|
||||
if (ivr == CyIVRRxEx) { /* exception */
|
||||
data = cyy_readb(info, CyRDSR);
|
||||
} else { /* normal character reception */
|
||||
char_count = cyy_readb(info, CyRDCR);
|
||||
while (char_count--)
|
||||
data = cyy_readb(info, CyRDSR);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
/* there is an open port for this data */
|
||||
if (ivr == CyIVRRxEx) { /* exception */
|
||||
data = cyy_readb(info, CyRDSR);
|
||||
@@ -484,40 +473,45 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
|
||||
|
||||
if (data & info->ignore_status_mask) {
|
||||
info->icount.rx++;
|
||||
tty_kref_put(tty);
|
||||
return;
|
||||
}
|
||||
if (tty_buffer_request_room(tty, 1)) {
|
||||
if (tty_buffer_request_room(port, 1)) {
|
||||
if (data & info->read_status_mask) {
|
||||
if (data & CyBREAK) {
|
||||
tty_insert_flip_char(tty,
|
||||
tty_insert_flip_char(port,
|
||||
cyy_readb(info, CyRDSR),
|
||||
TTY_BREAK);
|
||||
info->icount.rx++;
|
||||
if (info->port.flags & ASYNC_SAK)
|
||||
do_SAK(tty);
|
||||
if (port->flags & ASYNC_SAK) {
|
||||
struct tty_struct *tty =
|
||||
tty_port_tty_get(port);
|
||||
if (tty) {
|
||||
do_SAK(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
} else if (data & CyFRAME) {
|
||||
tty_insert_flip_char(tty,
|
||||
tty_insert_flip_char(port,
|
||||
cyy_readb(info, CyRDSR),
|
||||
TTY_FRAME);
|
||||
info->icount.rx++;
|
||||
info->idle_stats.frame_errs++;
|
||||
} else if (data & CyPARITY) {
|
||||
/* Pieces of seven... */
|
||||
tty_insert_flip_char(tty,
|
||||
tty_insert_flip_char(port,
|
||||
cyy_readb(info, CyRDSR),
|
||||
TTY_PARITY);
|
||||
info->icount.rx++;
|
||||
info->idle_stats.parity_errs++;
|
||||
} else if (data & CyOVERRUN) {
|
||||
tty_insert_flip_char(tty, 0,
|
||||
tty_insert_flip_char(port, 0,
|
||||
TTY_OVERRUN);
|
||||
info->icount.rx++;
|
||||
/* If the flip buffer itself is
|
||||
overflowing, we still lose
|
||||
the next incoming character.
|
||||
*/
|
||||
tty_insert_flip_char(tty,
|
||||
tty_insert_flip_char(port,
|
||||
cyy_readb(info, CyRDSR),
|
||||
TTY_FRAME);
|
||||
info->icount.rx++;
|
||||
@@ -527,12 +521,12 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
|
||||
/* } else if(data & CyTIMEOUT) { */
|
||||
/* } else if(data & CySPECHAR) { */
|
||||
} else {
|
||||
tty_insert_flip_char(tty, 0,
|
||||
tty_insert_flip_char(port, 0,
|
||||
TTY_NORMAL);
|
||||
info->icount.rx++;
|
||||
}
|
||||
} else {
|
||||
tty_insert_flip_char(tty, 0, TTY_NORMAL);
|
||||
tty_insert_flip_char(port, 0, TTY_NORMAL);
|
||||
info->icount.rx++;
|
||||
}
|
||||
} else {
|
||||
@@ -552,10 +546,10 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
|
||||
info->mon.char_max = char_count;
|
||||
info->mon.char_last = char_count;
|
||||
#endif
|
||||
len = tty_buffer_request_room(tty, char_count);
|
||||
len = tty_buffer_request_room(port, char_count);
|
||||
while (len--) {
|
||||
data = cyy_readb(info, CyRDSR);
|
||||
tty_insert_flip_char(tty, data, TTY_NORMAL);
|
||||
tty_insert_flip_char(port, data, TTY_NORMAL);
|
||||
info->idle_stats.recv_bytes++;
|
||||
info->icount.rx++;
|
||||
#ifdef CY_16Y_HACK
|
||||
@@ -564,9 +558,8 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip,
|
||||
}
|
||||
info->idle_stats.recv_idle = jiffies;
|
||||
}
|
||||
tty_schedule_flip(tty);
|
||||
tty_kref_put(tty);
|
||||
end:
|
||||
tty_schedule_flip(port);
|
||||
|
||||
/* end of service */
|
||||
cyy_writeb(info, CyRIR, save_xir & 0x3f);
|
||||
cyy_writeb(info, CyCAR, save_car);
|
||||
@@ -924,10 +917,11 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
|
||||
return 0;
|
||||
} /* cyz_issue_cmd */
|
||||
|
||||
static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
|
||||
static void cyz_handle_rx(struct cyclades_port *info)
|
||||
{
|
||||
struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
|
||||
struct cyclades_card *cinfo = info->card;
|
||||
struct tty_port *port = &info->port;
|
||||
unsigned int char_count;
|
||||
int len;
|
||||
#ifdef BLOCKMOVE
|
||||
@@ -946,80 +940,77 @@ static void cyz_handle_rx(struct cyclades_port *info, struct tty_struct *tty)
|
||||
else
|
||||
char_count = rx_put - rx_get + rx_bufsize;
|
||||
|
||||
if (char_count) {
|
||||
if (!char_count)
|
||||
return;
|
||||
|
||||
#ifdef CY_ENABLE_MONITORING
|
||||
info->mon.int_count++;
|
||||
info->mon.char_count += char_count;
|
||||
if (char_count > info->mon.char_max)
|
||||
info->mon.char_max = char_count;
|
||||
info->mon.char_last = char_count;
|
||||
info->mon.int_count++;
|
||||
info->mon.char_count += char_count;
|
||||
if (char_count > info->mon.char_max)
|
||||
info->mon.char_max = char_count;
|
||||
info->mon.char_last = char_count;
|
||||
#endif
|
||||
if (tty == NULL) {
|
||||
/* flush received characters */
|
||||
new_rx_get = (new_rx_get + char_count) &
|
||||
(rx_bufsize - 1);
|
||||
info->rflush_count++;
|
||||
} else {
|
||||
|
||||
#ifdef BLOCKMOVE
|
||||
/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
|
||||
for performance, but because of buffer boundaries, there
|
||||
may be several steps to the operation */
|
||||
while (1) {
|
||||
len = tty_prepare_flip_string(tty, &buf,
|
||||
char_count);
|
||||
if (!len)
|
||||
break;
|
||||
/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
|
||||
for performance, but because of buffer boundaries, there
|
||||
may be several steps to the operation */
|
||||
while (1) {
|
||||
len = tty_prepare_flip_string(port, &buf,
|
||||
char_count);
|
||||
if (!len)
|
||||
break;
|
||||
|
||||
len = min_t(unsigned int, min(len, char_count),
|
||||
rx_bufsize - new_rx_get);
|
||||
len = min_t(unsigned int, min(len, char_count),
|
||||
rx_bufsize - new_rx_get);
|
||||
|
||||
memcpy_fromio(buf, cinfo->base_addr +
|
||||
rx_bufaddr + new_rx_get, len);
|
||||
memcpy_fromio(buf, cinfo->base_addr +
|
||||
rx_bufaddr + new_rx_get, len);
|
||||
|
||||
new_rx_get = (new_rx_get + len) &
|
||||
(rx_bufsize - 1);
|
||||
char_count -= len;
|
||||
info->icount.rx += len;
|
||||
info->idle_stats.recv_bytes += len;
|
||||
}
|
||||
new_rx_get = (new_rx_get + len) &
|
||||
(rx_bufsize - 1);
|
||||
char_count -= len;
|
||||
info->icount.rx += len;
|
||||
info->idle_stats.recv_bytes += len;
|
||||
}
|
||||
#else
|
||||
len = tty_buffer_request_room(tty, char_count);
|
||||
while (len--) {
|
||||
data = readb(cinfo->base_addr + rx_bufaddr +
|
||||
new_rx_get);
|
||||
new_rx_get = (new_rx_get + 1) &
|
||||
(rx_bufsize - 1);
|
||||
tty_insert_flip_char(tty, data, TTY_NORMAL);
|
||||
info->idle_stats.recv_bytes++;
|
||||
info->icount.rx++;
|
||||
}
|
||||
len = tty_buffer_request_room(port, char_count);
|
||||
while (len--) {
|
||||
data = readb(cinfo->base_addr + rx_bufaddr +
|
||||
new_rx_get);
|
||||
new_rx_get = (new_rx_get + 1) &
|
||||
(rx_bufsize - 1);
|
||||
tty_insert_flip_char(port, data, TTY_NORMAL);
|
||||
info->idle_stats.recv_bytes++;
|
||||
info->icount.rx++;
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_CYZ_INTR
|
||||
/* Recalculate the number of chars in the RX buffer and issue
|
||||
a cmd in case it's higher than the RX high water mark */
|
||||
rx_put = readl(&buf_ctrl->rx_put);
|
||||
if (rx_put >= rx_get)
|
||||
char_count = rx_put - rx_get;
|
||||
else
|
||||
char_count = rx_put - rx_get + rx_bufsize;
|
||||
if (char_count >= readl(&buf_ctrl->rx_threshold) &&
|
||||
!timer_pending(&cyz_rx_full_timer[
|
||||
info->line]))
|
||||
mod_timer(&cyz_rx_full_timer[info->line],
|
||||
jiffies + 1);
|
||||
/* Recalculate the number of chars in the RX buffer and issue
|
||||
a cmd in case it's higher than the RX high water mark */
|
||||
rx_put = readl(&buf_ctrl->rx_put);
|
||||
if (rx_put >= rx_get)
|
||||
char_count = rx_put - rx_get;
|
||||
else
|
||||
char_count = rx_put - rx_get + rx_bufsize;
|
||||
if (char_count >= readl(&buf_ctrl->rx_threshold) &&
|
||||
!timer_pending(&cyz_rx_full_timer[
|
||||
info->line]))
|
||||
mod_timer(&cyz_rx_full_timer[info->line],
|
||||
jiffies + 1);
|
||||
#endif
|
||||
info->idle_stats.recv_idle = jiffies;
|
||||
tty_schedule_flip(tty);
|
||||
}
|
||||
/* Update rx_get */
|
||||
cy_writel(&buf_ctrl->rx_get, new_rx_get);
|
||||
}
|
||||
info->idle_stats.recv_idle = jiffies;
|
||||
tty_schedule_flip(&info->port);
|
||||
|
||||
/* Update rx_get */
|
||||
cy_writel(&buf_ctrl->rx_get, new_rx_get);
|
||||
}
|
||||
|
||||
static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
|
||||
static void cyz_handle_tx(struct cyclades_port *info)
|
||||
{
|
||||
struct BUF_CTRL __iomem *buf_ctrl = info->u.cyz.buf_ctrl;
|
||||
struct cyclades_card *cinfo = info->card;
|
||||
struct tty_struct *tty;
|
||||
u8 data;
|
||||
unsigned int char_count;
|
||||
#ifdef BLOCKMOVE
|
||||
@@ -1039,63 +1030,63 @@ static void cyz_handle_tx(struct cyclades_port *info, struct tty_struct *tty)
|
||||
else
|
||||
char_count = tx_get - tx_put - 1;
|
||||
|
||||
if (char_count) {
|
||||
if (!char_count)
|
||||
return;
|
||||
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (tty == NULL)
|
||||
goto ztxdone;
|
||||
|
||||
if (tty == NULL)
|
||||
goto ztxdone;
|
||||
if (info->x_char) { /* send special char */
|
||||
data = info->x_char;
|
||||
|
||||
if (info->x_char) { /* send special char */
|
||||
data = info->x_char;
|
||||
|
||||
cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
|
||||
tx_put = (tx_put + 1) & (tx_bufsize - 1);
|
||||
info->x_char = 0;
|
||||
char_count--;
|
||||
info->icount.tx++;
|
||||
}
|
||||
#ifdef BLOCKMOVE
|
||||
while (0 < (small_count = min_t(unsigned int,
|
||||
tx_bufsize - tx_put, min_t(unsigned int,
|
||||
(SERIAL_XMIT_SIZE - info->xmit_tail),
|
||||
min_t(unsigned int, info->xmit_cnt,
|
||||
char_count))))) {
|
||||
|
||||
memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr +
|
||||
tx_put),
|
||||
&info->port.xmit_buf[info->xmit_tail],
|
||||
small_count);
|
||||
|
||||
tx_put = (tx_put + small_count) & (tx_bufsize - 1);
|
||||
char_count -= small_count;
|
||||
info->icount.tx += small_count;
|
||||
info->xmit_cnt -= small_count;
|
||||
info->xmit_tail = (info->xmit_tail + small_count) &
|
||||
(SERIAL_XMIT_SIZE - 1);
|
||||
}
|
||||
#else
|
||||
while (info->xmit_cnt && char_count) {
|
||||
data = info->port.xmit_buf[info->xmit_tail];
|
||||
info->xmit_cnt--;
|
||||
info->xmit_tail = (info->xmit_tail + 1) &
|
||||
(SERIAL_XMIT_SIZE - 1);
|
||||
|
||||
cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
|
||||
tx_put = (tx_put + 1) & (tx_bufsize - 1);
|
||||
char_count--;
|
||||
info->icount.tx++;
|
||||
}
|
||||
#endif
|
||||
tty_wakeup(tty);
|
||||
ztxdone:
|
||||
/* Update tx_put */
|
||||
cy_writel(&buf_ctrl->tx_put, tx_put);
|
||||
cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
|
||||
tx_put = (tx_put + 1) & (tx_bufsize - 1);
|
||||
info->x_char = 0;
|
||||
char_count--;
|
||||
info->icount.tx++;
|
||||
}
|
||||
#ifdef BLOCKMOVE
|
||||
while (0 < (small_count = min_t(unsigned int,
|
||||
tx_bufsize - tx_put, min_t(unsigned int,
|
||||
(SERIAL_XMIT_SIZE - info->xmit_tail),
|
||||
min_t(unsigned int, info->xmit_cnt,
|
||||
char_count))))) {
|
||||
|
||||
memcpy_toio((char *)(cinfo->base_addr + tx_bufaddr + tx_put),
|
||||
&info->port.xmit_buf[info->xmit_tail],
|
||||
small_count);
|
||||
|
||||
tx_put = (tx_put + small_count) & (tx_bufsize - 1);
|
||||
char_count -= small_count;
|
||||
info->icount.tx += small_count;
|
||||
info->xmit_cnt -= small_count;
|
||||
info->xmit_tail = (info->xmit_tail + small_count) &
|
||||
(SERIAL_XMIT_SIZE - 1);
|
||||
}
|
||||
#else
|
||||
while (info->xmit_cnt && char_count) {
|
||||
data = info->port.xmit_buf[info->xmit_tail];
|
||||
info->xmit_cnt--;
|
||||
info->xmit_tail = (info->xmit_tail + 1) &
|
||||
(SERIAL_XMIT_SIZE - 1);
|
||||
|
||||
cy_writeb(cinfo->base_addr + tx_bufaddr + tx_put, data);
|
||||
tx_put = (tx_put + 1) & (tx_bufsize - 1);
|
||||
char_count--;
|
||||
info->icount.tx++;
|
||||
}
|
||||
#endif
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
ztxdone:
|
||||
/* Update tx_put */
|
||||
cy_writel(&buf_ctrl->tx_put, tx_put);
|
||||
}
|
||||
|
||||
static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
{
|
||||
struct BOARD_CTRL __iomem *board_ctrl = cinfo->board_ctrl;
|
||||
struct tty_struct *tty;
|
||||
struct cyclades_port *info;
|
||||
__u32 channel, param, fw_ver;
|
||||
__u8 cmd;
|
||||
@@ -1108,23 +1099,20 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
special_count = 0;
|
||||
delta_count = 0;
|
||||
info = &cinfo->ports[channel];
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (tty == NULL)
|
||||
continue;
|
||||
|
||||
switch (cmd) {
|
||||
case C_CM_PR_ERROR:
|
||||
tty_insert_flip_char(tty, 0, TTY_PARITY);
|
||||
tty_insert_flip_char(&info->port, 0, TTY_PARITY);
|
||||
info->icount.rx++;
|
||||
special_count++;
|
||||
break;
|
||||
case C_CM_FR_ERROR:
|
||||
tty_insert_flip_char(tty, 0, TTY_FRAME);
|
||||
tty_insert_flip_char(&info->port, 0, TTY_FRAME);
|
||||
info->icount.rx++;
|
||||
special_count++;
|
||||
break;
|
||||
case C_CM_RXBRK:
|
||||
tty_insert_flip_char(tty, 0, TTY_BREAK);
|
||||
tty_insert_flip_char(&info->port, 0, TTY_BREAK);
|
||||
info->icount.rx++;
|
||||
special_count++;
|
||||
break;
|
||||
@@ -1136,8 +1124,14 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
readl(&info->u.cyz.ch_ctrl->rs_status);
|
||||
if (dcd & C_RS_DCD)
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
else
|
||||
tty_hangup(tty);
|
||||
else {
|
||||
struct tty_struct *tty;
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case C_CM_MCTS:
|
||||
@@ -1166,7 +1160,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
|
||||
"port %ld\n", info->card, channel);
|
||||
#endif
|
||||
cyz_handle_rx(info, tty);
|
||||
cyz_handle_rx(info);
|
||||
break;
|
||||
case C_CM_TXBEMPTY:
|
||||
case C_CM_TXLOWWM:
|
||||
@@ -1176,7 +1170,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
|
||||
"port %ld\n", info->card, channel);
|
||||
#endif
|
||||
cyz_handle_tx(info, tty);
|
||||
cyz_handle_tx(info);
|
||||
break;
|
||||
#endif /* CONFIG_CYZ_INTR */
|
||||
case C_CM_FATAL:
|
||||
@@ -1188,8 +1182,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
||||
if (delta_count)
|
||||
wake_up_interruptible(&info->port.delta_msr_wait);
|
||||
if (special_count)
|
||||
tty_schedule_flip(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_schedule_flip(&info->port);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1255,17 +1248,11 @@ static void cyz_poll(unsigned long arg)
|
||||
cyz_handle_cmd(cinfo);
|
||||
|
||||
for (port = 0; port < cinfo->nports; port++) {
|
||||
struct tty_struct *tty;
|
||||
|
||||
info = &cinfo->ports[port];
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
/* OK to pass NULL to the handle functions below.
|
||||
They need to drop the data in that case. */
|
||||
|
||||
if (!info->throttle)
|
||||
cyz_handle_rx(info, tty);
|
||||
cyz_handle_tx(info, tty);
|
||||
tty_kref_put(tty);
|
||||
cyz_handle_rx(info);
|
||||
cyz_handle_tx(info);
|
||||
}
|
||||
/* poll every 'cyz_polling_cycle' period */
|
||||
expires = jiffies + cyz_polling_cycle;
|
||||
|
@@ -371,22 +371,17 @@ console_initcall(ehv_bc_console_init);
|
||||
static irqreturn_t ehv_bc_tty_rx_isr(int irq, void *data)
|
||||
{
|
||||
struct ehv_bc_data *bc = data;
|
||||
struct tty_struct *ttys = tty_port_tty_get(&bc->port);
|
||||
unsigned int rx_count, tx_count, len;
|
||||
int count;
|
||||
char buffer[EV_BYTE_CHANNEL_MAX_BYTES];
|
||||
int ret;
|
||||
|
||||
/* ttys could be NULL during a hangup */
|
||||
if (!ttys)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
/* Find out how much data needs to be read, and then ask the TTY layer
|
||||
* if it can handle that much. We want to ensure that every byte we
|
||||
* read from the byte channel will be accepted by the TTY layer.
|
||||
*/
|
||||
ev_byte_channel_poll(bc->handle, &rx_count, &tx_count);
|
||||
count = tty_buffer_request_room(ttys, rx_count);
|
||||
count = tty_buffer_request_room(&bc->port, rx_count);
|
||||
|
||||
/* 'count' is the maximum amount of data the TTY layer can accept at
|
||||
* this time. However, during testing, I was never able to get 'count'
|
||||
@@ -407,7 +402,7 @@ static irqreturn_t ehv_bc_tty_rx_isr(int irq, void *data)
|
||||
*/
|
||||
|
||||
/* Pass the received data to the tty layer. */
|
||||
ret = tty_insert_flip_string(ttys, buffer, len);
|
||||
ret = tty_insert_flip_string(&bc->port, buffer, len);
|
||||
|
||||
/* 'ret' is the number of bytes that the TTY layer accepted.
|
||||
* If it's not equal to 'len', then it means the buffer is
|
||||
@@ -422,9 +417,7 @@ static irqreturn_t ehv_bc_tty_rx_isr(int irq, void *data)
|
||||
}
|
||||
|
||||
/* Tell the tty layer that we're done. */
|
||||
tty_flip_buffer_push(ttys);
|
||||
|
||||
tty_kref_put(ttys);
|
||||
tty_flip_buffer_push(&bc->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
328
drivers/tty/goldfish.c
Normal file
328
drivers/tty/goldfish.c
Normal file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
* Copyright (C) 2012 Intel, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
enum {
|
||||
GOLDFISH_TTY_PUT_CHAR = 0x00,
|
||||
GOLDFISH_TTY_BYTES_READY = 0x04,
|
||||
GOLDFISH_TTY_CMD = 0x08,
|
||||
|
||||
GOLDFISH_TTY_DATA_PTR = 0x10,
|
||||
GOLDFISH_TTY_DATA_LEN = 0x14,
|
||||
|
||||
GOLDFISH_TTY_CMD_INT_DISABLE = 0,
|
||||
GOLDFISH_TTY_CMD_INT_ENABLE = 1,
|
||||
GOLDFISH_TTY_CMD_WRITE_BUFFER = 2,
|
||||
GOLDFISH_TTY_CMD_READ_BUFFER = 3,
|
||||
};
|
||||
|
||||
struct goldfish_tty {
|
||||
struct tty_port port;
|
||||
spinlock_t lock;
|
||||
void __iomem *base;
|
||||
u32 irq;
|
||||
int opencount;
|
||||
struct console console;
|
||||
};
|
||||
|
||||
static DEFINE_MUTEX(goldfish_tty_lock);
|
||||
static struct tty_driver *goldfish_tty_driver;
|
||||
static u32 goldfish_tty_line_count = 8;
|
||||
static u32 goldfish_tty_current_line_count;
|
||||
static struct goldfish_tty *goldfish_ttys;
|
||||
|
||||
static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
|
||||
{
|
||||
unsigned long irq_flags;
|
||||
struct goldfish_tty *qtty = &goldfish_ttys[line];
|
||||
void __iomem *base = qtty->base;
|
||||
spin_lock_irqsave(&qtty->lock, irq_flags);
|
||||
writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR);
|
||||
writel(count, base + GOLDFISH_TTY_DATA_LEN);
|
||||
writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);
|
||||
spin_unlock_irqrestore(&qtty->lock, irq_flags);
|
||||
}
|
||||
|
||||
static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct platform_device *pdev = dev_id;
|
||||
struct goldfish_tty *qtty = &goldfish_ttys[pdev->id];
|
||||
void __iomem *base = qtty->base;
|
||||
unsigned long irq_flags;
|
||||
unsigned char *buf;
|
||||
u32 count;
|
||||
|
||||
count = readl(base + GOLDFISH_TTY_BYTES_READY);
|
||||
if(count == 0)
|
||||
return IRQ_NONE;
|
||||
|
||||
count = tty_prepare_flip_string(&qtty->port, &buf, count);
|
||||
spin_lock_irqsave(&qtty->lock, irq_flags);
|
||||
writel((u32)buf, base + GOLDFISH_TTY_DATA_PTR);
|
||||
writel(count, base + GOLDFISH_TTY_DATA_LEN);
|
||||
writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);
|
||||
spin_unlock_irqrestore(&qtty->lock, irq_flags);
|
||||
tty_schedule_flip(&qtty->port);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port);
|
||||
writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void goldfish_tty_shutdown(struct tty_port *port)
|
||||
{
|
||||
struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port);
|
||||
writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD);
|
||||
}
|
||||
|
||||
static int goldfish_tty_open(struct tty_struct * tty, struct file * filp)
|
||||
{
|
||||
struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
|
||||
return tty_port_open(&qtty->port, tty, filp);
|
||||
}
|
||||
|
||||
static void goldfish_tty_close(struct tty_struct * tty, struct file * filp)
|
||||
{
|
||||
tty_port_close(tty->port, tty, filp);
|
||||
}
|
||||
|
||||
static void goldfish_tty_hangup(struct tty_struct *tty)
|
||||
{
|
||||
tty_port_hangup(tty->port);
|
||||
}
|
||||
|
||||
static int goldfish_tty_write(struct tty_struct * tty, const unsigned char *buf, int count)
|
||||
{
|
||||
goldfish_tty_do_write(tty->index, buf, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int goldfish_tty_write_room(struct tty_struct *tty)
|
||||
{
|
||||
return 0x10000;
|
||||
}
|
||||
|
||||
static int goldfish_tty_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct goldfish_tty *qtty = &goldfish_ttys[tty->index];
|
||||
void __iomem *base = qtty->base;
|
||||
return readl(base + GOLDFISH_TTY_BYTES_READY);
|
||||
}
|
||||
|
||||
static void goldfish_tty_console_write(struct console *co, const char *b, unsigned count)
|
||||
{
|
||||
goldfish_tty_do_write(co->index, b, count);
|
||||
}
|
||||
|
||||
static struct tty_driver *goldfish_tty_console_device(struct console *c, int *index)
|
||||
{
|
||||
*index = c->index;
|
||||
return goldfish_tty_driver;
|
||||
}
|
||||
|
||||
static int goldfish_tty_console_setup(struct console *co, char *options)
|
||||
{
|
||||
if((unsigned)co->index > goldfish_tty_line_count)
|
||||
return -ENODEV;
|
||||
if(goldfish_ttys[co->index].base == 0)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tty_port_operations goldfish_port_ops = {
|
||||
.activate = goldfish_tty_activate,
|
||||
.shutdown = goldfish_tty_shutdown
|
||||
};
|
||||
|
||||
static struct tty_operations goldfish_tty_ops = {
|
||||
.open = goldfish_tty_open,
|
||||
.close = goldfish_tty_close,
|
||||
.hangup = goldfish_tty_hangup,
|
||||
.write = goldfish_tty_write,
|
||||
.write_room = goldfish_tty_write_room,
|
||||
.chars_in_buffer = goldfish_tty_chars_in_buffer,
|
||||
};
|
||||
|
||||
static int goldfish_tty_create_driver(void)
|
||||
{
|
||||
int ret;
|
||||
struct tty_driver *tty;
|
||||
|
||||
goldfish_ttys = kzalloc(sizeof(*goldfish_ttys) * goldfish_tty_line_count, GFP_KERNEL);
|
||||
if(goldfish_ttys == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_goldfish_ttys_failed;
|
||||
}
|
||||
tty = alloc_tty_driver(goldfish_tty_line_count);
|
||||
if(tty == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err_alloc_tty_driver_failed;
|
||||
}
|
||||
tty->driver_name = "goldfish";
|
||||
tty->name = "ttyGF";
|
||||
tty->type = TTY_DRIVER_TYPE_SERIAL;
|
||||
tty->subtype = SERIAL_TYPE_NORMAL;
|
||||
tty->init_termios = tty_std_termios;
|
||||
tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
|
||||
tty_set_operations(tty, &goldfish_tty_ops);
|
||||
ret = tty_register_driver(tty);
|
||||
if(ret)
|
||||
goto err_tty_register_driver_failed;
|
||||
|
||||
goldfish_tty_driver = tty;
|
||||
return 0;
|
||||
|
||||
err_tty_register_driver_failed:
|
||||
put_tty_driver(tty);
|
||||
err_alloc_tty_driver_failed:
|
||||
kfree(goldfish_ttys);
|
||||
goldfish_ttys = NULL;
|
||||
err_alloc_goldfish_ttys_failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void goldfish_tty_delete_driver(void)
|
||||
{
|
||||
tty_unregister_driver(goldfish_tty_driver);
|
||||
put_tty_driver(goldfish_tty_driver);
|
||||
goldfish_tty_driver = NULL;
|
||||
kfree(goldfish_ttys);
|
||||
goldfish_ttys = NULL;
|
||||
}
|
||||
|
||||
static int goldfish_tty_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct goldfish_tty *qtty;
|
||||
int ret = -EINVAL;
|
||||
int i;
|
||||
struct resource *r;
|
||||
struct device *ttydev;
|
||||
void __iomem *base;
|
||||
u32 irq;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if(r == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
base = ioremap(r->start, 0x1000);
|
||||
if (base == NULL)
|
||||
pr_err("goldfish_tty: unable to remap base\n");
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if(r == NULL)
|
||||
goto err_unmap;
|
||||
|
||||
irq = r->start;
|
||||
|
||||
if(pdev->id >= goldfish_tty_line_count)
|
||||
goto err_unmap;
|
||||
|
||||
mutex_lock(&goldfish_tty_lock);
|
||||
if(goldfish_tty_current_line_count == 0) {
|
||||
ret = goldfish_tty_create_driver();
|
||||
if(ret)
|
||||
goto err_create_driver_failed;
|
||||
}
|
||||
goldfish_tty_current_line_count++;
|
||||
|
||||
qtty = &goldfish_ttys[pdev->id];
|
||||
spin_lock_init(&qtty->lock);
|
||||
tty_port_init(&qtty->port);
|
||||
qtty->port.ops = &goldfish_port_ops;
|
||||
qtty->base = base;
|
||||
qtty->irq = irq;
|
||||
|
||||
writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD);
|
||||
|
||||
ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", pdev);
|
||||
if(ret)
|
||||
goto err_request_irq_failed;
|
||||
|
||||
|
||||
ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver,
|
||||
pdev->id, &pdev->dev);
|
||||
if(IS_ERR(ttydev)) {
|
||||
ret = PTR_ERR(ttydev);
|
||||
goto err_tty_register_device_failed;
|
||||
}
|
||||
|
||||
strcpy(qtty->console.name, "ttyGF");
|
||||
qtty->console.write = goldfish_tty_console_write;
|
||||
qtty->console.device = goldfish_tty_console_device;
|
||||
qtty->console.setup = goldfish_tty_console_setup;
|
||||
qtty->console.flags = CON_PRINTBUFFER;
|
||||
qtty->console.index = pdev->id;
|
||||
register_console(&qtty->console);
|
||||
|
||||
mutex_unlock(&goldfish_tty_lock);
|
||||
return 0;
|
||||
|
||||
tty_unregister_device(goldfish_tty_driver, i);
|
||||
err_tty_register_device_failed:
|
||||
free_irq(irq, pdev);
|
||||
err_request_irq_failed:
|
||||
goldfish_tty_current_line_count--;
|
||||
if(goldfish_tty_current_line_count == 0)
|
||||
goldfish_tty_delete_driver();
|
||||
err_create_driver_failed:
|
||||
mutex_unlock(&goldfish_tty_lock);
|
||||
err_unmap:
|
||||
iounmap(base);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int goldfish_tty_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct goldfish_tty *qtty;
|
||||
|
||||
mutex_lock(&goldfish_tty_lock);
|
||||
|
||||
qtty = &goldfish_ttys[pdev->id];
|
||||
unregister_console(&qtty->console);
|
||||
tty_unregister_device(goldfish_tty_driver, pdev->id);
|
||||
iounmap(qtty->base);
|
||||
qtty->base = 0;
|
||||
free_irq(qtty->irq, pdev);
|
||||
goldfish_tty_current_line_count--;
|
||||
if(goldfish_tty_current_line_count == 0)
|
||||
goldfish_tty_delete_driver();
|
||||
mutex_unlock(&goldfish_tty_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver goldfish_tty_platform_driver = {
|
||||
.probe = goldfish_tty_probe,
|
||||
.remove = goldfish_tty_remove,
|
||||
.driver = {
|
||||
.name = "goldfish_tty"
|
||||
}
|
||||
};
|
||||
|
||||
module_platform_driver(goldfish_tty_platform_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
@@ -1,3 +1,5 @@
|
||||
if TTY
|
||||
|
||||
config HVC_DRIVER
|
||||
bool
|
||||
help
|
||||
@@ -119,3 +121,4 @@ config HVCS
|
||||
which will also be compiled when this driver is built as a
|
||||
module.
|
||||
|
||||
endif # TTY
|
||||
|
@@ -629,7 +629,7 @@ int hvc_poll(struct hvc_struct *hp)
|
||||
|
||||
/* Read data if any */
|
||||
for (;;) {
|
||||
int count = tty_buffer_request_room(tty, N_INBUF);
|
||||
int count = tty_buffer_request_room(&hp->port, N_INBUF);
|
||||
|
||||
/* If flip is full, just reschedule a later read */
|
||||
if (count == 0) {
|
||||
@@ -672,7 +672,7 @@ int hvc_poll(struct hvc_struct *hp)
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_MAGIC_SYSRQ */
|
||||
tty_insert_flip_char(tty, buf[i], 0);
|
||||
tty_insert_flip_char(&hp->port, buf[i], 0);
|
||||
}
|
||||
|
||||
read_total += n;
|
||||
@@ -691,7 +691,7 @@ int hvc_poll(struct hvc_struct *hp)
|
||||
a minimum for performance. */
|
||||
timeout = MIN_TIMEOUT;
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&hp->port);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
|
||||
|
@@ -609,11 +609,11 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
|
||||
/* remove the read masks */
|
||||
hvcsd->todo_mask &= ~(HVCS_READ_MASK);
|
||||
|
||||
if (tty_buffer_request_room(tty, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) {
|
||||
if (tty_buffer_request_room(&hvcsd->port, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) {
|
||||
got = hvc_get_chars(unit_address,
|
||||
&buf[0],
|
||||
HVCS_BUFF_LEN);
|
||||
tty_insert_flip_string(tty, buf, got);
|
||||
tty_insert_flip_string(&hvcsd->port, buf, got);
|
||||
}
|
||||
|
||||
/* Give the TTY time to process the data we just sent. */
|
||||
@@ -623,7 +623,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd)
|
||||
spin_unlock_irqrestore(&hvcsd->lock, flags);
|
||||
/* This is synch because tty->low_latency == 1 */
|
||||
if(got)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&hvcsd->port);
|
||||
|
||||
if (!got) {
|
||||
/* Do this _after_ the flip_buffer_push */
|
||||
|
@@ -329,8 +329,7 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
|
||||
}
|
||||
}
|
||||
|
||||
static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
const char *buf, int len)
|
||||
static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -346,7 +345,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
continue;
|
||||
}
|
||||
#endif /* CONFIG_MAGIC_SYSRQ */
|
||||
tty_insert_flip_char(tty, c, 0);
|
||||
tty_insert_flip_char(&hp->port, c, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,8 +358,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
* revisited.
|
||||
*/
|
||||
#define TTY_THRESHOLD_THROTTLE 128
|
||||
static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
const uint8_t *packet)
|
||||
static bool hvsi_recv_data(struct hvsi_struct *hp, const uint8_t *packet)
|
||||
{
|
||||
const struct hvsi_header *header = (const struct hvsi_header *)packet;
|
||||
const uint8_t *data = packet + sizeof(struct hvsi_header);
|
||||
@@ -377,7 +375,7 @@ static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
datalen = TTY_THRESHOLD_THROTTLE;
|
||||
}
|
||||
|
||||
hvsi_insert_chars(hp, tty, data, datalen);
|
||||
hvsi_insert_chars(hp, data, datalen);
|
||||
|
||||
if (overflow > 0) {
|
||||
/*
|
||||
@@ -438,9 +436,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
case VS_DATA_PACKET_HEADER:
|
||||
if (!is_open(hp))
|
||||
break;
|
||||
if (tty == NULL)
|
||||
break; /* no tty buffer to put data in */
|
||||
flip = hvsi_recv_data(hp, tty, packet);
|
||||
flip = hvsi_recv_data(hp, packet);
|
||||
break;
|
||||
case VS_CONTROL_PACKET_HEADER:
|
||||
hvsi_recv_control(hp, packet, tty, handshake);
|
||||
@@ -469,17 +465,17 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
|
||||
compact_inbuf(hp, packet);
|
||||
|
||||
if (flip)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&hp->port);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty)
|
||||
static void hvsi_send_overflow(struct hvsi_struct *hp)
|
||||
{
|
||||
pr_debug("%s: delivering %i bytes overflow\n", __func__,
|
||||
hp->n_throttle);
|
||||
|
||||
hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle);
|
||||
hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
|
||||
hp->n_throttle = 0;
|
||||
}
|
||||
|
||||
@@ -514,8 +510,8 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
|
||||
if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
/* we weren't hung up and we weren't throttled, so we can
|
||||
* deliver the rest now */
|
||||
hvsi_send_overflow(hp, tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
hvsi_send_overflow(hp);
|
||||
tty_flip_buffer_push(&hp->port);
|
||||
}
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
|
||||
@@ -1001,8 +997,8 @@ static void hvsi_unthrottle(struct tty_struct *tty)
|
||||
|
||||
spin_lock_irqsave(&hp->lock, flags);
|
||||
if (hp->n_throttle) {
|
||||
hvsi_send_overflow(hp, tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
hvsi_send_overflow(hp);
|
||||
tty_flip_buffer_push(&hp->port);
|
||||
}
|
||||
spin_unlock_irqrestore(&hp->lock, flags);
|
||||
|
||||
@@ -1187,9 +1183,7 @@ static int __init hvsi_console_init(void)
|
||||
hvsi_wait = poll_for_state; /* no irqs yet; must poll */
|
||||
|
||||
/* search device tree for vty nodes */
|
||||
for (vty = of_find_compatible_node(NULL, "serial", "hvterm-protocol");
|
||||
vty != NULL;
|
||||
vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) {
|
||||
for_each_compatible_node(vty, "serial", "hvterm-protocol") {
|
||||
struct hvsi_struct *hp;
|
||||
const uint32_t *vtermno, *irq;
|
||||
|
||||
|
@@ -106,7 +106,7 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp)
|
||||
|
||||
tty->port.tty = linux_tty;
|
||||
linux_tty->driver_data = tty;
|
||||
linux_tty->low_latency = 1;
|
||||
tty->port.low_latency = 1;
|
||||
|
||||
if (tty->tty_type == TTYTYPE_MODEM)
|
||||
ipwireless_ppp_open(tty->network);
|
||||
@@ -160,15 +160,9 @@ static void ipw_close(struct tty_struct *linux_tty, struct file *filp)
|
||||
void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
|
||||
unsigned int length)
|
||||
{
|
||||
struct tty_struct *linux_tty;
|
||||
int work = 0;
|
||||
|
||||
mutex_lock(&tty->ipw_tty_mutex);
|
||||
linux_tty = tty->port.tty;
|
||||
if (linux_tty == NULL) {
|
||||
mutex_unlock(&tty->ipw_tty_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tty->port.count) {
|
||||
mutex_unlock(&tty->ipw_tty_mutex);
|
||||
@@ -176,7 +170,7 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
|
||||
}
|
||||
mutex_unlock(&tty->ipw_tty_mutex);
|
||||
|
||||
work = tty_insert_flip_string(linux_tty, data, length);
|
||||
work = tty_insert_flip_string(&tty->port, data, length);
|
||||
|
||||
if (work != length)
|
||||
printk(KERN_DEBUG IPWIRELESS_PCCARD_NAME
|
||||
@@ -187,7 +181,7 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data,
|
||||
* This may sleep if ->low_latency is set
|
||||
*/
|
||||
if (work)
|
||||
tty_flip_buffer_push(linux_tty);
|
||||
tty_flip_buffer_push(&tty->port);
|
||||
}
|
||||
|
||||
static void ipw_write_packet_sent_callback(void *callback_data,
|
||||
|
@@ -634,10 +634,10 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
|
||||
break;
|
||||
|
||||
case 1: /* Received Break !!! */
|
||||
tty_insert_flip_char(tty, 0, TTY_BREAK);
|
||||
tty_insert_flip_char(&port->port, 0, TTY_BREAK);
|
||||
if (port->port.flags & ASYNC_SAK)
|
||||
do_SAK(tty);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
break;
|
||||
|
||||
case 2: /* Statistics */
|
||||
@@ -650,15 +650,15 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
|
||||
break;
|
||||
}
|
||||
} else { /* Data Packet */
|
||||
|
||||
count = tty_prepare_flip_string(tty, &rp, byte_count & ~1);
|
||||
count = tty_prepare_flip_string(&port->port, &rp,
|
||||
byte_count & ~1);
|
||||
pr_debug("%s: Can rx %d of %d bytes.\n",
|
||||
__func__, count, byte_count);
|
||||
word_count = count >> 1;
|
||||
insw(base, rp, word_count);
|
||||
byte_count -= (word_count << 1);
|
||||
if (count & 0x0001) {
|
||||
tty_insert_flip_char(tty, inw(base) & 0xff,
|
||||
tty_insert_flip_char(&port->port, inw(base) & 0xff,
|
||||
TTY_NORMAL);
|
||||
byte_count -= 2;
|
||||
}
|
||||
@@ -671,7 +671,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id)
|
||||
byte_count -= 2;
|
||||
}
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
}
|
||||
outw(0x0000, base+0x04); /* enable interrupts */
|
||||
spin_unlock(&card->card_lock);
|
||||
|
677
drivers/tty/metag_da.c
Normal file
677
drivers/tty/metag_da.c
Normal file
@@ -0,0 +1,677 @@
|
||||
/*
|
||||
* dashtty.c - tty driver for Dash channels interface.
|
||||
*
|
||||
* Copyright (C) 2007,2008,2012 Imagination Technologies
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file COPYING in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/da.h>
|
||||
|
||||
/* Channel error codes */
|
||||
#define CONAOK 0
|
||||
#define CONERR 1
|
||||
#define CONBAD 2
|
||||
#define CONPRM 3
|
||||
#define CONADR 4
|
||||
#define CONCNT 5
|
||||
#define CONCBF 6
|
||||
#define CONCBE 7
|
||||
#define CONBSY 8
|
||||
|
||||
/* Default channel for the console */
|
||||
#define CONSOLE_CHANNEL 1
|
||||
|
||||
#define NUM_TTY_CHANNELS 6
|
||||
|
||||
/* Auto allocate */
|
||||
#define DA_TTY_MAJOR 0
|
||||
|
||||
/* A speedy poll rate helps the userland debug process connection response.
|
||||
* But, if you set it too high then no other userland processes get much
|
||||
* of a look in.
|
||||
*/
|
||||
#define DA_TTY_POLL (HZ / 50)
|
||||
|
||||
/*
|
||||
* A short put delay improves latency but has a high throughput overhead
|
||||
*/
|
||||
#define DA_TTY_PUT_DELAY (HZ / 100)
|
||||
|
||||
static atomic_t num_channels_need_poll = ATOMIC_INIT(0);
|
||||
|
||||
static struct timer_list poll_timer;
|
||||
|
||||
static struct tty_driver *channel_driver;
|
||||
|
||||
static struct timer_list put_timer;
|
||||
static struct task_struct *dashtty_thread;
|
||||
|
||||
#define RX_BUF_SIZE 1024
|
||||
|
||||
enum {
|
||||
INCHR = 1,
|
||||
OUTCHR,
|
||||
RDBUF,
|
||||
WRBUF,
|
||||
RDSTAT
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dashtty_port - Wrapper struct for dashtty tty_port.
|
||||
* @port: TTY port data
|
||||
* @rx_lock: Lock for rx_buf.
|
||||
* This protects between the poll timer and user context.
|
||||
* It's also held during read SWITCH operations.
|
||||
* @rx_buf: Read buffer
|
||||
* @xmit_lock: Lock for xmit_*, and port.xmit_buf.
|
||||
* This protects between user context and kernel thread.
|
||||
* It's also held during write SWITCH operations.
|
||||
* @xmit_cnt: Size of xmit buffer contents
|
||||
* @xmit_head: Head of xmit buffer where data is written
|
||||
* @xmit_tail: Tail of xmit buffer where data is read
|
||||
* @xmit_empty: Completion for xmit buffer being empty
|
||||
*/
|
||||
struct dashtty_port {
|
||||
struct tty_port port;
|
||||
spinlock_t rx_lock;
|
||||
void *rx_buf;
|
||||
struct mutex xmit_lock;
|
||||
unsigned int xmit_cnt;
|
||||
unsigned int xmit_head;
|
||||
unsigned int xmit_tail;
|
||||
struct completion xmit_empty;
|
||||
};
|
||||
|
||||
static struct dashtty_port dashtty_ports[NUM_TTY_CHANNELS];
|
||||
|
||||
static atomic_t dashtty_xmit_cnt = ATOMIC_INIT(0);
|
||||
static wait_queue_head_t dashtty_waitqueue;
|
||||
|
||||
/*
|
||||
* Low-level DA channel access routines
|
||||
*/
|
||||
static int chancall(int in_bios_function, int in_channel,
|
||||
int in_arg2, void *in_arg3,
|
||||
void *in_arg4)
|
||||
{
|
||||
register int bios_function asm("D1Ar1") = in_bios_function;
|
||||
register int channel asm("D0Ar2") = in_channel;
|
||||
register int arg2 asm("D1Ar3") = in_arg2;
|
||||
register void *arg3 asm("D0Ar4") = in_arg3;
|
||||
register void *arg4 asm("D1Ar5") = in_arg4;
|
||||
register int bios_call asm("D0Ar6") = 3;
|
||||
register int result asm("D0Re0");
|
||||
|
||||
asm volatile (
|
||||
"MSETL [A0StP++], %6,%4,%2\n\t"
|
||||
"ADD A0StP, A0StP, #8\n\t"
|
||||
"SWITCH #0x0C30208\n\t"
|
||||
"GETD %0, [A0StP+#-8]\n\t"
|
||||
"SUB A0StP, A0StP, #(4*6)+8\n\t"
|
||||
: "=d" (result) /* outs */
|
||||
: "d" (bios_function),
|
||||
"d" (channel),
|
||||
"d" (arg2),
|
||||
"d" (arg3),
|
||||
"d" (arg4),
|
||||
"d" (bios_call) /* ins */
|
||||
: "memory");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempts to fetch count bytes from channel and returns actual count.
|
||||
*/
|
||||
static int fetch_data(unsigned int channel)
|
||||
{
|
||||
struct dashtty_port *dport = &dashtty_ports[channel];
|
||||
int received = 0;
|
||||
|
||||
spin_lock_bh(&dport->rx_lock);
|
||||
/* check the port isn't being shut down */
|
||||
if (!dport->rx_buf)
|
||||
goto unlock;
|
||||
if (chancall(RDBUF, channel, RX_BUF_SIZE,
|
||||
(void *)dport->rx_buf, &received) == CONAOK) {
|
||||
if (received) {
|
||||
int space;
|
||||
unsigned char *cbuf;
|
||||
|
||||
space = tty_prepare_flip_string(&dport->port, &cbuf,
|
||||
received);
|
||||
|
||||
if (space <= 0)
|
||||
goto unlock;
|
||||
|
||||
memcpy(cbuf, dport->rx_buf, space);
|
||||
tty_flip_buffer_push(&dport->port);
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
spin_unlock_bh(&dport->rx_lock);
|
||||
|
||||
return received;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_channel_to_poll() - Returns number of the next channel to poll.
|
||||
* Returns: The number of the next channel to poll, or -1 if none need
|
||||
* polling.
|
||||
*/
|
||||
static int find_channel_to_poll(void)
|
||||
{
|
||||
static int last_polled_channel;
|
||||
int last = last_polled_channel;
|
||||
int chan;
|
||||
struct dashtty_port *dport;
|
||||
|
||||
for (chan = last + 1; ; ++chan) {
|
||||
if (chan >= NUM_TTY_CHANNELS)
|
||||
chan = 0;
|
||||
|
||||
dport = &dashtty_ports[chan];
|
||||
if (dport->rx_buf) {
|
||||
last_polled_channel = chan;
|
||||
return chan;
|
||||
}
|
||||
|
||||
if (chan == last)
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* put_channel_data() - Write out a block of channel data.
|
||||
* @chan: DA channel number.
|
||||
*
|
||||
* Write a single block of data out to the debug adapter. If the circular buffer
|
||||
* is wrapped then only the first block is written.
|
||||
*
|
||||
* Returns: 1 if the remote buffer was too full to accept data.
|
||||
* 0 otherwise.
|
||||
*/
|
||||
static int put_channel_data(unsigned int chan)
|
||||
{
|
||||
struct dashtty_port *dport;
|
||||
struct tty_struct *tty;
|
||||
int number_written;
|
||||
unsigned int count = 0;
|
||||
|
||||
dport = &dashtty_ports[chan];
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
if (dport->xmit_cnt) {
|
||||
count = min((unsigned int)(SERIAL_XMIT_SIZE - dport->xmit_tail),
|
||||
dport->xmit_cnt);
|
||||
chancall(WRBUF, chan, count,
|
||||
dport->port.xmit_buf + dport->xmit_tail,
|
||||
&number_written);
|
||||
dport->xmit_cnt -= number_written;
|
||||
if (!dport->xmit_cnt) {
|
||||
/* reset pointers to avoid wraps */
|
||||
dport->xmit_head = 0;
|
||||
dport->xmit_tail = 0;
|
||||
complete(&dport->xmit_empty);
|
||||
} else {
|
||||
dport->xmit_tail += number_written;
|
||||
if (dport->xmit_tail >= SERIAL_XMIT_SIZE)
|
||||
dport->xmit_tail -= SERIAL_XMIT_SIZE;
|
||||
}
|
||||
atomic_sub(number_written, &dashtty_xmit_cnt);
|
||||
}
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
|
||||
/* if we've made more data available, wake up tty */
|
||||
if (count && number_written) {
|
||||
tty = tty_port_tty_get(&dport->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
/* did the write fail? */
|
||||
return count && !number_written;
|
||||
}
|
||||
|
||||
/**
|
||||
* put_data() - Kernel thread to write out blocks of channel data to DA.
|
||||
* @arg: Unused.
|
||||
*
|
||||
* This kernel thread runs while @dashtty_xmit_cnt != 0, and loops over the
|
||||
* channels to write out any buffered data. If any of the channels stall due to
|
||||
* the remote buffer being full, a hold off happens to allow the debugger to
|
||||
* drain the buffer.
|
||||
*/
|
||||
static int put_data(void *arg)
|
||||
{
|
||||
unsigned int chan, stall;
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
while (!kthread_should_stop()) {
|
||||
/*
|
||||
* For each channel see if there's anything to transmit in the
|
||||
* port's xmit_buf.
|
||||
*/
|
||||
stall = 0;
|
||||
for (chan = 0; chan < NUM_TTY_CHANNELS; ++chan)
|
||||
stall += put_channel_data(chan);
|
||||
|
||||
/*
|
||||
* If some of the buffers are full, hold off for a short while
|
||||
* to allow them to empty.
|
||||
*/
|
||||
if (stall)
|
||||
msleep(25);
|
||||
|
||||
wait_event_interruptible(dashtty_waitqueue,
|
||||
atomic_read(&dashtty_xmit_cnt));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This gets called every DA_TTY_POLL and polls the channels for data
|
||||
*/
|
||||
static void dashtty_timer(unsigned long ignored)
|
||||
{
|
||||
int channel;
|
||||
|
||||
/* If there are no ports open do nothing and don't poll again. */
|
||||
if (!atomic_read(&num_channels_need_poll))
|
||||
return;
|
||||
|
||||
channel = find_channel_to_poll();
|
||||
|
||||
/* Did we find a channel to poll? */
|
||||
if (channel >= 0)
|
||||
fetch_data(channel);
|
||||
|
||||
mod_timer_pinned(&poll_timer, jiffies + DA_TTY_POLL);
|
||||
}
|
||||
|
||||
static void add_poll_timer(struct timer_list *poll_timer)
|
||||
{
|
||||
setup_timer(poll_timer, dashtty_timer, 0);
|
||||
poll_timer->expires = jiffies + DA_TTY_POLL;
|
||||
|
||||
/*
|
||||
* Always attach the timer to the boot CPU. The DA channels are per-CPU
|
||||
* so all polling should be from a single CPU.
|
||||
*/
|
||||
add_timer_on(poll_timer, 0);
|
||||
}
|
||||
|
||||
static int dashtty_port_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
struct dashtty_port *dport = container_of(port, struct dashtty_port,
|
||||
port);
|
||||
void *rx_buf;
|
||||
|
||||
/* Allocate the buffer we use for writing data */
|
||||
if (tty_port_alloc_xmit_buf(port) < 0)
|
||||
goto err;
|
||||
|
||||
/* Allocate the buffer we use for reading data */
|
||||
rx_buf = kzalloc(RX_BUF_SIZE, GFP_KERNEL);
|
||||
if (!rx_buf)
|
||||
goto err_free_xmit;
|
||||
|
||||
spin_lock_bh(&dport->rx_lock);
|
||||
dport->rx_buf = rx_buf;
|
||||
spin_unlock_bh(&dport->rx_lock);
|
||||
|
||||
/*
|
||||
* Don't add the poll timer if we're opening a console. This
|
||||
* avoids the overhead of polling the Dash but means it is not
|
||||
* possible to have a login on /dev/console.
|
||||
*
|
||||
*/
|
||||
if (dport != &dashtty_ports[CONSOLE_CHANNEL])
|
||||
if (atomic_inc_return(&num_channels_need_poll) == 1)
|
||||
add_poll_timer(&poll_timer);
|
||||
|
||||
return 0;
|
||||
err_free_xmit:
|
||||
tty_port_free_xmit_buf(port);
|
||||
err:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void dashtty_port_shutdown(struct tty_port *port)
|
||||
{
|
||||
struct dashtty_port *dport = container_of(port, struct dashtty_port,
|
||||
port);
|
||||
void *rx_buf;
|
||||
unsigned int count;
|
||||
|
||||
/* stop reading */
|
||||
if (dport != &dashtty_ports[CONSOLE_CHANNEL])
|
||||
if (atomic_dec_and_test(&num_channels_need_poll))
|
||||
del_timer_sync(&poll_timer);
|
||||
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
count = dport->xmit_cnt;
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
if (count) {
|
||||
/*
|
||||
* There's still data to write out, so wake and wait for the
|
||||
* writer thread to drain the buffer.
|
||||
*/
|
||||
del_timer(&put_timer);
|
||||
wake_up_interruptible(&dashtty_waitqueue);
|
||||
wait_for_completion(&dport->xmit_empty);
|
||||
}
|
||||
|
||||
/* Null the read buffer (timer could still be running!) */
|
||||
spin_lock_bh(&dport->rx_lock);
|
||||
rx_buf = dport->rx_buf;
|
||||
dport->rx_buf = NULL;
|
||||
spin_unlock_bh(&dport->rx_lock);
|
||||
/* Free the read buffer */
|
||||
kfree(rx_buf);
|
||||
|
||||
/* Free the write buffer */
|
||||
tty_port_free_xmit_buf(port);
|
||||
}
|
||||
|
||||
static const struct tty_port_operations dashtty_port_ops = {
|
||||
.activate = dashtty_port_activate,
|
||||
.shutdown = dashtty_port_shutdown,
|
||||
};
|
||||
|
||||
static int dashtty_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
return tty_port_install(&dashtty_ports[tty->index].port, driver, tty);
|
||||
}
|
||||
|
||||
static int dashtty_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
return tty_port_open(tty->port, tty, filp);
|
||||
}
|
||||
|
||||
static void dashtty_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
return tty_port_close(tty->port, tty, filp);
|
||||
}
|
||||
|
||||
static void dashtty_hangup(struct tty_struct *tty)
|
||||
{
|
||||
int channel;
|
||||
struct dashtty_port *dport;
|
||||
|
||||
channel = tty->index;
|
||||
dport = &dashtty_ports[channel];
|
||||
|
||||
/* drop any data in the xmit buffer */
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
if (dport->xmit_cnt) {
|
||||
atomic_sub(dport->xmit_cnt, &dashtty_xmit_cnt);
|
||||
dport->xmit_cnt = 0;
|
||||
dport->xmit_head = 0;
|
||||
dport->xmit_tail = 0;
|
||||
complete(&dport->xmit_empty);
|
||||
}
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
|
||||
tty_port_hangup(tty->port);
|
||||
}
|
||||
|
||||
/**
|
||||
* dashtty_put_timer() - Delayed wake up of kernel thread.
|
||||
* @ignored: unused
|
||||
*
|
||||
* This timer function wakes up the kernel thread if any data exists in the
|
||||
* buffers. It is used to delay the expensive writeout until the writer has
|
||||
* stopped writing.
|
||||
*/
|
||||
static void dashtty_put_timer(unsigned long ignored)
|
||||
{
|
||||
if (atomic_read(&dashtty_xmit_cnt))
|
||||
wake_up_interruptible(&dashtty_waitqueue);
|
||||
}
|
||||
|
||||
static int dashtty_write(struct tty_struct *tty, const unsigned char *buf,
|
||||
int total)
|
||||
{
|
||||
int channel, count, block;
|
||||
struct dashtty_port *dport;
|
||||
|
||||
/* Determine the channel */
|
||||
channel = tty->index;
|
||||
dport = &dashtty_ports[channel];
|
||||
|
||||
/*
|
||||
* Write to output buffer.
|
||||
*
|
||||
* The reason that we asynchronously write the buffer is because if we
|
||||
* were to write the buffer synchronously then because DA channels are
|
||||
* per-CPU the buffer would be written to the channel of whatever CPU
|
||||
* we're running on.
|
||||
*
|
||||
* What we actually want to happen is have all input and output done on
|
||||
* one CPU.
|
||||
*/
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
/* work out how many bytes we can write to the xmit buffer */
|
||||
total = min(total, (int)(SERIAL_XMIT_SIZE - dport->xmit_cnt));
|
||||
atomic_add(total, &dashtty_xmit_cnt);
|
||||
dport->xmit_cnt += total;
|
||||
/* write the actual bytes (may need splitting if it wraps) */
|
||||
for (count = total; count; count -= block) {
|
||||
block = min(count, (int)(SERIAL_XMIT_SIZE - dport->xmit_head));
|
||||
memcpy(dport->port.xmit_buf + dport->xmit_head, buf, block);
|
||||
dport->xmit_head += block;
|
||||
if (dport->xmit_head >= SERIAL_XMIT_SIZE)
|
||||
dport->xmit_head -= SERIAL_XMIT_SIZE;
|
||||
buf += block;
|
||||
}
|
||||
count = dport->xmit_cnt;
|
||||
/* xmit buffer no longer empty? */
|
||||
if (count)
|
||||
INIT_COMPLETION(dport->xmit_empty);
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
|
||||
if (total) {
|
||||
/*
|
||||
* If the buffer is full, wake up the kthread, otherwise allow
|
||||
* some more time for the buffer to fill up a bit before waking
|
||||
* it.
|
||||
*/
|
||||
if (count == SERIAL_XMIT_SIZE) {
|
||||
del_timer(&put_timer);
|
||||
wake_up_interruptible(&dashtty_waitqueue);
|
||||
} else {
|
||||
mod_timer(&put_timer, jiffies + DA_TTY_PUT_DELAY);
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static int dashtty_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct dashtty_port *dport;
|
||||
int channel;
|
||||
int room;
|
||||
|
||||
channel = tty->index;
|
||||
dport = &dashtty_ports[channel];
|
||||
|
||||
/* report the space in the xmit buffer */
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
room = SERIAL_XMIT_SIZE - dport->xmit_cnt;
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
static int dashtty_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct dashtty_port *dport;
|
||||
int channel;
|
||||
int chars;
|
||||
|
||||
channel = tty->index;
|
||||
dport = &dashtty_ports[channel];
|
||||
|
||||
/* report the number of bytes in the xmit buffer */
|
||||
mutex_lock(&dport->xmit_lock);
|
||||
chars = dport->xmit_cnt;
|
||||
mutex_unlock(&dport->xmit_lock);
|
||||
|
||||
return chars;
|
||||
}
|
||||
|
||||
static const struct tty_operations dashtty_ops = {
|
||||
.install = dashtty_install,
|
||||
.open = dashtty_open,
|
||||
.close = dashtty_close,
|
||||
.hangup = dashtty_hangup,
|
||||
.write = dashtty_write,
|
||||
.write_room = dashtty_write_room,
|
||||
.chars_in_buffer = dashtty_chars_in_buffer,
|
||||
};
|
||||
|
||||
static int __init dashtty_init(void)
|
||||
{
|
||||
int ret;
|
||||
int nport;
|
||||
struct dashtty_port *dport;
|
||||
|
||||
if (!metag_da_enabled())
|
||||
return -ENODEV;
|
||||
|
||||
channel_driver = tty_alloc_driver(NUM_TTY_CHANNELS,
|
||||
TTY_DRIVER_REAL_RAW);
|
||||
if (IS_ERR(channel_driver))
|
||||
return PTR_ERR(channel_driver);
|
||||
|
||||
channel_driver->driver_name = "metag_da";
|
||||
channel_driver->name = "ttyDA";
|
||||
channel_driver->major = DA_TTY_MAJOR;
|
||||
channel_driver->minor_start = 0;
|
||||
channel_driver->type = TTY_DRIVER_TYPE_SERIAL;
|
||||
channel_driver->subtype = SERIAL_TYPE_NORMAL;
|
||||
channel_driver->init_termios = tty_std_termios;
|
||||
channel_driver->init_termios.c_cflag |= CLOCAL;
|
||||
|
||||
tty_set_operations(channel_driver, &dashtty_ops);
|
||||
for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
|
||||
dport = &dashtty_ports[nport];
|
||||
tty_port_init(&dport->port);
|
||||
dport->port.ops = &dashtty_port_ops;
|
||||
spin_lock_init(&dport->rx_lock);
|
||||
mutex_init(&dport->xmit_lock);
|
||||
/* the xmit buffer starts empty, i.e. completely written */
|
||||
init_completion(&dport->xmit_empty);
|
||||
complete(&dport->xmit_empty);
|
||||
}
|
||||
|
||||
setup_timer(&put_timer, dashtty_put_timer, 0);
|
||||
|
||||
init_waitqueue_head(&dashtty_waitqueue);
|
||||
dashtty_thread = kthread_create(put_data, NULL, "ttyDA");
|
||||
if (IS_ERR(dashtty_thread)) {
|
||||
pr_err("Couldn't create dashtty thread\n");
|
||||
ret = PTR_ERR(dashtty_thread);
|
||||
goto err_destroy_ports;
|
||||
}
|
||||
/*
|
||||
* Bind the writer thread to the boot CPU so it can't migrate.
|
||||
* DA channels are per-CPU and we want all channel I/O to be on a single
|
||||
* predictable CPU.
|
||||
*/
|
||||
kthread_bind(dashtty_thread, 0);
|
||||
wake_up_process(dashtty_thread);
|
||||
|
||||
ret = tty_register_driver(channel_driver);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_err("Couldn't install dashtty driver: err %d\n",
|
||||
ret);
|
||||
goto err_stop_kthread;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_stop_kthread:
|
||||
kthread_stop(dashtty_thread);
|
||||
err_destroy_ports:
|
||||
for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
|
||||
dport = &dashtty_ports[nport];
|
||||
tty_port_destroy(&dport->port);
|
||||
}
|
||||
put_tty_driver(channel_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dashtty_exit(void)
|
||||
{
|
||||
int nport;
|
||||
struct dashtty_port *dport;
|
||||
|
||||
del_timer_sync(&put_timer);
|
||||
kthread_stop(dashtty_thread);
|
||||
del_timer_sync(&poll_timer);
|
||||
tty_unregister_driver(channel_driver);
|
||||
for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) {
|
||||
dport = &dashtty_ports[nport];
|
||||
tty_port_destroy(&dport->port);
|
||||
}
|
||||
put_tty_driver(channel_driver);
|
||||
}
|
||||
|
||||
module_init(dashtty_init);
|
||||
module_exit(dashtty_exit);
|
||||
|
||||
#ifdef CONFIG_DA_CONSOLE
|
||||
|
||||
static void dash_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
int actually_written;
|
||||
|
||||
chancall(WRBUF, CONSOLE_CHANNEL, count, (void *)s, &actually_written);
|
||||
}
|
||||
|
||||
static struct tty_driver *dash_console_device(struct console *c, int *index)
|
||||
{
|
||||
*index = c->index;
|
||||
return channel_driver;
|
||||
}
|
||||
|
||||
struct console dash_console = {
|
||||
.name = "ttyDA",
|
||||
.write = dash_console_write,
|
||||
.device = dash_console_device,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = 1,
|
||||
};
|
||||
|
||||
#endif
|
@@ -1405,7 +1405,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
||||
if (inited && !test_bit(TTY_THROTTLED, &tty->flags) &&
|
||||
MoxaPortRxQueue(p) > 0) { /* RX */
|
||||
MoxaPortReadData(p);
|
||||
tty_schedule_flip(tty);
|
||||
tty_schedule_flip(&p->port);
|
||||
}
|
||||
} else {
|
||||
clear_bit(EMPTYWAIT, &p->statusflags);
|
||||
@@ -1429,8 +1429,8 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
|
||||
goto put;
|
||||
|
||||
if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
|
||||
tty_insert_flip_char(tty, 0, TTY_BREAK);
|
||||
tty_schedule_flip(tty);
|
||||
tty_insert_flip_char(&p->port, 0, TTY_BREAK);
|
||||
tty_schedule_flip(&p->port);
|
||||
}
|
||||
|
||||
if (intr & IntrLine)
|
||||
@@ -1966,7 +1966,7 @@ static int MoxaPortReadData(struct moxa_port *port)
|
||||
ofs = baseAddr + DynPage_addr + bufhead + head;
|
||||
len = (tail >= head) ? (tail - head) :
|
||||
(rx_mask + 1 - head);
|
||||
len = tty_prepare_flip_string(tty, &dst,
|
||||
len = tty_prepare_flip_string(&port->port, &dst,
|
||||
min(len, count));
|
||||
memcpy_fromio(dst, ofs, len);
|
||||
head = (head + len) & rx_mask;
|
||||
@@ -1978,7 +1978,7 @@ static int MoxaPortReadData(struct moxa_port *port)
|
||||
while (count > 0) {
|
||||
writew(pageno, baseAddr + Control_reg);
|
||||
ofs = baseAddr + DynPage_addr + pageofs;
|
||||
len = tty_prepare_flip_string(tty, &dst,
|
||||
len = tty_prepare_flip_string(&port->port, &dst,
|
||||
min(Page_size - pageofs, count));
|
||||
memcpy_fromio(dst, ofs, len);
|
||||
|
||||
|
@@ -1264,7 +1264,7 @@ static int mxser_set_serial_info(struct tty_struct *tty,
|
||||
(new_serial.flags & ASYNC_FLAGS));
|
||||
port->close_delay = new_serial.close_delay * HZ / 100;
|
||||
port->closing_wait = new_serial.closing_wait * HZ / 100;
|
||||
tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
port->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST &&
|
||||
(new_serial.baud_base != info->baud_base ||
|
||||
new_serial.custom_divisor !=
|
||||
@@ -2079,7 +2079,7 @@ static void mxser_receive_chars(struct tty_struct *tty,
|
||||
}
|
||||
while (gdl--) {
|
||||
ch = inb(port->ioaddr + UART_RX);
|
||||
tty_insert_flip_char(tty, ch, 0);
|
||||
tty_insert_flip_char(&port->port, ch, 0);
|
||||
cnt++;
|
||||
}
|
||||
goto end_intr;
|
||||
@@ -2118,7 +2118,7 @@ intr_old:
|
||||
} else
|
||||
flag = TTY_BREAK;
|
||||
}
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(&port->port, ch, flag);
|
||||
cnt++;
|
||||
if (cnt >= recv_room) {
|
||||
if (!port->ldisc_stop_rx)
|
||||
@@ -2145,7 +2145,7 @@ end_intr:
|
||||
* recursive locking.
|
||||
*/
|
||||
spin_unlock(&port->slock);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->port);
|
||||
spin_lock(&port->slock);
|
||||
}
|
||||
|
||||
@@ -2364,7 +2364,6 @@ static void mxser_release_vector(struct mxser_board *brd)
|
||||
|
||||
static void mxser_release_ISA_res(struct mxser_board *brd)
|
||||
{
|
||||
free_irq(brd->irq, brd);
|
||||
release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
|
||||
mxser_release_vector(brd);
|
||||
}
|
||||
@@ -2430,6 +2429,7 @@ static void mxser_board_remove(struct mxser_board *brd)
|
||||
tty_unregister_device(mxvar_sdriver, brd->idx + i);
|
||||
tty_port_destroy(&brd->ports[i].port);
|
||||
}
|
||||
free_irq(brd->irq, brd);
|
||||
}
|
||||
|
||||
static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
|
||||
@@ -2554,6 +2554,7 @@ static int mxser_probe(struct pci_dev *pdev,
|
||||
struct mxser_board *brd;
|
||||
unsigned int i, j;
|
||||
unsigned long ioaddress;
|
||||
struct device *tty_dev;
|
||||
int retval = -EINVAL;
|
||||
|
||||
for (i = 0; i < MXSER_BOARDS; i++)
|
||||
@@ -2637,13 +2638,25 @@ static int mxser_probe(struct pci_dev *pdev,
|
||||
if (retval)
|
||||
goto err_rel3;
|
||||
|
||||
for (i = 0; i < brd->info->nports; i++)
|
||||
tty_port_register_device(&brd->ports[i].port, mxvar_sdriver,
|
||||
brd->idx + i, &pdev->dev);
|
||||
for (i = 0; i < brd->info->nports; i++) {
|
||||
tty_dev = tty_port_register_device(&brd->ports[i].port,
|
||||
mxvar_sdriver, brd->idx + i, &pdev->dev);
|
||||
if (IS_ERR(tty_dev)) {
|
||||
retval = PTR_ERR(tty_dev);
|
||||
for (i--; i >= 0; i--)
|
||||
tty_unregister_device(mxvar_sdriver,
|
||||
brd->idx + i);
|
||||
goto err_relbrd;
|
||||
}
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, brd);
|
||||
|
||||
return 0;
|
||||
err_relbrd:
|
||||
for (i = 0; i < brd->info->nports; i++)
|
||||
tty_port_destroy(&brd->ports[i].port);
|
||||
free_irq(brd->irq, brd);
|
||||
err_rel3:
|
||||
pci_release_region(pdev, 3);
|
||||
err_zero:
|
||||
@@ -2665,7 +2678,6 @@ static void mxser_remove(struct pci_dev *pdev)
|
||||
|
||||
mxser_board_remove(brd);
|
||||
|
||||
free_irq(pdev->irq, brd);
|
||||
pci_release_region(pdev, 2);
|
||||
pci_release_region(pdev, 3);
|
||||
pci_disable_device(pdev);
|
||||
@@ -2683,6 +2695,7 @@ static struct pci_driver mxser_driver = {
|
||||
static int __init mxser_module_init(void)
|
||||
{
|
||||
struct mxser_board *brd;
|
||||
struct device *tty_dev;
|
||||
unsigned int b, i, m;
|
||||
int retval;
|
||||
|
||||
@@ -2728,14 +2741,29 @@ static int __init mxser_module_init(void)
|
||||
|
||||
/* mxser_initbrd will hook ISR. */
|
||||
if (mxser_initbrd(brd, NULL) < 0) {
|
||||
mxser_release_ISA_res(brd);
|
||||
brd->info = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
brd->idx = m * MXSER_PORTS_PER_BOARD;
|
||||
for (i = 0; i < brd->info->nports; i++)
|
||||
tty_port_register_device(&brd->ports[i].port,
|
||||
for (i = 0; i < brd->info->nports; i++) {
|
||||
tty_dev = tty_port_register_device(&brd->ports[i].port,
|
||||
mxvar_sdriver, brd->idx + i, NULL);
|
||||
if (IS_ERR(tty_dev)) {
|
||||
for (i--; i >= 0; i--)
|
||||
tty_unregister_device(mxvar_sdriver,
|
||||
brd->idx + i);
|
||||
for (i = 0; i < brd->info->nports; i++)
|
||||
tty_port_destroy(&brd->ports[i].port);
|
||||
free_irq(brd->irq, brd);
|
||||
mxser_release_ISA_res(brd);
|
||||
brd->info = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (brd->info == NULL)
|
||||
continue;
|
||||
|
||||
m++;
|
||||
}
|
||||
|
@@ -1067,9 +1067,9 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
|
||||
if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
|
||||
if (!(tty->termios.c_cflag & CLOCAL))
|
||||
tty_hangup(tty);
|
||||
if (brk & 0x01)
|
||||
tty_insert_flip_char(tty, 0, TTY_BREAK);
|
||||
}
|
||||
if (brk & 0x01)
|
||||
tty_insert_flip_char(&dlci->port, 0, TTY_BREAK);
|
||||
dlci->modem_rx = mlines;
|
||||
}
|
||||
|
||||
@@ -1137,7 +1137,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
|
||||
|
||||
static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port;
|
||||
unsigned int addr = 0 ;
|
||||
u8 bits;
|
||||
int len = clen;
|
||||
@@ -1160,19 +1160,18 @@ static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
|
||||
bits = *dp;
|
||||
if ((bits & 1) == 0)
|
||||
return;
|
||||
/* See if we have an uplink tty */
|
||||
tty = tty_port_tty_get(&gsm->dlci[addr]->port);
|
||||
|
||||
if (tty) {
|
||||
if (bits & 2)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
if (bits & 4)
|
||||
tty_insert_flip_char(tty, 0, TTY_PARITY);
|
||||
if (bits & 8)
|
||||
tty_insert_flip_char(tty, 0, TTY_FRAME);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
port = &gsm->dlci[addr]->port;
|
||||
|
||||
if (bits & 2)
|
||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||
if (bits & 4)
|
||||
tty_insert_flip_char(port, 0, TTY_PARITY);
|
||||
if (bits & 8)
|
||||
tty_insert_flip_char(port, 0, TTY_FRAME);
|
||||
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
gsm_control_reply(gsm, CMD_RLS, data, clen);
|
||||
}
|
||||
|
||||
@@ -1545,36 +1544,37 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen)
|
||||
{
|
||||
/* krefs .. */
|
||||
struct tty_port *port = &dlci->port;
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
struct tty_struct *tty;
|
||||
unsigned int modem = 0;
|
||||
int len = clen;
|
||||
|
||||
if (debug & 16)
|
||||
pr_debug("%d bytes for tty %p\n", len, tty);
|
||||
if (tty) {
|
||||
switch (dlci->adaption) {
|
||||
/* Unsupported types */
|
||||
/* Packetised interruptible data */
|
||||
case 4:
|
||||
break;
|
||||
/* Packetised uininterruptible voice/data */
|
||||
case 3:
|
||||
break;
|
||||
/* Asynchronous serial with line state in each frame */
|
||||
case 2:
|
||||
while (gsm_read_ea(&modem, *data++) == 0) {
|
||||
len--;
|
||||
if (len == 0)
|
||||
return;
|
||||
}
|
||||
gsm_process_modem(tty, dlci, modem, clen);
|
||||
/* Line state will go via DLCI 0 controls only */
|
||||
case 1:
|
||||
default:
|
||||
tty_insert_flip_string(tty, data, len);
|
||||
tty_flip_buffer_push(tty);
|
||||
pr_debug("%d bytes for tty\n", len);
|
||||
switch (dlci->adaption) {
|
||||
/* Unsupported types */
|
||||
/* Packetised interruptible data */
|
||||
case 4:
|
||||
break;
|
||||
/* Packetised uininterruptible voice/data */
|
||||
case 3:
|
||||
break;
|
||||
/* Asynchronous serial with line state in each frame */
|
||||
case 2:
|
||||
while (gsm_read_ea(&modem, *data++) == 0) {
|
||||
len--;
|
||||
if (len == 0)
|
||||
return;
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
tty = tty_port_tty_get(port);
|
||||
if (tty) {
|
||||
gsm_process_modem(tty, dlci, modem, clen);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
/* Line state will go via DLCI 0 controls only */
|
||||
case 1:
|
||||
default:
|
||||
tty_insert_flip_string(port, data, len);
|
||||
tty_flip_buffer_push(port);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1689,6 +1689,8 @@ static inline void dlci_put(struct gsm_dlci *dlci)
|
||||
tty_port_put(&dlci->port);
|
||||
}
|
||||
|
||||
static void gsm_destroy_network(struct gsm_dlci *dlci);
|
||||
|
||||
/**
|
||||
* gsm_dlci_release - release DLCI
|
||||
* @dlci: DLCI to destroy
|
||||
@@ -1702,9 +1704,19 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&dlci->port);
|
||||
if (tty) {
|
||||
mutex_lock(&dlci->mutex);
|
||||
gsm_destroy_network(dlci);
|
||||
mutex_unlock(&dlci->mutex);
|
||||
|
||||
/* tty_vhangup needs the tty_lock, so unlock and
|
||||
relock after doing the hangup. */
|
||||
tty_unlock(tty);
|
||||
tty_vhangup(tty);
|
||||
tty_lock(tty);
|
||||
tty_port_tty_set(&dlci->port, NULL);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
dlci->state = DLCI_CLOSED;
|
||||
dlci_put(dlci);
|
||||
}
|
||||
|
||||
@@ -2947,6 +2959,8 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
|
||||
|
||||
if (dlci == NULL)
|
||||
return;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
mutex_lock(&dlci->mutex);
|
||||
gsm_destroy_network(dlci);
|
||||
mutex_unlock(&dlci->mutex);
|
||||
@@ -2965,6 +2979,8 @@ out:
|
||||
static void gsmtty_hangup(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
tty_port_hangup(&dlci->port);
|
||||
gsm_dlci_begin_close(dlci);
|
||||
}
|
||||
@@ -2972,9 +2988,12 @@ static void gsmtty_hangup(struct tty_struct *tty)
|
||||
static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
|
||||
int len)
|
||||
{
|
||||
int sent;
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
/* Stuff the bytes into the fifo queue */
|
||||
int sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
|
||||
sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock);
|
||||
/* Need to kick the channel */
|
||||
gsm_dlci_data_kick(dlci);
|
||||
return sent;
|
||||
@@ -2983,18 +3002,24 @@ static int gsmtty_write(struct tty_struct *tty, const unsigned char *buf,
|
||||
static int gsmtty_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
return TX_SIZE - kfifo_len(dlci->fifo);
|
||||
}
|
||||
|
||||
static int gsmtty_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
return kfifo_len(dlci->fifo);
|
||||
}
|
||||
|
||||
static void gsmtty_flush_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
/* Caution needed: If we implement reliable transport classes
|
||||
then the data being transmitted can't simply be junked once
|
||||
it has first hit the stack. Until then we can just blow it
|
||||
@@ -3013,6 +3038,8 @@ static void gsmtty_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
static int gsmtty_tiocmget(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
return dlci->modem_rx;
|
||||
}
|
||||
|
||||
@@ -3022,6 +3049,8 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
unsigned int modem_tx = dlci->modem_tx;
|
||||
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
modem_tx &= ~clear;
|
||||
modem_tx |= set;
|
||||
|
||||
@@ -3040,6 +3069,8 @@ static int gsmtty_ioctl(struct tty_struct *tty,
|
||||
struct gsm_netconfig nc;
|
||||
int index;
|
||||
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
switch (cmd) {
|
||||
case GSMIOC_ENABLE_NET:
|
||||
if (copy_from_user(&nc, (void __user *)arg, sizeof(nc)))
|
||||
@@ -3066,6 +3097,9 @@ static int gsmtty_ioctl(struct tty_struct *tty,
|
||||
|
||||
static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
/* For the moment its fixed. In actual fact the speed information
|
||||
for the virtual channel can be propogated in both directions by
|
||||
the RPN control message. This however rapidly gets nasty as we
|
||||
@@ -3077,6 +3111,8 @@ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
|
||||
static void gsmtty_throttle(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
dlci->modem_tx &= ~TIOCM_DTR;
|
||||
dlci->throttled = 1;
|
||||
@@ -3087,6 +3123,8 @@ static void gsmtty_throttle(struct tty_struct *tty)
|
||||
static void gsmtty_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return;
|
||||
if (tty->termios.c_cflag & CRTSCTS)
|
||||
dlci->modem_tx |= TIOCM_DTR;
|
||||
dlci->throttled = 0;
|
||||
@@ -3098,6 +3136,8 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
|
||||
{
|
||||
struct gsm_dlci *dlci = tty->driver_data;
|
||||
int encode = 0; /* Off */
|
||||
if (dlci->state == DLCI_CLOSED)
|
||||
return -EINVAL;
|
||||
|
||||
if (state == -1) /* "On indefinitely" - we can't encode this
|
||||
properly */
|
||||
|
@@ -49,6 +49,7 @@
|
||||
#include <linux/file.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
|
||||
/* number of characters left in xmit buffer before select has we have room */
|
||||
@@ -100,7 +101,7 @@ struct n_tty_data {
|
||||
struct mutex atomic_read_lock;
|
||||
struct mutex output_lock;
|
||||
struct mutex echo_lock;
|
||||
spinlock_t read_lock;
|
||||
raw_spinlock_t read_lock;
|
||||
};
|
||||
|
||||
static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
|
||||
@@ -182,9 +183,9 @@ static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
|
||||
* The problem of stomping on the buffers ends here.
|
||||
* Why didn't anyone see this one coming? --AJK
|
||||
*/
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
put_tty_queue_nolock(c, ldata);
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,9 +219,9 @@ static void reset_buffer_flags(struct tty_struct *tty)
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
ldata->read_head = ldata->read_tail = ldata->read_cnt = 0;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
|
||||
mutex_lock(&ldata->echo_lock);
|
||||
ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0;
|
||||
@@ -276,7 +277,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
|
||||
unsigned long flags;
|
||||
ssize_t n = 0;
|
||||
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
if (!ldata->icanon) {
|
||||
n = ldata->read_cnt;
|
||||
} else if (ldata->canon_data) {
|
||||
@@ -284,7 +285,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
|
||||
ldata->canon_head - ldata->read_tail :
|
||||
ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail);
|
||||
}
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -915,19 +916,19 @@ static void eraser(unsigned char c, struct tty_struct *tty)
|
||||
kill_type = WERASE;
|
||||
else {
|
||||
if (!L_ECHO(tty)) {
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
|
||||
(N_TTY_BUF_SIZE - 1));
|
||||
ldata->read_head = ldata->canon_head;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
return;
|
||||
}
|
||||
if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &
|
||||
(N_TTY_BUF_SIZE - 1));
|
||||
ldata->read_head = ldata->canon_head;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
finish_erasing(ldata);
|
||||
echo_char(KILL_CHAR(tty), tty);
|
||||
/* Add a newline if ECHOK is on and ECHOKE is off. */
|
||||
@@ -961,10 +962,10 @@ static void eraser(unsigned char c, struct tty_struct *tty)
|
||||
break;
|
||||
}
|
||||
cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1);
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
ldata->read_head = head;
|
||||
ldata->read_cnt -= cnt;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
if (L_ECHO(tty)) {
|
||||
if (L_ECHOPRT(tty)) {
|
||||
if (!ldata->erasing) {
|
||||
@@ -1344,12 +1345,12 @@ send_signal:
|
||||
put_tty_queue(c, ldata);
|
||||
|
||||
handle_newline:
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
set_bit(ldata->read_head, ldata->read_flags);
|
||||
put_tty_queue_nolock(c, ldata);
|
||||
ldata->canon_head = ldata->read_head;
|
||||
ldata->canon_data++;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
|
||||
if (waitqueue_active(&tty->read_wait))
|
||||
wake_up_interruptible(&tty->read_wait);
|
||||
@@ -1423,7 +1424,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||
unsigned long cpuflags;
|
||||
|
||||
if (ldata->real_raw) {
|
||||
spin_lock_irqsave(&ldata->read_lock, cpuflags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, cpuflags);
|
||||
i = min(N_TTY_BUF_SIZE - ldata->read_cnt,
|
||||
N_TTY_BUF_SIZE - ldata->read_head);
|
||||
i = min(count, i);
|
||||
@@ -1439,7 +1440,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||
memcpy(ldata->read_buf + ldata->read_head, cp, i);
|
||||
ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1);
|
||||
ldata->read_cnt += i;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, cpuflags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, cpuflags);
|
||||
} else {
|
||||
for (i = count, p = cp, f = fp; i; i--, p++) {
|
||||
if (f)
|
||||
@@ -1635,7 +1636,7 @@ static int n_tty_open(struct tty_struct *tty)
|
||||
mutex_init(&ldata->atomic_read_lock);
|
||||
mutex_init(&ldata->output_lock);
|
||||
mutex_init(&ldata->echo_lock);
|
||||
spin_lock_init(&ldata->read_lock);
|
||||
raw_spin_lock_init(&ldata->read_lock);
|
||||
|
||||
/* These are ugly. Currently a malloc failure here can panic */
|
||||
ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
|
||||
@@ -1703,10 +1704,10 @@ static int copy_from_read_buf(struct tty_struct *tty,
|
||||
bool is_eof;
|
||||
|
||||
retval = 0;
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail);
|
||||
n = min(*nr, n);
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
if (n) {
|
||||
retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n);
|
||||
n -= retval;
|
||||
@@ -1714,13 +1715,13 @@ static int copy_from_read_buf(struct tty_struct *tty,
|
||||
ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty);
|
||||
tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n,
|
||||
ldata->icanon);
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1);
|
||||
ldata->read_cnt -= n;
|
||||
/* Turn single EOF into zero-length read */
|
||||
if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt)
|
||||
n = 0;
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
*b += n;
|
||||
*nr -= n;
|
||||
}
|
||||
@@ -1900,7 +1901,7 @@ do_it_again:
|
||||
|
||||
if (ldata->icanon && !L_EXTPROC(tty)) {
|
||||
/* N.B. avoid overrun if nr == 0 */
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
while (nr && ldata->read_cnt) {
|
||||
int eol;
|
||||
|
||||
@@ -1918,25 +1919,25 @@ do_it_again:
|
||||
if (--ldata->canon_data < 0)
|
||||
ldata->canon_data = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
|
||||
if (!eol || (c != __DISABLED_CHAR)) {
|
||||
if (tty_put_user(tty, c, b++)) {
|
||||
retval = -EFAULT;
|
||||
b--;
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
break;
|
||||
}
|
||||
nr--;
|
||||
}
|
||||
if (eol) {
|
||||
tty_audit_push(tty);
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
break;
|
||||
}
|
||||
spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
if (retval)
|
||||
break;
|
||||
} else {
|
||||
@@ -2188,7 +2189,7 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
|
||||
* n_tty_inherit_ops - inherit N_TTY methods
|
||||
* @ops: struct tty_ldisc_ops where to save N_TTY methods
|
||||
*
|
||||
* Used by a generic struct tty_ldisc_ops to easily inherit N_TTY
|
||||
* Enables a 'subclass' line discipline to 'inherit' N_TTY
|
||||
* methods.
|
||||
*/
|
||||
|
||||
|
@@ -827,15 +827,10 @@ static int receive_data(enum port_type index, struct nozomi *dc)
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
int i, ret;
|
||||
|
||||
if (unlikely(!tty)) {
|
||||
DBG1("tty not open for port: %d?", index);
|
||||
return 1;
|
||||
}
|
||||
|
||||
read_mem32((u32 *) &size, addr, 4);
|
||||
/* DBG1( "%d bytes port: %d", size, index); */
|
||||
|
||||
if (test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (tty && test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
DBG1("No room in tty, don't read data, don't ack interrupt, "
|
||||
"disable interrupt");
|
||||
|
||||
@@ -855,13 +850,14 @@ static int receive_data(enum port_type index, struct nozomi *dc)
|
||||
read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX);
|
||||
|
||||
if (size == 1) {
|
||||
tty_insert_flip_char(tty, buf[0], TTY_NORMAL);
|
||||
tty_insert_flip_char(&port->port, buf[0], TTY_NORMAL);
|
||||
size = 0;
|
||||
} else if (size < RECEIVE_BUF_MAX) {
|
||||
size -= tty_insert_flip_string(tty, (char *) buf, size);
|
||||
size -= tty_insert_flip_string(&port->port,
|
||||
(char *)buf, size);
|
||||
} else {
|
||||
i = tty_insert_flip_string(tty, \
|
||||
(char *) buf, RECEIVE_BUF_MAX);
|
||||
i = tty_insert_flip_string(&port->port,
|
||||
(char *)buf, RECEIVE_BUF_MAX);
|
||||
size -= i;
|
||||
offset += i;
|
||||
}
|
||||
@@ -1276,15 +1272,11 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id)
|
||||
|
||||
exit_handler:
|
||||
spin_unlock(&dc->spin_mutex);
|
||||
for (a = 0; a < NOZOMI_MAX_PORTS; a++) {
|
||||
struct tty_struct *tty;
|
||||
if (test_and_clear_bit(a, &dc->flip)) {
|
||||
tty = tty_port_tty_get(&dc->port[a].port);
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
for (a = 0; a < NOZOMI_MAX_PORTS; a++)
|
||||
if (test_and_clear_bit(a, &dc->flip))
|
||||
tty_flip_buffer_push(&dc->port[a].port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
none:
|
||||
spin_unlock(&dc->spin_mutex);
|
||||
@@ -1687,12 +1679,6 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
|
||||
|
||||
rval = kfifo_in(&port->fifo_ul, (unsigned char *)buffer, count);
|
||||
|
||||
/* notify card */
|
||||
if (unlikely(dc == NULL)) {
|
||||
DBG1("No device context?");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dc->spin_mutex, flags);
|
||||
/* CTS is only valid on the modem channel */
|
||||
if (port == &(dc->port[PORT_MDM])) {
|
||||
@@ -1708,7 +1694,6 @@ static int ntty_write(struct tty_struct *tty, const unsigned char *buffer,
|
||||
}
|
||||
spin_unlock_irqrestore(&dc->spin_mutex, flags);
|
||||
|
||||
exit:
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
@@ -38,16 +38,18 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
||||
if (tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
WARN_ON(tty->count > 1);
|
||||
else {
|
||||
if (test_bit(TTY_IO_ERROR, &tty->flags))
|
||||
return;
|
||||
if (tty->count > 2)
|
||||
return;
|
||||
}
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
wake_up_interruptible(&tty->read_wait);
|
||||
wake_up_interruptible(&tty->write_wait);
|
||||
tty->packet = 0;
|
||||
/* Review - krefs on tty_link ?? */
|
||||
if (!tty->link)
|
||||
return;
|
||||
tty->link->packet = 0;
|
||||
set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
|
||||
wake_up_interruptible(&tty->link->read_wait);
|
||||
wake_up_interruptible(&tty->link->write_wait);
|
||||
@@ -55,9 +57,10 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
|
||||
set_bit(TTY_OTHER_CLOSED, &tty->flags);
|
||||
#ifdef CONFIG_UNIX98_PTYS
|
||||
if (tty->driver == ptm_driver) {
|
||||
mutex_lock(&devpts_mutex);
|
||||
devpts_pty_kill(tty->link->driver_data);
|
||||
mutex_unlock(&devpts_mutex);
|
||||
mutex_lock(&devpts_mutex);
|
||||
if (tty->link->driver_data)
|
||||
devpts_pty_kill(tty->link->driver_data);
|
||||
mutex_unlock(&devpts_mutex);
|
||||
}
|
||||
#endif
|
||||
tty_unlock(tty);
|
||||
@@ -120,10 +123,10 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
|
||||
|
||||
if (c > 0) {
|
||||
/* Stuff the data into the input queue of the other end */
|
||||
c = tty_insert_flip_string(to, buf, c);
|
||||
c = tty_insert_flip_string(to->port, buf, c);
|
||||
/* And shovel */
|
||||
if (c) {
|
||||
tty_flip_buffer_push(to);
|
||||
tty_flip_buffer_push(to->port);
|
||||
tty_wakeup(tty);
|
||||
}
|
||||
}
|
||||
@@ -246,14 +249,17 @@ static int pty_open(struct tty_struct *tty, struct file *filp)
|
||||
if (!tty || !tty->link)
|
||||
goto out;
|
||||
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
|
||||
retval = -EIO;
|
||||
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
|
||||
goto out;
|
||||
if (test_bit(TTY_PTY_LOCK, &tty->link->flags))
|
||||
goto out;
|
||||
if (tty->link->count != 1)
|
||||
if (tty->driver->subtype == PTY_TYPE_SLAVE && tty->link->count != 1)
|
||||
goto out;
|
||||
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
clear_bit(TTY_OTHER_CLOSED, &tty->link->flags);
|
||||
set_bit(TTY_THROTTLED, &tty->flags);
|
||||
retval = 0;
|
||||
@@ -663,7 +669,7 @@ static const struct tty_operations pty_unix98_ops = {
|
||||
* Allocate a unix98 pty master device from the ptmx driver.
|
||||
*
|
||||
* Locking: tty_mutex protects the init_dev work. tty->count should
|
||||
* protect the rest.
|
||||
* protect the rest.
|
||||
* allocated_ptys_lock handles the list of free pty numbers
|
||||
*/
|
||||
|
||||
@@ -704,6 +710,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
||||
mutex_unlock(&tty_mutex);
|
||||
|
||||
set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
|
||||
tty->driver_data = inode;
|
||||
|
||||
tty_add_file(tty, filp);
|
||||
|
||||
@@ -714,14 +721,13 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
||||
retval = PTR_ERR(slave_inode);
|
||||
goto err_release;
|
||||
}
|
||||
tty->link->driver_data = slave_inode;
|
||||
|
||||
retval = ptm_driver->ops->open(tty, filp);
|
||||
if (retval)
|
||||
goto err_release;
|
||||
|
||||
tty_unlock(tty);
|
||||
tty->driver_data = inode;
|
||||
tty->link->driver_data = slave_inode;
|
||||
return 0;
|
||||
err_release:
|
||||
tty_unlock(tty);
|
||||
@@ -797,7 +803,7 @@ static void __init unix98_pty_init(void)
|
||||
cdev_init(&ptmx_cdev, &ptmx_fops);
|
||||
if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
|
||||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
|
||||
panic("Couldn't register /dev/ptmx driver\n");
|
||||
panic("Couldn't register /dev/ptmx driver");
|
||||
device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
|
||||
}
|
||||
|
||||
|
@@ -55,7 +55,7 @@
|
||||
#undef REV_PCI_ORDER
|
||||
#undef ROCKET_DEBUG_IO
|
||||
|
||||
#define POLL_PERIOD HZ/100 /* Polling period .01 seconds (10ms) */
|
||||
#define POLL_PERIOD (HZ/100) /* Polling period .01 seconds (10ms) */
|
||||
|
||||
/****** Kernel includes ******/
|
||||
|
||||
@@ -315,9 +315,8 @@ static inline int rocket_paranoia_check(struct r_port *info,
|
||||
* that receive data is present on a serial port. Pulls data from FIFO, moves it into the
|
||||
* tty layer.
|
||||
*/
|
||||
static void rp_do_receive(struct r_port *info,
|
||||
struct tty_struct *tty,
|
||||
CHANNEL_t * cp, unsigned int ChanStatus)
|
||||
static void rp_do_receive(struct r_port *info, CHANNEL_t *cp,
|
||||
unsigned int ChanStatus)
|
||||
{
|
||||
unsigned int CharNStat;
|
||||
int ToRecv, wRecv, space;
|
||||
@@ -379,7 +378,8 @@ static void rp_do_receive(struct r_port *info,
|
||||
flag = TTY_OVERRUN;
|
||||
else
|
||||
flag = TTY_NORMAL;
|
||||
tty_insert_flip_char(tty, CharNStat & 0xff, flag);
|
||||
tty_insert_flip_char(&info->port, CharNStat & 0xff,
|
||||
flag);
|
||||
ToRecv--;
|
||||
}
|
||||
|
||||
@@ -399,7 +399,7 @@ static void rp_do_receive(struct r_port *info,
|
||||
* characters at time by doing repeated word IO
|
||||
* transfer.
|
||||
*/
|
||||
space = tty_prepare_flip_string(tty, &cbuf, ToRecv);
|
||||
space = tty_prepare_flip_string(&info->port, &cbuf, ToRecv);
|
||||
if (space < ToRecv) {
|
||||
#ifdef ROCKET_DEBUG_RECEIVE
|
||||
printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space);
|
||||
@@ -415,7 +415,7 @@ static void rp_do_receive(struct r_port *info,
|
||||
cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
|
||||
}
|
||||
/* Push the data up to the tty layer */
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&info->port);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -494,7 +494,6 @@ static void rp_do_transmit(struct r_port *info)
|
||||
static void rp_handle_port(struct r_port *info)
|
||||
{
|
||||
CHANNEL_t *cp;
|
||||
struct tty_struct *tty;
|
||||
unsigned int IntMask, ChanStatus;
|
||||
|
||||
if (!info)
|
||||
@@ -505,12 +504,7 @@ static void rp_handle_port(struct r_port *info)
|
||||
"info->flags & NOT_INIT\n");
|
||||
return;
|
||||
}
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (!tty) {
|
||||
printk(KERN_WARNING "rp: WARNING: rp_handle_port called with "
|
||||
"tty==NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cp = &info->channel;
|
||||
|
||||
IntMask = sGetChanIntID(cp) & info->intmask;
|
||||
@@ -519,7 +513,7 @@ static void rp_handle_port(struct r_port *info)
|
||||
#endif
|
||||
ChanStatus = sGetChanStatus(cp);
|
||||
if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */
|
||||
rp_do_receive(info, tty, cp, ChanStatus);
|
||||
rp_do_receive(info, cp, ChanStatus);
|
||||
}
|
||||
if (IntMask & DELTA_CD) { /* CD change */
|
||||
#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP))
|
||||
@@ -527,10 +521,15 @@ static void rp_handle_port(struct r_port *info)
|
||||
(ChanStatus & CD_ACT) ? "on" : "off");
|
||||
#endif
|
||||
if (!(ChanStatus & CD_ACT) && info->cd_status) {
|
||||
struct tty_struct *tty;
|
||||
#ifdef ROCKET_DEBUG_HANGUP
|
||||
printk(KERN_INFO "CD drop, calling hangup.\n");
|
||||
#endif
|
||||
tty_hangup(tty);
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
@@ -543,7 +542,6 @@ static void rp_handle_port(struct r_port *info)
|
||||
printk(KERN_INFO "DSR change...\n");
|
||||
}
|
||||
#endif
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1758,8 +1756,29 @@ static void rp_flush_buffer(struct tty_struct *tty)
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
static struct pci_device_id __used rocket_pci_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
|
||||
static DEFINE_PCI_DEVICE_TABLE(rocket_pci_ids) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4QUAD) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8OCTA) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8INTF) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8INTF) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8J) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4J) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8SNI) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16SNI) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16INTF) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP16INTF) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_CRP16INTF) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP32INTF) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP32INTF) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP4) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RPP8) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_232) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP2_422) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP6M) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4M) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_8PORT) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_UPCI_RM3_4PORT) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
|
||||
@@ -1781,7 +1800,8 @@ static __init int register_PCI(int i, struct pci_dev *dev)
|
||||
WordIO_t ConfigIO = 0;
|
||||
ByteIO_t UPCIRingInd = 0;
|
||||
|
||||
if (!dev || pci_enable_device(dev))
|
||||
if (!dev || !pci_match_id(rocket_pci_ids, dev) ||
|
||||
pci_enable_device(dev))
|
||||
return 0;
|
||||
|
||||
rcktpt_io_addr[i] = pci_resource_start(dev, 0);
|
||||
|
@@ -85,7 +85,6 @@ static void serial21285_enable_ms(struct uart_port *port)
|
||||
static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
unsigned int status, ch, flag, rxs, max_count = 256;
|
||||
|
||||
status = *CSR_UARTFLG;
|
||||
@@ -115,7 +114,7 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
|
||||
|
||||
status = *CSR_UARTFLG;
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -262,8 +262,7 @@ static void rs_start(struct tty_struct *tty)
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
static void receive_chars(struct m68k_serial *info, struct tty_struct *tty,
|
||||
unsigned short rx)
|
||||
static void receive_chars(struct m68k_serial *info, unsigned short rx)
|
||||
{
|
||||
m68328_uart *uart = &uart_addr[info->line];
|
||||
unsigned char ch, flag;
|
||||
@@ -293,9 +292,6 @@ static void receive_chars(struct m68k_serial *info, struct tty_struct *tty,
|
||||
}
|
||||
}
|
||||
|
||||
if(!tty)
|
||||
goto clear_and_exit;
|
||||
|
||||
flag = TTY_NORMAL;
|
||||
|
||||
if (rx & URX_PARITY_ERROR)
|
||||
@@ -305,15 +301,12 @@ static void receive_chars(struct m68k_serial *info, struct tty_struct *tty,
|
||||
else if (rx & URX_FRAME_ERROR)
|
||||
flag = TTY_FRAME;
|
||||
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(&info->tport, ch, flag);
|
||||
#ifndef CONFIG_XCOPILOT_BUGS
|
||||
} while((rx = uart->urx.w) & URX_DATA_READY);
|
||||
#endif
|
||||
|
||||
tty_schedule_flip(tty);
|
||||
|
||||
clear_and_exit:
|
||||
return;
|
||||
tty_schedule_flip(&info->tport);
|
||||
}
|
||||
|
||||
static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty)
|
||||
@@ -367,11 +360,11 @@ irqreturn_t rs_interrupt(int irq, void *dev_id)
|
||||
tx = uart->utx.w;
|
||||
|
||||
if (rx & URX_DATA_READY)
|
||||
receive_chars(info, tty, rx);
|
||||
receive_chars(info, rx);
|
||||
if (tx & UTX_TX_AVAIL)
|
||||
transmit_chars(info, tty);
|
||||
#else
|
||||
receive_chars(info, tty, rx);
|
||||
receive_chars(info, rx);
|
||||
#endif
|
||||
tty_kref_put(tty);
|
||||
|
||||
@@ -1009,7 +1002,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
|
||||
m68328_uart *uart = &uart_addr[info->line];
|
||||
unsigned long flags;
|
||||
|
||||
if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
|
||||
if (serial_paranoia_check(info, tty->name, "rs_close"))
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
@@ -239,13 +239,6 @@ static const struct serial8250_config uart_config[] = {
|
||||
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
|
||||
.flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE,
|
||||
},
|
||||
[PORT_RM9000] = {
|
||||
.name = "RM9000",
|
||||
.fifo_size = 16,
|
||||
.tx_loadsz = 16,
|
||||
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
|
||||
.flags = UART_CAP_FIFO,
|
||||
},
|
||||
[PORT_OCTEON] = {
|
||||
.name = "OCTEON",
|
||||
.fifo_size = 64,
|
||||
@@ -324,9 +317,9 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
serial_out(up, UART_DLM, value >> 8 & 0xff);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MIPS_ALCHEMY
|
||||
#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
|
||||
|
||||
/* Au1x00 UART hardware has a weird register layout */
|
||||
/* Au1x00/RT288x UART hardware has a weird register layout */
|
||||
static const u8 au_io_in_map[] = {
|
||||
[UART_RX] = 0,
|
||||
[UART_IER] = 2,
|
||||
@@ -370,56 +363,6 @@ static void au_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_RM9K
|
||||
|
||||
static const u8
|
||||
regmap_in[8] = {
|
||||
[UART_RX] = 0x00,
|
||||
[UART_IER] = 0x0c,
|
||||
[UART_IIR] = 0x14,
|
||||
[UART_LCR] = 0x1c,
|
||||
[UART_MCR] = 0x20,
|
||||
[UART_LSR] = 0x24,
|
||||
[UART_MSR] = 0x28,
|
||||
[UART_SCR] = 0x2c
|
||||
},
|
||||
regmap_out[8] = {
|
||||
[UART_TX] = 0x04,
|
||||
[UART_IER] = 0x0c,
|
||||
[UART_FCR] = 0x18,
|
||||
[UART_LCR] = 0x1c,
|
||||
[UART_MCR] = 0x20,
|
||||
[UART_LSR] = 0x24,
|
||||
[UART_MSR] = 0x28,
|
||||
[UART_SCR] = 0x2c
|
||||
};
|
||||
|
||||
static unsigned int rm9k_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
offset = regmap_in[offset] << p->regshift;
|
||||
return readl(p->membase + offset);
|
||||
}
|
||||
|
||||
static void rm9k_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
offset = regmap_out[offset] << p->regshift;
|
||||
writel(value, p->membase + offset);
|
||||
}
|
||||
|
||||
static int rm9k_serial_dl_read(struct uart_8250_port *up)
|
||||
{
|
||||
return ((__raw_readl(up->port.membase + 0x10) << 8) |
|
||||
(__raw_readl(up->port.membase + 0x08) & 0xff)) & 0xffff;
|
||||
}
|
||||
|
||||
static void rm9k_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
{
|
||||
__raw_writel(value, up->port.membase + 0x08);
|
||||
__raw_writel(value >> 8, up->port.membase + 0x10);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static unsigned int hub6_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
offset = offset << p->regshift;
|
||||
@@ -497,16 +440,7 @@ static void set_io_from_upio(struct uart_port *p)
|
||||
p->serial_out = mem32_serial_out;
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_RM9K
|
||||
case UPIO_RM9000:
|
||||
p->serial_in = rm9k_serial_in;
|
||||
p->serial_out = rm9k_serial_out;
|
||||
up->dl_read = rm9k_serial_dl_read;
|
||||
up->dl_write = rm9k_serial_dl_write;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MIPS_ALCHEMY
|
||||
#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X)
|
||||
case UPIO_AU:
|
||||
p->serial_in = au_serial_in;
|
||||
p->serial_out = au_serial_out;
|
||||
@@ -1341,7 +1275,9 @@ static void serial8250_start_tx(struct uart_port *port)
|
||||
struct uart_8250_port *up =
|
||||
container_of(port, struct uart_8250_port, port);
|
||||
|
||||
if (!(up->ier & UART_IER_THRI)) {
|
||||
if (up->dma && !serial8250_tx_dma(up)) {
|
||||
return;
|
||||
} else if (!(up->ier & UART_IER_THRI)) {
|
||||
up->ier |= UART_IER_THRI;
|
||||
serial_port_out(port, UART_IER, up->ier);
|
||||
|
||||
@@ -1349,9 +1285,7 @@ static void serial8250_start_tx(struct uart_port *port)
|
||||
unsigned char lsr;
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
||||
if ((port->type == PORT_RM9000) ?
|
||||
(lsr & UART_LSR_THRE) :
|
||||
(lsr & UART_LSR_TEMT))
|
||||
if (lsr & UART_LSR_TEMT)
|
||||
serial8250_tx_chars(up);
|
||||
}
|
||||
}
|
||||
@@ -1397,7 +1331,6 @@ unsigned char
|
||||
serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
|
||||
{
|
||||
struct uart_port *port = &up->port;
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
unsigned char ch;
|
||||
int max_count = 256;
|
||||
char flag;
|
||||
@@ -1462,7 +1395,7 @@ ignore_char:
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
} while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (max_count-- > 0));
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
spin_lock(&port->lock);
|
||||
return lsr;
|
||||
}
|
||||
@@ -1547,6 +1480,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
||||
unsigned long flags;
|
||||
struct uart_8250_port *up =
|
||||
container_of(port, struct uart_8250_port, port);
|
||||
int dma_err = 0;
|
||||
|
||||
if (iir & UART_IIR_NO_INT)
|
||||
return 0;
|
||||
@@ -1557,8 +1491,13 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
||||
|
||||
DEBUG_INTR("status = %x...", status);
|
||||
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI))
|
||||
status = serial8250_rx_chars(up, status);
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI)) {
|
||||
if (up->dma)
|
||||
dma_err = serial8250_rx_dma(up, iir);
|
||||
|
||||
if (!up->dma || dma_err)
|
||||
status = serial8250_rx_chars(up, status);
|
||||
}
|
||||
serial8250_modem_status(up);
|
||||
if (status & UART_LSR_THRE)
|
||||
serial8250_tx_chars(up);
|
||||
@@ -1991,9 +1930,12 @@ static int serial8250_startup(struct uart_port *port)
|
||||
if (port->type == PORT_8250_CIR)
|
||||
return -ENODEV;
|
||||
|
||||
port->fifosize = uart_config[up->port.type].fifo_size;
|
||||
up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
|
||||
up->capabilities = uart_config[up->port.type].flags;
|
||||
if (!port->fifosize)
|
||||
port->fifosize = uart_config[port->type].fifo_size;
|
||||
if (!up->tx_loadsz)
|
||||
up->tx_loadsz = uart_config[port->type].tx_loadsz;
|
||||
if (!up->capabilities)
|
||||
up->capabilities = uart_config[port->type].flags;
|
||||
up->mcr = 0;
|
||||
|
||||
if (port->iotype != up->cur_iotype)
|
||||
@@ -2197,6 +2139,18 @@ dont_test_tx_en:
|
||||
up->lsr_saved_flags = 0;
|
||||
up->msr_saved_flags = 0;
|
||||
|
||||
/*
|
||||
* Request DMA channels for both RX and TX.
|
||||
*/
|
||||
if (up->dma) {
|
||||
retval = serial8250_request_dma(up);
|
||||
if (retval) {
|
||||
pr_warn_ratelimited("ttyS%d - failed to request DMA\n",
|
||||
serial_index(port));
|
||||
up->dma = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, enable interrupts. Note: Modem status interrupts
|
||||
* are set via set_termios(), which will be occurring imminently
|
||||
@@ -2230,6 +2184,9 @@ static void serial8250_shutdown(struct uart_port *port)
|
||||
up->ier = 0;
|
||||
serial_port_out(port, UART_IER, 0);
|
||||
|
||||
if (up->dma)
|
||||
serial8250_release_dma(up);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if (port->flags & UPF_FOURPORT) {
|
||||
/* reset interrupts on the AST Fourport board */
|
||||
@@ -2826,9 +2783,12 @@ static void
|
||||
serial8250_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
|
||||
{
|
||||
up->port.type = type;
|
||||
up->port.fifosize = uart_config[type].fifo_size;
|
||||
up->capabilities = uart_config[type].flags;
|
||||
up->tx_loadsz = uart_config[type].tx_loadsz;
|
||||
if (!up->port.fifosize)
|
||||
up->port.fifosize = uart_config[type].fifo_size;
|
||||
if (!up->tx_loadsz)
|
||||
up->tx_loadsz = uart_config[type].tx_loadsz;
|
||||
if (!up->capabilities)
|
||||
up->capabilities = uart_config[type].flags;
|
||||
}
|
||||
|
||||
static void __init
|
||||
@@ -3262,6 +3222,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
uart->bugs = up->bugs;
|
||||
uart->port.mapbase = up->port.mapbase;
|
||||
uart->port.private_data = up->port.private_data;
|
||||
uart->port.fifosize = up->port.fifosize;
|
||||
uart->tx_loadsz = up->tx_loadsz;
|
||||
uart->capabilities = up->capabilities;
|
||||
|
||||
if (up->port.dev)
|
||||
uart->port.dev = up->port.dev;
|
||||
|
||||
@@ -3287,6 +3251,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
||||
uart->dl_read = up->dl_read;
|
||||
if (up->dl_write)
|
||||
uart->dl_write = up->dl_write;
|
||||
if (up->dma)
|
||||
uart->dma = up->dma;
|
||||
|
||||
if (serial8250_isa_config != NULL)
|
||||
serial8250_isa_config(0, &uart->port,
|
||||
|
@@ -12,6 +12,35 @@
|
||||
*/
|
||||
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
struct uart_8250_dma {
|
||||
dma_filter_fn fn;
|
||||
void *rx_param;
|
||||
void *tx_param;
|
||||
|
||||
int rx_chan_id;
|
||||
int tx_chan_id;
|
||||
|
||||
struct dma_slave_config rxconf;
|
||||
struct dma_slave_config txconf;
|
||||
|
||||
struct dma_chan *rxchan;
|
||||
struct dma_chan *txchan;
|
||||
|
||||
dma_addr_t rx_addr;
|
||||
dma_addr_t tx_addr;
|
||||
|
||||
dma_cookie_t rx_cookie;
|
||||
dma_cookie_t tx_cookie;
|
||||
|
||||
void *rx_buf;
|
||||
|
||||
size_t rx_size;
|
||||
size_t tx_size;
|
||||
|
||||
unsigned char tx_running:1;
|
||||
};
|
||||
|
||||
struct old_serial_port {
|
||||
unsigned int uart;
|
||||
@@ -143,3 +172,24 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
extern int serial8250_tx_dma(struct uart_8250_port *);
|
||||
extern int serial8250_rx_dma(struct uart_8250_port *, unsigned int iir);
|
||||
extern int serial8250_request_dma(struct uart_8250_port *);
|
||||
extern void serial8250_release_dma(struct uart_8250_port *);
|
||||
#else
|
||||
static inline int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
static inline int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
static inline int serial8250_request_dma(struct uart_8250_port *p)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
static inline void serial8250_release_dma(struct uart_8250_port *p) { }
|
||||
#endif
|
||||
|
216
drivers/tty/serial/8250/8250_dma.c
Normal file
216
drivers/tty/serial/8250/8250_dma.c
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* 8250_dma.c - DMA Engine API support for 8250.c
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
static void __dma_tx_complete(void *param)
|
||||
{
|
||||
struct uart_8250_port *p = param;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
|
||||
dma->tx_running = 0;
|
||||
|
||||
dma_sync_single_for_cpu(dma->txchan->device->dev, dma->tx_addr,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
|
||||
xmit->tail += dma->tx_size;
|
||||
xmit->tail &= UART_XMIT_SIZE - 1;
|
||||
p->port.icount.tx += dma->tx_size;
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&p->port);
|
||||
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) {
|
||||
serial8250_tx_dma(p);
|
||||
uart_write_wakeup(&p->port);
|
||||
}
|
||||
}
|
||||
|
||||
static void __dma_rx_complete(void *param)
|
||||
{
|
||||
struct uart_8250_port *p = param;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct tty_port *tty_port = &p->port.state->port;
|
||||
struct dma_tx_state state;
|
||||
int count;
|
||||
|
||||
dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
dmaengine_terminate_all(dma->rxchan);
|
||||
|
||||
count = dma->rx_size - state.residue;
|
||||
|
||||
tty_insert_flip_string(tty_port, dma->rx_buf, count);
|
||||
p->port.icount.rx += count;
|
||||
|
||||
tty_flip_buffer_push(tty_port);
|
||||
}
|
||||
|
||||
int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
|
||||
if (dma->tx_running)
|
||||
return -EBUSY;
|
||||
|
||||
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
if (!dma->tx_size)
|
||||
return -EINVAL;
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->txchan,
|
||||
dma->tx_addr + xmit->tail,
|
||||
dma->tx_size, DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc)
|
||||
return -EBUSY;
|
||||
|
||||
dma->tx_running = 1;
|
||||
|
||||
desc->callback = __dma_tx_complete;
|
||||
desc->callback_param = p;
|
||||
|
||||
dma->tx_cookie = dmaengine_submit(desc);
|
||||
|
||||
dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
|
||||
dma_async_issue_pending(dma->txchan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_tx_dma);
|
||||
|
||||
int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct dma_tx_state state;
|
||||
int dma_status;
|
||||
|
||||
/*
|
||||
* If RCVR FIFO trigger level was not reached, complete the transfer and
|
||||
* let 8250.c copy the remaining data.
|
||||
*/
|
||||
if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) {
|
||||
dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie,
|
||||
&state);
|
||||
if (dma_status == DMA_IN_PROGRESS) {
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_complete(p);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
|
||||
dma->rx_size, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc)
|
||||
return -EBUSY;
|
||||
|
||||
desc->callback = __dma_rx_complete;
|
||||
desc->callback_param = p;
|
||||
|
||||
dma->rx_cookie = dmaengine_submit(desc);
|
||||
|
||||
dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr,
|
||||
dma->rx_size, DMA_FROM_DEVICE);
|
||||
|
||||
dma_async_issue_pending(dma->rxchan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_rx_dma);
|
||||
|
||||
int serial8250_request_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
dma->rxconf.src_addr = p->port.mapbase + UART_RX;
|
||||
dma->txconf.dst_addr = p->port.mapbase + UART_TX;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
/* Get a channel for RX */
|
||||
dma->rxchan = dma_request_channel(mask, dma->fn, dma->rx_param);
|
||||
if (!dma->rxchan)
|
||||
return -ENODEV;
|
||||
|
||||
dmaengine_slave_config(dma->rxchan, &dma->rxconf);
|
||||
|
||||
/* Get a channel for TX */
|
||||
dma->txchan = dma_request_channel(mask, dma->fn, dma->tx_param);
|
||||
if (!dma->txchan) {
|
||||
dma_release_channel(dma->rxchan);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dmaengine_slave_config(dma->txchan, &dma->txconf);
|
||||
|
||||
/* RX buffer */
|
||||
if (!dma->rx_size)
|
||||
dma->rx_size = PAGE_SIZE;
|
||||
|
||||
dma->rx_buf = dma_alloc_coherent(dma->rxchan->device->dev, dma->rx_size,
|
||||
&dma->rx_addr, GFP_KERNEL);
|
||||
if (!dma->rx_buf) {
|
||||
dma_release_channel(dma->rxchan);
|
||||
dma_release_channel(dma->txchan);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* TX buffer */
|
||||
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
|
||||
p->port.state->xmit.buf,
|
||||
UART_XMIT_SIZE,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
dev_dbg_ratelimited(p->port.dev, "got both dma channels\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_request_dma);
|
||||
|
||||
void serial8250_release_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
|
||||
if (!dma)
|
||||
return;
|
||||
|
||||
/* Release RX resources */
|
||||
dmaengine_terminate_all(dma->rxchan);
|
||||
dma_free_coherent(dma->rxchan->device->dev, dma->rx_size, dma->rx_buf,
|
||||
dma->rx_addr);
|
||||
dma_release_channel(dma->rxchan);
|
||||
dma->rxchan = NULL;
|
||||
|
||||
/* Release TX resources */
|
||||
dmaengine_terminate_all(dma->txchan);
|
||||
dma_unmap_single(dma->txchan->device->dev, dma->tx_addr,
|
||||
UART_XMIT_SIZE, DMA_TO_DEVICE);
|
||||
dma_release_channel(dma->txchan);
|
||||
dma->txchan = NULL;
|
||||
dma->tx_running = 0;
|
||||
|
||||
dev_dbg_ratelimited(p->port.dev, "dma channels released\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_release_dma);
|
@@ -2,6 +2,7 @@
|
||||
* Synopsys DesignWare 8250 driver.
|
||||
*
|
||||
* Copyright 2011 Picochip, Jamie Iles.
|
||||
* Copyright 2013 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -24,6 +25,34 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
/* Offsets for the DesignWare specific registers */
|
||||
#define DW_UART_USR 0x1f /* UART Status Register */
|
||||
#define DW_UART_CPR 0xf4 /* Component Parameter Register */
|
||||
#define DW_UART_UCV 0xf8 /* UART Component Version */
|
||||
|
||||
/* Intel Low Power Subsystem specific */
|
||||
#define LPSS_PRV_CLOCK_PARAMS 0x800
|
||||
|
||||
/* Component Parameter Register bits */
|
||||
#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
|
||||
#define DW_UART_CPR_AFCE_MODE (1 << 4)
|
||||
#define DW_UART_CPR_THRE_MODE (1 << 5)
|
||||
#define DW_UART_CPR_SIR_MODE (1 << 6)
|
||||
#define DW_UART_CPR_SIR_LP_MODE (1 << 7)
|
||||
#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8)
|
||||
#define DW_UART_CPR_FIFO_ACCESS (1 << 9)
|
||||
#define DW_UART_CPR_FIFO_STAT (1 << 10)
|
||||
#define DW_UART_CPR_SHADOW (1 << 11)
|
||||
#define DW_UART_CPR_ENCODED_PARMS (1 << 12)
|
||||
#define DW_UART_CPR_DMA_EXTRA (1 << 13)
|
||||
#define DW_UART_CPR_FIFO_MODE (0xff << 16)
|
||||
/* Helper for fifo size calculation */
|
||||
#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
|
||||
|
||||
|
||||
struct dw8250_data {
|
||||
int last_lcr;
|
||||
@@ -66,9 +95,6 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
|
||||
return readl(p->membase + offset);
|
||||
}
|
||||
|
||||
/* Offset for the DesignWare's UART Status Register. */
|
||||
#define UART_USR 0x1f
|
||||
|
||||
static int dw8250_handle_irq(struct uart_port *p)
|
||||
{
|
||||
struct dw8250_data *d = p->private_data;
|
||||
@@ -78,7 +104,7 @@ static int dw8250_handle_irq(struct uart_port *p)
|
||||
return 1;
|
||||
} else if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
|
||||
/* Clear the USR and write the LCR again. */
|
||||
(void)p->serial_in(p, UART_USR);
|
||||
(void)p->serial_in(p, DW_UART_USR);
|
||||
p->serial_out(p, UART_LCR, d->last_lcr);
|
||||
|
||||
return 1;
|
||||
@@ -87,61 +113,210 @@ static int dw8250_handle_irq(struct uart_port *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw8250_probe_of(struct uart_port *p)
|
||||
{
|
||||
struct device_node *np = p->dev->of_node;
|
||||
u32 val;
|
||||
|
||||
if (!of_property_read_u32(np, "reg-io-width", &val)) {
|
||||
switch (val) {
|
||||
case 1:
|
||||
break;
|
||||
case 4:
|
||||
p->iotype = UPIO_MEM32;
|
||||
p->serial_in = dw8250_serial_in32;
|
||||
p->serial_out = dw8250_serial_out32;
|
||||
break;
|
||||
default:
|
||||
dev_err(p->dev, "unsupported reg-io-width (%u)\n", val);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "reg-shift", &val))
|
||||
p->regshift = val;
|
||||
|
||||
if (of_property_read_u32(np, "clock-frequency", &val)) {
|
||||
dev_err(p->dev, "no clock-frequency property set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
p->uartclk = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static bool dw8250_acpi_dma_filter(struct dma_chan *chan, void *parm)
|
||||
{
|
||||
return chan->chan_id == *(int *)parm;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
dw8250_acpi_walk_resource(struct acpi_resource *res, void *data)
|
||||
{
|
||||
struct uart_port *p = data;
|
||||
struct uart_8250_port *port;
|
||||
struct uart_8250_dma *dma;
|
||||
struct acpi_resource_fixed_dma *fixed_dma;
|
||||
struct dma_slave_config *slave;
|
||||
|
||||
port = container_of(p, struct uart_8250_port, port);
|
||||
|
||||
switch (res->type) {
|
||||
case ACPI_RESOURCE_TYPE_FIXED_DMA:
|
||||
fixed_dma = &res->data.fixed_dma;
|
||||
|
||||
/* TX comes first */
|
||||
if (!port->dma) {
|
||||
dma = devm_kzalloc(p->dev, sizeof(*dma), GFP_KERNEL);
|
||||
if (!dma)
|
||||
return AE_NO_MEMORY;
|
||||
|
||||
port->dma = dma;
|
||||
slave = &dma->txconf;
|
||||
|
||||
slave->direction = DMA_MEM_TO_DEV;
|
||||
slave->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
slave->slave_id = fixed_dma->request_lines;
|
||||
slave->dst_maxburst = port->tx_loadsz / 4;
|
||||
|
||||
dma->tx_chan_id = fixed_dma->channels;
|
||||
dma->tx_param = &dma->tx_chan_id;
|
||||
dma->fn = dw8250_acpi_dma_filter;
|
||||
} else {
|
||||
dma = port->dma;
|
||||
slave = &dma->rxconf;
|
||||
|
||||
slave->direction = DMA_DEV_TO_MEM;
|
||||
slave->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
slave->slave_id = fixed_dma->request_lines;
|
||||
slave->src_maxburst = p->fifosize / 4;
|
||||
|
||||
dma->rx_chan_id = fixed_dma->channels;
|
||||
dma->rx_param = &dma->rx_chan_id;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int dw8250_probe_acpi(struct uart_port *p)
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
acpi_status status;
|
||||
u32 reg;
|
||||
|
||||
id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
p->iotype = UPIO_MEM32;
|
||||
p->serial_in = dw8250_serial_in32;
|
||||
p->serial_out = dw8250_serial_out32;
|
||||
p->regshift = 2;
|
||||
p->uartclk = (unsigned int)id->driver_data;
|
||||
|
||||
status = acpi_walk_resources(ACPI_HANDLE(p->dev), METHOD_NAME__CRS,
|
||||
dw8250_acpi_walk_resource, p);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err_ratelimited(p->dev, "%s failed \"%s\"\n", __func__,
|
||||
acpi_format_exception(status));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Fix Haswell issue where the clocks do not get enabled */
|
||||
if (!strcmp(id->id, "INT33C4") || !strcmp(id->id, "INT33C5")) {
|
||||
reg = readl(p->membase + LPSS_PRV_CLOCK_PARAMS);
|
||||
writel(reg | 1, p->membase + LPSS_PRV_CLOCK_PARAMS);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int dw8250_probe_acpi(struct uart_port *p)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
static void dw8250_setup_port(struct uart_8250_port *up)
|
||||
{
|
||||
struct uart_port *p = &up->port;
|
||||
u32 reg = readl(p->membase + DW_UART_UCV);
|
||||
|
||||
/*
|
||||
* If the Component Version Register returns zero, we know that
|
||||
* ADDITIONAL_FEATURES are not enabled. No need to go any further.
|
||||
*/
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n",
|
||||
(reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff);
|
||||
|
||||
reg = readl(p->membase + DW_UART_CPR);
|
||||
if (!reg)
|
||||
return;
|
||||
|
||||
/* Select the type based on fifo */
|
||||
if (reg & DW_UART_CPR_FIFO_MODE) {
|
||||
p->type = PORT_16550A;
|
||||
p->flags |= UPF_FIXED_TYPE;
|
||||
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
|
||||
up->tx_loadsz = p->fifosize;
|
||||
}
|
||||
}
|
||||
|
||||
static int dw8250_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_8250_port uart = {};
|
||||
struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 val;
|
||||
struct dw8250_data *data;
|
||||
int err;
|
||||
|
||||
if (!regs || !irq) {
|
||||
dev_err(&pdev->dev, "no registers/irq defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
uart.port.private_data = data;
|
||||
|
||||
spin_lock_init(&uart.port.lock);
|
||||
uart.port.mapbase = regs->start;
|
||||
uart.port.irq = irq->start;
|
||||
uart.port.handle_irq = dw8250_handle_irq;
|
||||
uart.port.type = PORT_8250;
|
||||
uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
|
||||
UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
|
||||
uart.port.dev = &pdev->dev;
|
||||
|
||||
uart.port.membase = ioremap(regs->start, resource_size(regs));
|
||||
if (!uart.port.membase)
|
||||
return -ENOMEM;
|
||||
|
||||
uart.port.iotype = UPIO_MEM;
|
||||
uart.port.serial_in = dw8250_serial_in;
|
||||
uart.port.serial_out = dw8250_serial_out;
|
||||
if (!of_property_read_u32(np, "reg-io-width", &val)) {
|
||||
switch (val) {
|
||||
case 1:
|
||||
break;
|
||||
case 4:
|
||||
uart.port.iotype = UPIO_MEM32;
|
||||
uart.port.serial_in = dw8250_serial_in32;
|
||||
uart.port.serial_out = dw8250_serial_out32;
|
||||
break;
|
||||
default:
|
||||
dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n",
|
||||
val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dw8250_setup_port(&uart);
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
err = dw8250_probe_of(&uart.port);
|
||||
if (err)
|
||||
return err;
|
||||
} else if (ACPI_HANDLE(&pdev->dev)) {
|
||||
err = dw8250_probe_acpi(&uart.port);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(np, "reg-shift", &val))
|
||||
uart.port.regshift = val;
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_u32(np, "clock-frequency", &val)) {
|
||||
dev_err(&pdev->dev, "no clock-frequency property set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
uart.port.uartclk = val;
|
||||
uart.port.private_data = data;
|
||||
|
||||
data->line = serial8250_register_8250_port(&uart);
|
||||
if (data->line < 0)
|
||||
@@ -184,17 +359,25 @@ static int dw8250_resume(struct platform_device *pdev)
|
||||
#define dw8250_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct of_device_id dw8250_match[] = {
|
||||
static const struct of_device_id dw8250_of_match[] = {
|
||||
{ .compatible = "snps,dw-apb-uart" },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, dw8250_match);
|
||||
MODULE_DEVICE_TABLE(of, dw8250_of_match);
|
||||
|
||||
static const struct acpi_device_id dw8250_acpi_match[] = {
|
||||
{ "INT33C4", 100000000 },
|
||||
{ "INT33C5", 100000000 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
|
||||
|
||||
static struct platform_driver dw8250_platform_driver = {
|
||||
.driver = {
|
||||
.name = "dw-apb-uart",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = dw8250_match,
|
||||
.of_match_table = dw8250_of_match,
|
||||
.acpi_match_table = ACPI_PTR(dw8250_acpi_match),
|
||||
},
|
||||
.probe = dw8250_probe,
|
||||
.remove = dw8250_remove,
|
||||
|
@@ -194,7 +194,7 @@ static int __init parse_options(struct early_serial8250_device *device,
|
||||
options++;
|
||||
device->baud = simple_strtoul(options, NULL, 0);
|
||||
length = min(strcspn(options, " "), sizeof(device->options));
|
||||
strncpy(device->options, options, length);
|
||||
strlcpy(device->options, options, length);
|
||||
} else {
|
||||
device->baud = probe_baud(port);
|
||||
snprintf(device->options, sizeof(device->options), "%u",
|
||||
|
@@ -1040,6 +1040,253 @@ static int pci_asix_setup(struct serial_private *priv,
|
||||
return pci_default_setup(priv, board, port, idx);
|
||||
}
|
||||
|
||||
/* Quatech devices have their own extra interface features */
|
||||
|
||||
struct quatech_feature {
|
||||
u16 devid;
|
||||
bool amcc;
|
||||
};
|
||||
|
||||
#define QPCR_TEST_FOR1 0x3F
|
||||
#define QPCR_TEST_GET1 0x00
|
||||
#define QPCR_TEST_FOR2 0x40
|
||||
#define QPCR_TEST_GET2 0x40
|
||||
#define QPCR_TEST_FOR3 0x80
|
||||
#define QPCR_TEST_GET3 0x40
|
||||
#define QPCR_TEST_FOR4 0xC0
|
||||
#define QPCR_TEST_GET4 0x80
|
||||
|
||||
#define QOPR_CLOCK_X1 0x0000
|
||||
#define QOPR_CLOCK_X2 0x0001
|
||||
#define QOPR_CLOCK_X4 0x0002
|
||||
#define QOPR_CLOCK_X8 0x0003
|
||||
#define QOPR_CLOCK_RATE_MASK 0x0003
|
||||
|
||||
|
||||
static struct quatech_feature quatech_cards[] = {
|
||||
{ PCI_DEVICE_ID_QUATECH_QSC100, 1 },
|
||||
{ PCI_DEVICE_ID_QUATECH_DSC100, 1 },
|
||||
{ PCI_DEVICE_ID_QUATECH_DSC100E, 0 },
|
||||
{ PCI_DEVICE_ID_QUATECH_DSC200, 1 },
|
||||
{ PCI_DEVICE_ID_QUATECH_DSC200E, 0 },
|
||||
{ PCI_DEVICE_ID_QUATECH_ESC100D, 1 },
|
||||
{ PCI_DEVICE_ID_QUATECH_ESC100M, 1 },
|
||||
{ PCI_DEVICE_ID_QUATECH_QSCP100, 1 },
|
||||
{ PCI_DEVICE_ID_QUATECH_DSCP100, 1 },
|
||||
{ PCI_DEVICE_ID_QUATECH_QSCP200, 1 },
|
||||
{ PCI_DEVICE_ID_QUATECH_DSCP200, 1 },
|
||||
{ PCI_DEVICE_ID_QUATECH_ESCLP100, 0 },
|
||||
{ PCI_DEVICE_ID_QUATECH_QSCLP100, 0 },
|
||||
{ PCI_DEVICE_ID_QUATECH_DSCLP100, 0 },
|
||||
{ PCI_DEVICE_ID_QUATECH_SSCLP100, 0 },
|
||||
{ PCI_DEVICE_ID_QUATECH_QSCLP200, 0 },
|
||||
{ PCI_DEVICE_ID_QUATECH_DSCLP200, 0 },
|
||||
{ PCI_DEVICE_ID_QUATECH_SSCLP200, 0 },
|
||||
{ PCI_DEVICE_ID_QUATECH_SPPXP_100, 0 },
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
static int pci_quatech_amcc(u16 devid)
|
||||
{
|
||||
struct quatech_feature *qf = &quatech_cards[0];
|
||||
while (qf->devid) {
|
||||
if (qf->devid == devid)
|
||||
return qf->amcc;
|
||||
qf++;
|
||||
}
|
||||
pr_err("quatech: unknown port type '0x%04X'.\n", devid);
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int pci_quatech_rqopr(struct uart_8250_port *port)
|
||||
{
|
||||
unsigned long base = port->port.iobase;
|
||||
u8 LCR, val;
|
||||
|
||||
LCR = inb(base + UART_LCR);
|
||||
outb(0xBF, base + UART_LCR);
|
||||
val = inb(base + UART_SCR);
|
||||
outb(LCR, base + UART_LCR);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pci_quatech_wqopr(struct uart_8250_port *port, u8 qopr)
|
||||
{
|
||||
unsigned long base = port->port.iobase;
|
||||
u8 LCR, val;
|
||||
|
||||
LCR = inb(base + UART_LCR);
|
||||
outb(0xBF, base + UART_LCR);
|
||||
val = inb(base + UART_SCR);
|
||||
outb(qopr, base + UART_SCR);
|
||||
outb(LCR, base + UART_LCR);
|
||||
}
|
||||
|
||||
static int pci_quatech_rqmcr(struct uart_8250_port *port)
|
||||
{
|
||||
unsigned long base = port->port.iobase;
|
||||
u8 LCR, val, qmcr;
|
||||
|
||||
LCR = inb(base + UART_LCR);
|
||||
outb(0xBF, base + UART_LCR);
|
||||
val = inb(base + UART_SCR);
|
||||
outb(val | 0x10, base + UART_SCR);
|
||||
qmcr = inb(base + UART_MCR);
|
||||
outb(val, base + UART_SCR);
|
||||
outb(LCR, base + UART_LCR);
|
||||
|
||||
return qmcr;
|
||||
}
|
||||
|
||||
static void pci_quatech_wqmcr(struct uart_8250_port *port, u8 qmcr)
|
||||
{
|
||||
unsigned long base = port->port.iobase;
|
||||
u8 LCR, val;
|
||||
|
||||
LCR = inb(base + UART_LCR);
|
||||
outb(0xBF, base + UART_LCR);
|
||||
val = inb(base + UART_SCR);
|
||||
outb(val | 0x10, base + UART_SCR);
|
||||
outb(qmcr, base + UART_MCR);
|
||||
outb(val, base + UART_SCR);
|
||||
outb(LCR, base + UART_LCR);
|
||||
}
|
||||
|
||||
static int pci_quatech_has_qmcr(struct uart_8250_port *port)
|
||||
{
|
||||
unsigned long base = port->port.iobase;
|
||||
u8 LCR, val;
|
||||
|
||||
LCR = inb(base + UART_LCR);
|
||||
outb(0xBF, base + UART_LCR);
|
||||
val = inb(base + UART_SCR);
|
||||
if (val & 0x20) {
|
||||
outb(0x80, UART_LCR);
|
||||
if (!(inb(UART_SCR) & 0x20)) {
|
||||
outb(LCR, base + UART_LCR);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_quatech_test(struct uart_8250_port *port)
|
||||
{
|
||||
u8 reg;
|
||||
u8 qopr = pci_quatech_rqopr(port);
|
||||
pci_quatech_wqopr(port, qopr & QPCR_TEST_FOR1);
|
||||
reg = pci_quatech_rqopr(port) & 0xC0;
|
||||
if (reg != QPCR_TEST_GET1)
|
||||
return -EINVAL;
|
||||
pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR2);
|
||||
reg = pci_quatech_rqopr(port) & 0xC0;
|
||||
if (reg != QPCR_TEST_GET2)
|
||||
return -EINVAL;
|
||||
pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR3);
|
||||
reg = pci_quatech_rqopr(port) & 0xC0;
|
||||
if (reg != QPCR_TEST_GET3)
|
||||
return -EINVAL;
|
||||
pci_quatech_wqopr(port, (qopr & QPCR_TEST_FOR1)|QPCR_TEST_FOR4);
|
||||
reg = pci_quatech_rqopr(port) & 0xC0;
|
||||
if (reg != QPCR_TEST_GET4)
|
||||
return -EINVAL;
|
||||
|
||||
pci_quatech_wqopr(port, qopr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_quatech_clock(struct uart_8250_port *port)
|
||||
{
|
||||
u8 qopr, reg, set;
|
||||
unsigned long clock;
|
||||
|
||||
if (pci_quatech_test(port) < 0)
|
||||
return 1843200;
|
||||
|
||||
qopr = pci_quatech_rqopr(port);
|
||||
|
||||
pci_quatech_wqopr(port, qopr & ~QOPR_CLOCK_X8);
|
||||
reg = pci_quatech_rqopr(port);
|
||||
if (reg & QOPR_CLOCK_X8) {
|
||||
clock = 1843200;
|
||||
goto out;
|
||||
}
|
||||
pci_quatech_wqopr(port, qopr | QOPR_CLOCK_X8);
|
||||
reg = pci_quatech_rqopr(port);
|
||||
if (!(reg & QOPR_CLOCK_X8)) {
|
||||
clock = 1843200;
|
||||
goto out;
|
||||
}
|
||||
reg &= QOPR_CLOCK_X8;
|
||||
if (reg == QOPR_CLOCK_X2) {
|
||||
clock = 3685400;
|
||||
set = QOPR_CLOCK_X2;
|
||||
} else if (reg == QOPR_CLOCK_X4) {
|
||||
clock = 7372800;
|
||||
set = QOPR_CLOCK_X4;
|
||||
} else if (reg == QOPR_CLOCK_X8) {
|
||||
clock = 14745600;
|
||||
set = QOPR_CLOCK_X8;
|
||||
} else {
|
||||
clock = 1843200;
|
||||
set = QOPR_CLOCK_X1;
|
||||
}
|
||||
qopr &= ~QOPR_CLOCK_RATE_MASK;
|
||||
qopr |= set;
|
||||
|
||||
out:
|
||||
pci_quatech_wqopr(port, qopr);
|
||||
return clock;
|
||||
}
|
||||
|
||||
static int pci_quatech_rs422(struct uart_8250_port *port)
|
||||
{
|
||||
u8 qmcr;
|
||||
int rs422 = 0;
|
||||
|
||||
if (!pci_quatech_has_qmcr(port))
|
||||
return 0;
|
||||
qmcr = pci_quatech_rqmcr(port);
|
||||
pci_quatech_wqmcr(port, 0xFF);
|
||||
if (pci_quatech_rqmcr(port))
|
||||
rs422 = 1;
|
||||
pci_quatech_wqmcr(port, qmcr);
|
||||
return rs422;
|
||||
}
|
||||
|
||||
static int pci_quatech_init(struct pci_dev *dev)
|
||||
{
|
||||
if (pci_quatech_amcc(dev->device)) {
|
||||
unsigned long base = pci_resource_start(dev, 0);
|
||||
if (base) {
|
||||
u32 tmp;
|
||||
outl(inl(base + 0x38), base + 0x38);
|
||||
tmp = inl(base + 0x3c);
|
||||
outl(tmp | 0x01000000, base + 0x3c);
|
||||
outl(tmp, base + 0x3c);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pci_quatech_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
{
|
||||
/* Needed by pci_quatech calls below */
|
||||
port->port.iobase = pci_resource_start(priv->dev, FL_GET_BASE(board->flags));
|
||||
/* Set up the clocking */
|
||||
port->port.uartclk = pci_quatech_clock(port);
|
||||
/* For now just warn about RS422 */
|
||||
if (pci_quatech_rs422(port))
|
||||
pr_warn("quatech: software control of RS422 features not currently supported.\n");
|
||||
return pci_default_setup(priv, board, port, idx);
|
||||
}
|
||||
|
||||
static void pci_quatech_exit(struct pci_dev *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static int pci_default_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
@@ -1318,6 +1565,9 @@ pci_wch_ch353_setup(struct serial_private *priv,
|
||||
#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
|
||||
#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
|
||||
|
||||
#define PCI_VENDOR_ID_SUNIX 0x1fd4
|
||||
#define PCI_DEVICE_ID_SUNIX_1999 0x1999
|
||||
|
||||
|
||||
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
|
||||
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
|
||||
@@ -1541,6 +1791,16 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
||||
.setup = pci_ni8430_setup,
|
||||
.exit = pci_ni8430_exit,
|
||||
},
|
||||
/* Quatech */
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_QUATECH,
|
||||
.device = PCI_ANY_ID,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_quatech_init,
|
||||
.setup = pci_quatech_setup,
|
||||
.exit = pci_quatech_exit,
|
||||
},
|
||||
/*
|
||||
* Panacom
|
||||
*/
|
||||
@@ -1703,6 +1963,23 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_timedia_setup,
|
||||
},
|
||||
/*
|
||||
* SUNIX (Timedia) cards
|
||||
* Do not "probe" for these cards as there is at least one combination
|
||||
* card that should be handled by parport_pc that doesn't match the
|
||||
* rule in pci_timedia_probe.
|
||||
* It is part number is MIO5079A but its subdevice ID is 0x0102.
|
||||
* There are some boards with part number SER5037AL that report
|
||||
* subdevice ID 0x0002.
|
||||
*/
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_SUNIX,
|
||||
.device = PCI_DEVICE_ID_SUNIX_1999,
|
||||
.subvendor = PCI_VENDOR_ID_SUNIX,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.init = pci_timedia_init,
|
||||
.setup = pci_timedia_setup,
|
||||
},
|
||||
/*
|
||||
* Exar cards
|
||||
*/
|
||||
@@ -3506,18 +3783,70 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
|
||||
0x10b5, 0x106a, 0, 0,
|
||||
pbn_plx_romulus },
|
||||
/*
|
||||
* Quatech cards. These actually have configurable clocks but for
|
||||
* now we just use the default.
|
||||
*
|
||||
* 100 series are RS232, 200 series RS422,
|
||||
*/
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b1_4_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b1_2_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100E,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b2_2_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b1_2_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC200E,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b2_2_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC200,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b1_4_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b1_8_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b1_8_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP100,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b1_4_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP100,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b1_2_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCP200,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b1_4_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCP200,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b1_2_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP100,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b2_4_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP100,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b2_2_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP100,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b2_1_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSCLP200,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b2_4_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSCLP200,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b2_2_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SSCLP200,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b2_1_115200 },
|
||||
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESCLP100,
|
||||
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
|
||||
pbn_b0_8_115200 },
|
||||
|
||||
{ PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
|
||||
PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
|
||||
0, 0,
|
||||
@@ -3901,6 +4230,19 @@ static struct pci_device_id serial_pci_tbl[] = {
|
||||
PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0,
|
||||
pbn_b0_bt_1_921600 },
|
||||
|
||||
/*
|
||||
* SUNIX (TIMEDIA)
|
||||
*/
|
||||
{ PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
|
||||
PCI_VENDOR_ID_SUNIX, PCI_ANY_ID,
|
||||
PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00,
|
||||
pbn_b0_bt_1_921600 },
|
||||
|
||||
{ PCI_VENDOR_ID_SUNIX, PCI_DEVICE_ID_SUNIX_1999,
|
||||
PCI_VENDOR_ID_SUNIX, PCI_ANY_ID,
|
||||
PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
|
||||
pbn_b0_bt_1_921600 },
|
||||
|
||||
/*
|
||||
* AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org>
|
||||
*/
|
||||
|
@@ -84,6 +84,14 @@ config SERIAL_8250_GSC
|
||||
depends on SERIAL_8250 && GSC
|
||||
default SERIAL_8250
|
||||
|
||||
config SERIAL_8250_DMA
|
||||
bool "DMA support for 16550 compatible UART controllers" if EXPERT
|
||||
depends on SERIAL_8250 && DMADEVICES=y
|
||||
default SERIAL_8250
|
||||
help
|
||||
This builds DMA support that can be used with 8250/16650
|
||||
compatible UART controllers that support DMA signaling.
|
||||
|
||||
config SERIAL_8250_PCI
|
||||
tristate "8250/16550 PCI device support" if EXPERT
|
||||
depends on SERIAL_8250 && PCI
|
||||
@@ -249,15 +257,6 @@ config SERIAL_8250_ACORN
|
||||
system, say Y to this option. The driver can handle 1, 2, or 3 port
|
||||
cards. If unsure, say N.
|
||||
|
||||
config SERIAL_8250_RM9K
|
||||
bool "Support for MIPS RM9xxx integrated serial port"
|
||||
depends on SERIAL_8250 != n && SERIAL_RM9000
|
||||
select SERIAL_8250_SHARE_IRQ
|
||||
help
|
||||
Selecting this option will add support for the integrated serial
|
||||
port hardware found on MIPS RM9122 and similar processors.
|
||||
If unsure, say N.
|
||||
|
||||
config SERIAL_8250_FSL
|
||||
bool
|
||||
depends on SERIAL_8250_CONSOLE && PPC_UDBG_16550
|
||||
@@ -265,7 +264,7 @@ config SERIAL_8250_FSL
|
||||
|
||||
config SERIAL_8250_DW
|
||||
tristate "Support for Synopsys DesignWare 8250 quirks"
|
||||
depends on SERIAL_8250 && OF
|
||||
depends on SERIAL_8250
|
||||
help
|
||||
Selecting this option will enable handling of the extra features
|
||||
present in the Synopsys DesignWare APB UART.
|
||||
@@ -277,3 +276,11 @@ config SERIAL_8250_EM
|
||||
Selecting this option will add support for the integrated serial
|
||||
port hardware found on the Emma Mobile line of processors.
|
||||
If unsure, say N.
|
||||
|
||||
config SERIAL_8250_RT288X
|
||||
bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support"
|
||||
depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883)
|
||||
help
|
||||
If you have a Ralink RT288x/RT305x SoC based board and want to use the
|
||||
serial port, say Y to this option. The driver can handle up to 2 serial
|
||||
ports. If unsure, say N.
|
||||
|
@@ -5,6 +5,7 @@
|
||||
obj-$(CONFIG_SERIAL_8250) += 8250_core.o
|
||||
8250_core-y := 8250.o
|
||||
8250_core-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
|
||||
8250_core-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
|
||||
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
|
||||
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
|
||||
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
|
||||
|
@@ -2,8 +2,10 @@
|
||||
# Serial device configuration
|
||||
#
|
||||
|
||||
if TTY
|
||||
|
||||
menu "Serial drivers"
|
||||
depends on HAS_IOMEM
|
||||
depends on HAS_IOMEM && GENERIC_HARDIRQS
|
||||
|
||||
source "drivers/tty/serial/8250/Kconfig"
|
||||
|
||||
@@ -269,6 +271,17 @@ config SERIAL_SIRFSOC_CONSOLE
|
||||
your boot loader about how to pass options to the kernel at
|
||||
boot time.)
|
||||
|
||||
config SERIAL_TEGRA
|
||||
tristate "NVIDIA Tegra20/30 SoC serial controller"
|
||||
depends on ARCH_TEGRA && TEGRA20_APB_DMA
|
||||
select SERIAL_CORE
|
||||
help
|
||||
Support for the on-chip UARTs on the NVIDIA Tegra series SOCs
|
||||
providing /dev/ttyHS0, 1, 2, 3 and 4 (note, some machines may not
|
||||
provide all of these ports, depending on how the serial port
|
||||
are enabled). This driver uses the APB DMA to achieve higher baudrate
|
||||
and better performance.
|
||||
|
||||
config SERIAL_MAX3100
|
||||
tristate "MAX3100 support"
|
||||
depends on SPI
|
||||
@@ -1447,4 +1460,30 @@ config SERIAL_ARC_NR_PORTS
|
||||
Set this to the number of serial ports you want the driver
|
||||
to support.
|
||||
|
||||
config SERIAL_RP2
|
||||
tristate "Comtrol RocketPort EXPRESS/INFINITY support"
|
||||
depends on PCI
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This driver supports the Comtrol RocketPort EXPRESS and
|
||||
RocketPort INFINITY families of PCI/PCIe multiport serial adapters.
|
||||
These adapters use a "RocketPort 2" ASIC that is not compatible
|
||||
with the original RocketPort driver (CONFIG_ROCKETPORT).
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called rp2.
|
||||
|
||||
If you want to compile this driver into the kernel, say Y here. If
|
||||
you don't have a suitable RocketPort card installed, say N.
|
||||
|
||||
config SERIAL_RP2_NR_UARTS
|
||||
int "Maximum number of RocketPort EXPRESS/INFINITY ports"
|
||||
depends on SERIAL_RP2
|
||||
default "32"
|
||||
help
|
||||
If multiple cards are present, the default limit of 32 ports may
|
||||
need to be increased.
|
||||
|
||||
endmenu
|
||||
|
||||
endif # TTY
|
||||
|
@@ -80,6 +80,8 @@ obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o
|
||||
obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o
|
||||
obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o
|
||||
obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o
|
||||
obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.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
|
||||
|
@@ -139,7 +139,7 @@ static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
|
||||
uart_insert_char(port, 0, 0, ch, flag);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(port->state->port.tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
|
||||
@@ -493,11 +493,9 @@ static int __init altera_jtaguart_init(void)
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = platform_driver_register(&altera_jtaguart_platform_driver);
|
||||
if (rc) {
|
||||
if (rc)
|
||||
uart_unregister_driver(&altera_jtaguart_driver);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit altera_jtaguart_exit(void)
|
||||
|
@@ -231,7 +231,7 @@ static void altera_uart_rx_chars(struct altera_uart *pp)
|
||||
flag);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(port->state->port.tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void altera_uart_tx_chars(struct altera_uart *pp)
|
||||
@@ -637,11 +637,9 @@ static int __init altera_uart_init(void)
|
||||
if (rc)
|
||||
return rc;
|
||||
rc = platform_driver_register(&altera_uart_platform_driver);
|
||||
if (rc) {
|
||||
if (rc)
|
||||
uart_unregister_driver(&altera_uart_driver);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __exit altera_uart_exit(void)
|
||||
|
@@ -116,7 +116,6 @@ static void pl010_enable_ms(struct uart_port *port)
|
||||
|
||||
static void pl010_rx_chars(struct uart_amba_port *uap)
|
||||
{
|
||||
struct tty_struct *tty = uap->port.state->port.tty;
|
||||
unsigned int status, ch, flag, rsr, max_count = 256;
|
||||
|
||||
status = readb(uap->port.membase + UART01x_FR);
|
||||
@@ -165,7 +164,7 @@ static void pl010_rx_chars(struct uart_amba_port *uap)
|
||||
status = readb(uap->port.membase + UART01x_FR);
|
||||
}
|
||||
spin_unlock(&uap->port.lock);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&uap->port.state->port);
|
||||
spin_lock(&uap->port.lock);
|
||||
}
|
||||
|
||||
|
@@ -698,7 +698,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
|
||||
u32 pending, bool use_buf_b,
|
||||
bool readfifo)
|
||||
{
|
||||
struct tty_struct *tty = uap->port.state->port.tty;
|
||||
struct tty_port *port = &uap->port.state->port;
|
||||
struct pl011_sgbuf *sgbuf = use_buf_b ?
|
||||
&uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
|
||||
struct device *dev = uap->dmarx.chan->device->dev;
|
||||
@@ -715,8 +715,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
|
||||
* Note that tty_insert_flip_buf() tries to take as many chars
|
||||
* as it can.
|
||||
*/
|
||||
dma_count = tty_insert_flip_string(uap->port.state->port.tty,
|
||||
sgbuf->buf, pending);
|
||||
dma_count = tty_insert_flip_string(port, sgbuf->buf, pending);
|
||||
|
||||
/* Return buffer to device */
|
||||
dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
|
||||
@@ -754,7 +753,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
|
||||
dev_vdbg(uap->port.dev,
|
||||
"Took %d chars from DMA buffer and %d chars from the FIFO\n",
|
||||
dma_count, fifotaken);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(port);
|
||||
spin_lock(&uap->port.lock);
|
||||
}
|
||||
|
||||
@@ -1076,12 +1075,10 @@ static void pl011_enable_ms(struct uart_port *port)
|
||||
|
||||
static void pl011_rx_chars(struct uart_amba_port *uap)
|
||||
{
|
||||
struct tty_struct *tty = uap->port.state->port.tty;
|
||||
|
||||
pl011_fifo_to_tty(uap);
|
||||
|
||||
spin_unlock(&uap->port.lock);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&uap->port.state->port);
|
||||
/*
|
||||
* If we were temporarily out of DMA mode for a while,
|
||||
* attempt to switch back to DMA mode again.
|
||||
|
@@ -78,7 +78,6 @@ static void apbuart_enable_ms(struct uart_port *port)
|
||||
|
||||
static void apbuart_rx_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
unsigned int status, ch, rsr, flag;
|
||||
unsigned int max_chars = port->fifosize;
|
||||
|
||||
@@ -126,7 +125,7 @@ static void apbuart_rx_chars(struct uart_port *port)
|
||||
status = UART_GET_STATUS(port);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void apbuart_tx_chars(struct uart_port *port)
|
||||
|
@@ -297,10 +297,9 @@ static void ar933x_uart_set_termios(struct uart_port *port,
|
||||
|
||||
static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port = &up->port.state->port;
|
||||
int max_count = 256;
|
||||
|
||||
tty = tty_port_tty_get(&up->port.state->port);
|
||||
do {
|
||||
unsigned int rdata;
|
||||
unsigned char ch;
|
||||
@@ -313,11 +312,6 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
|
||||
ar933x_uart_write(up, AR933X_UART_DATA_REG,
|
||||
AR933X_UART_DATA_RX_CSR);
|
||||
|
||||
if (!tty) {
|
||||
/* discard the data if no tty available */
|
||||
continue;
|
||||
}
|
||||
|
||||
up->port.icount.rx++;
|
||||
ch = rdata & AR933X_UART_DATA_TX_RX_MASK;
|
||||
|
||||
@@ -325,13 +319,10 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
|
||||
continue;
|
||||
|
||||
if ((up->port.ignore_status_mask & AR933X_DUMMY_STATUS_RD) == 0)
|
||||
tty_insert_flip_char(tty, ch, TTY_NORMAL);
|
||||
tty_insert_flip_char(port, ch, TTY_NORMAL);
|
||||
} while (max_count-- > 0);
|
||||
|
||||
if (tty) {
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_flip_buffer_push(port);
|
||||
}
|
||||
|
||||
static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
|
||||
|
@@ -37,6 +37,8 @@
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
/*************************************
|
||||
* ARC UART Hardware Specs
|
||||
@@ -209,12 +211,8 @@ static void arc_serial_start_tx(struct uart_port *port)
|
||||
|
||||
static void arc_serial_rx_chars(struct arc_uart_port *uart)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&uart->port.state->port);
|
||||
unsigned int status, ch, flg = 0;
|
||||
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
/*
|
||||
* UART has 4 deep RX-FIFO. Driver's recongnition of this fact
|
||||
* is very subtle. Here's how ...
|
||||
@@ -250,10 +248,8 @@ static void arc_serial_rx_chars(struct arc_uart_port *uart)
|
||||
uart_insert_char(&uart->port, status, RXOERR, ch, flg);
|
||||
|
||||
done:
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&uart->port.state->port);
|
||||
}
|
||||
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -526,18 +522,37 @@ static struct uart_ops arc_serial_pops = {
|
||||
};
|
||||
|
||||
static int
|
||||
arc_uart_init_one(struct platform_device *pdev, struct arc_uart_port *uart)
|
||||
arc_uart_init_one(struct platform_device *pdev, int dev_id)
|
||||
{
|
||||
struct resource *res, *res2;
|
||||
unsigned long *plat_data;
|
||||
|
||||
if (pdev->id < 0 || pdev->id >= CONFIG_SERIAL_ARC_NR_PORTS) {
|
||||
dev_err(&pdev->dev, "Wrong uart platform device id.\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
struct arc_uart_port *uart = &arc_uart_ports[dev_id];
|
||||
|
||||
plat_data = ((unsigned long *)(pdev->dev.platform_data));
|
||||
uart->baud = plat_data[0];
|
||||
if (!plat_data)
|
||||
return -ENODEV;
|
||||
|
||||
uart->is_emulated = !!plat_data[0]; /* workaround ISS bug */
|
||||
|
||||
if (is_early_platform_device(pdev)) {
|
||||
uart->port.uartclk = plat_data[1];
|
||||
uart->baud = plat_data[2];
|
||||
} else {
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 val;
|
||||
|
||||
if (of_property_read_u32(np, "clock-frequency", &val)) {
|
||||
dev_err(&pdev->dev, "clock-frequency property NOTset\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
uart->port.uartclk = val;
|
||||
|
||||
if (of_property_read_u32(np, "current-speed", &val)) {
|
||||
dev_err(&pdev->dev, "current-speed property NOT set\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
uart->baud = val;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
@@ -557,10 +572,9 @@ arc_uart_init_one(struct platform_device *pdev, struct arc_uart_port *uart)
|
||||
uart->port.dev = &pdev->dev;
|
||||
uart->port.iotype = UPIO_MEM;
|
||||
uart->port.flags = UPF_BOOT_AUTOCONF;
|
||||
uart->port.line = pdev->id;
|
||||
uart->port.line = dev_id;
|
||||
uart->port.ops = &arc_serial_pops;
|
||||
|
||||
uart->port.uartclk = plat_data[1];
|
||||
uart->port.fifosize = ARC_UART_TX_FIFO_SIZE;
|
||||
|
||||
/*
|
||||
@@ -569,9 +583,6 @@ arc_uart_init_one(struct platform_device *pdev, struct arc_uart_port *uart)
|
||||
*/
|
||||
uart->port.ignore_status_mask = 0;
|
||||
|
||||
/* Real Hardware vs. emulated to work around a bug */
|
||||
uart->is_emulated = !!plat_data[2];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -648,45 +659,50 @@ static __init void early_serial_write(struct console *con, const char *s,
|
||||
}
|
||||
}
|
||||
|
||||
static struct __initdata console arc_early_serial_console = {
|
||||
static struct console arc_early_serial_console __initdata = {
|
||||
.name = "early_ARCuart",
|
||||
.write = early_serial_write,
|
||||
.flags = CON_PRINTBUFFER | CON_BOOT,
|
||||
.index = -1
|
||||
};
|
||||
|
||||
static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
|
||||
static int __init arc_serial_probe_earlyprintk(struct platform_device *pdev)
|
||||
{
|
||||
arc_early_serial_console.index = pdev->id;
|
||||
int dev_id = pdev->id < 0 ? 0 : pdev->id;
|
||||
int rc;
|
||||
|
||||
arc_uart_init_one(pdev, &arc_uart_ports[pdev->id]);
|
||||
arc_early_serial_console.index = dev_id;
|
||||
|
||||
rc = arc_uart_init_one(pdev, dev_id);
|
||||
if (rc)
|
||||
panic("early console init failed\n");
|
||||
|
||||
arc_serial_console_setup(&arc_early_serial_console, NULL);
|
||||
|
||||
register_console(&arc_early_serial_console);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int arc_serial_probe_earlyprintk(struct platform_device *pdev)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_SERIAL_ARC_CONSOLE */
|
||||
|
||||
static int arc_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct arc_uart_port *uart;
|
||||
int rc;
|
||||
int rc, dev_id;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
if (is_early_platform_device(pdev))
|
||||
return arc_serial_probe_earlyprintk(pdev);
|
||||
/* no device tree device */
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
uart = &arc_uart_ports[pdev->id];
|
||||
rc = arc_uart_init_one(pdev, uart);
|
||||
dev_id = of_alias_get_id(np, "serial");
|
||||
if (dev_id < 0)
|
||||
dev_id = 0;
|
||||
|
||||
rc = arc_uart_init_one(pdev, dev_id);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return uart_add_one_port(&arc_uart_driver, &uart->port);
|
||||
rc = uart_add_one_port(&arc_uart_driver, &arc_uart_ports[dev_id].port);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int arc_serial_remove(struct platform_device *pdev)
|
||||
@@ -695,16 +711,32 @@ static int arc_serial_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id arc_uart_dt_ids[] = {
|
||||
{ .compatible = "snps,arc-uart" },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, arc_uart_dt_ids);
|
||||
|
||||
static struct platform_driver arc_platform_driver = {
|
||||
.probe = arc_serial_probe,
|
||||
.remove = arc_serial_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = arc_uart_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_ARC_CONSOLE
|
||||
|
||||
static struct platform_driver early_arc_platform_driver __initdata = {
|
||||
.probe = arc_serial_probe_earlyprintk,
|
||||
.remove = arc_serial_remove,
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
/*
|
||||
* Register an early platform driver of "earlyprintk" class.
|
||||
* ARCH platform code installs the driver and probes the early devices
|
||||
@@ -712,7 +744,7 @@ static struct platform_driver arc_platform_driver = {
|
||||
* or it could be done independently, for all "earlyprintk" class drivers.
|
||||
* [see arch/arc/plat-arcfpga/platform.c]
|
||||
*/
|
||||
early_platform_init("earlyprintk", &arc_platform_driver);
|
||||
early_platform_init("earlyprintk", &early_arc_platform_driver);
|
||||
|
||||
#endif /* CONFIG_SERIAL_ARC_CONSOLE */
|
||||
|
||||
|
@@ -774,14 +774,14 @@ static void atmel_rx_from_ring(struct uart_port *port)
|
||||
* uart_start(), which takes the lock.
|
||||
*/
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(port->state->port.tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
spin_lock(&port->lock);
|
||||
}
|
||||
|
||||
static void atmel_rx_from_dma(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct atmel_dma_buffer *pdc;
|
||||
int rx_idx = atmel_port->pdc_rx_idx;
|
||||
unsigned int head;
|
||||
@@ -820,7 +820,8 @@ static void atmel_rx_from_dma(struct uart_port *port)
|
||||
*/
|
||||
count = head - tail;
|
||||
|
||||
tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
|
||||
tty_insert_flip_string(tport, pdc->buf + pdc->ofs,
|
||||
count);
|
||||
|
||||
dma_sync_single_for_device(port->dev, pdc->dma_addr,
|
||||
pdc->dma_size, DMA_FROM_DEVICE);
|
||||
@@ -848,7 +849,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
|
||||
* uart_start(), which takes the lock.
|
||||
*/
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
spin_lock(&port->lock);
|
||||
|
||||
UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
|
||||
|
@@ -235,14 +235,13 @@ static const char *bcm_uart_type(struct uart_port *port)
|
||||
*/
|
||||
static void bcm_uart_do_rx(struct uart_port *port)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port = &port->state->port;
|
||||
unsigned int max_count;
|
||||
|
||||
/* limit number of char read in interrupt, should not be
|
||||
* higher than fifo size anyway since we're much faster than
|
||||
* serial port */
|
||||
max_count = 32;
|
||||
tty = port->state->port.tty;
|
||||
do {
|
||||
unsigned int iestat, c, cstat;
|
||||
char flag;
|
||||
@@ -261,7 +260,7 @@ static void bcm_uart_do_rx(struct uart_port *port)
|
||||
bcm_uart_writel(port, val, UART_CTL_REG);
|
||||
|
||||
port->icount.overrun++;
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||
}
|
||||
|
||||
if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
|
||||
@@ -300,11 +299,11 @@ static void bcm_uart_do_rx(struct uart_port *port)
|
||||
|
||||
|
||||
if ((cstat & port->ignore_status_mask) == 0)
|
||||
tty_insert_flip_char(tty, c, flag);
|
||||
tty_insert_flip_char(port, c, flag);
|
||||
|
||||
} while (--max_count);
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(port);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -149,7 +149,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int size, int baud_rate)
|
||||
static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sport_uart_port *up = dev_id;
|
||||
struct tty_struct *tty = up->port.state->port.tty;
|
||||
struct tty_port *port = &up->port.state->port;
|
||||
unsigned int ch;
|
||||
|
||||
spin_lock(&up->port.lock);
|
||||
@@ -159,9 +159,10 @@ static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
|
||||
up->port.icount.rx++;
|
||||
|
||||
if (!uart_handle_sysrq_char(&up->port, ch))
|
||||
tty_insert_flip_char(tty, ch, TTY_NORMAL);
|
||||
tty_insert_flip_char(port, ch, TTY_NORMAL);
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
/* XXX this won't deadlock with lowlat? */
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
spin_unlock(&up->port.lock);
|
||||
|
||||
@@ -182,7 +183,6 @@ static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id)
|
||||
static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sport_uart_port *up = dev_id;
|
||||
struct tty_struct *tty = up->port.state->port.tty;
|
||||
unsigned int stat = SPORT_GET_STAT(up);
|
||||
|
||||
spin_lock(&up->port.lock);
|
||||
@@ -190,7 +190,7 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
|
||||
/* Overflow in RX FIFO */
|
||||
if (stat & ROVF) {
|
||||
up->port.icount.overrun++;
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(&up->port.state->port, 0, TTY_OVERRUN);
|
||||
SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */
|
||||
}
|
||||
/* These should not happen */
|
||||
@@ -205,6 +205,8 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
|
||||
SSYNC();
|
||||
|
||||
spin_unlock(&up->port.lock);
|
||||
/* XXX we don't push the overrun bit to TTY? */
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@@ -223,7 +223,6 @@ static void bfin_serial_enable_ms(struct uart_port *port)
|
||||
#ifdef CONFIG_SERIAL_BFIN_PIO
|
||||
static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
|
||||
{
|
||||
struct tty_struct *tty = NULL;
|
||||
unsigned int status, ch, flg;
|
||||
static struct timeval anomaly_start = { .tv_sec = 0 };
|
||||
|
||||
@@ -242,11 +241,9 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uart->port.state || !uart->port.state->port.tty)
|
||||
if (!uart->port.state)
|
||||
return;
|
||||
#endif
|
||||
tty = uart->port.state->port.tty;
|
||||
|
||||
if (ANOMALY_05000363) {
|
||||
/* The BF533 (and BF561) family of processors have a nice anomaly
|
||||
* where they continuously generate characters for a "single" break.
|
||||
@@ -325,7 +322,7 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
|
||||
uart_insert_char(&uart->port, status, OE, ch, flg);
|
||||
|
||||
ignore_char:
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&uart->port.state->port);
|
||||
}
|
||||
|
||||
static void bfin_serial_tx_chars(struct bfin_serial_port *uart)
|
||||
@@ -426,7 +423,6 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
|
||||
|
||||
static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
|
||||
{
|
||||
struct tty_struct *tty = uart->port.state->port.tty;
|
||||
int i, flg, status;
|
||||
|
||||
status = UART_GET_LSR(uart);
|
||||
@@ -471,7 +467,7 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
|
||||
}
|
||||
|
||||
dma_ignore_char:
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&uart->port.state->port);
|
||||
}
|
||||
|
||||
void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
|
||||
|
@@ -85,12 +85,8 @@ static void uart_clps711x_enable_ms(struct uart_port *port)
|
||||
static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->state->port);
|
||||
unsigned int status, ch, flg;
|
||||
|
||||
if (!tty)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
for (;;) {
|
||||
status = clps_readl(SYSFLG(port));
|
||||
if (status & SYSFLG_URXFE)
|
||||
@@ -130,9 +126,7 @@ static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id)
|
||||
uart_insert_char(port, status, UARTDR_OVERR, ch, flg);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -245,7 +245,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
|
||||
int i;
|
||||
unsigned char ch;
|
||||
u8 *cp;
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
|
||||
cbd_t __iomem *bdp;
|
||||
u16 status;
|
||||
@@ -276,7 +276,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
|
||||
/* If we have not enough room in tty flip buffer, then we try
|
||||
* later, which will be the next rx-interrupt or a timeout
|
||||
*/
|
||||
if(tty_buffer_request_room(tty, i) < i) {
|
||||
if (tty_buffer_request_room(tport, i) < i) {
|
||||
printk(KERN_WARNING "No room in flip buffer\n");
|
||||
return;
|
||||
}
|
||||
@@ -302,7 +302,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
|
||||
}
|
||||
#endif
|
||||
error_return:
|
||||
tty_insert_flip_char(tty, ch, flg);
|
||||
tty_insert_flip_char(tport, ch, flg);
|
||||
|
||||
} /* End while (i--) */
|
||||
|
||||
@@ -322,7 +322,7 @@ static void cpm_uart_int_rx(struct uart_port *port)
|
||||
pinfo->rx_cur = bdp;
|
||||
|
||||
/* activate BH processing */
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
return;
|
||||
|
||||
@@ -507,7 +507,7 @@ static void cpm_uart_set_termios(struct uart_port *port,
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
|
||||
if (baud < HW_BUF_SPD_THRESHOLD ||
|
||||
(pinfo->port.state && pinfo->port.state->port.tty->low_latency))
|
||||
(pinfo->port.state && pinfo->port.state->port.low_latency))
|
||||
pinfo->rx_fifosize = 1;
|
||||
else
|
||||
pinfo->rx_fifosize = RX_BUF_SIZE;
|
||||
|
@@ -1760,8 +1760,7 @@ add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char fl
|
||||
|
||||
info->icount.rx++;
|
||||
} else {
|
||||
struct tty_struct *tty = info->port.tty;
|
||||
tty_insert_flip_char(tty, data, flag);
|
||||
tty_insert_flip_char(&info->port, data, flag);
|
||||
info->icount.rx++;
|
||||
}
|
||||
|
||||
@@ -2105,22 +2104,15 @@ static int force_eop_if_needed(struct e100_serial *info)
|
||||
|
||||
static void flush_to_flip_buffer(struct e100_serial *info)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
struct etrax_recv_buffer *buffer;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
tty = info->port.tty;
|
||||
|
||||
if (!tty) {
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((buffer = info->first_recv_buffer) != NULL) {
|
||||
unsigned int count = buffer->length;
|
||||
|
||||
tty_insert_flip_string(tty, buffer->buffer, count);
|
||||
tty_insert_flip_string(&info->port, buffer->buffer, count);
|
||||
info->recv_cnt -= count;
|
||||
|
||||
if (count == buffer->length) {
|
||||
@@ -2139,7 +2131,7 @@ static void flush_to_flip_buffer(struct e100_serial *info)
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* This includes a check for low-latency */
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&info->port);
|
||||
}
|
||||
|
||||
static void check_flush_timeout(struct e100_serial *info)
|
||||
@@ -2275,12 +2267,6 @@ static
|
||||
struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
|
||||
{
|
||||
unsigned long data_read;
|
||||
struct tty_struct *tty = info->port.tty;
|
||||
|
||||
if (!tty) {
|
||||
printk("!NO TTY!\n");
|
||||
return info;
|
||||
}
|
||||
|
||||
/* Read data and status at the same time */
|
||||
data_read = *((unsigned long *)&info->ioport[REG_DATA_STATUS32]);
|
||||
@@ -2338,8 +2324,7 @@ more_data:
|
||||
data_in, data_read);
|
||||
char flag = TTY_NORMAL;
|
||||
if (info->errorcode == ERRCODE_INSERT_BREAK) {
|
||||
struct tty_struct *tty = info->port.tty;
|
||||
tty_insert_flip_char(tty, 0, flag);
|
||||
tty_insert_flip_char(&info->port, 0, flag);
|
||||
info->icount.rx++;
|
||||
}
|
||||
|
||||
@@ -2353,7 +2338,7 @@ more_data:
|
||||
info->icount.frame++;
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
tty_insert_flip_char(tty, data, flag);
|
||||
tty_insert_flip_char(&info->port, data, flag);
|
||||
info->errorcode = 0;
|
||||
}
|
||||
info->break_detected_cnt = 0;
|
||||
@@ -2369,7 +2354,7 @@ more_data:
|
||||
log_int(rdpc(), 0, 0);
|
||||
}
|
||||
);
|
||||
tty_insert_flip_char(tty,
|
||||
tty_insert_flip_char(&info->port,
|
||||
IO_EXTRACT(R_SERIAL0_READ, data_in, data_read),
|
||||
TTY_NORMAL);
|
||||
} else {
|
||||
@@ -2384,7 +2369,7 @@ more_data:
|
||||
goto more_data;
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(info->port.tty);
|
||||
tty_flip_buffer_push(&info->port);
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -3137,7 +3122,7 @@ static int rs_raw_write(struct tty_struct *tty,
|
||||
|
||||
/* first some sanity checks */
|
||||
|
||||
if (!tty || !info->xmit.buf)
|
||||
if (!info->xmit.buf)
|
||||
return 0;
|
||||
|
||||
#ifdef SERIAL_DEBUG_DATA
|
||||
@@ -3464,7 +3449,7 @@ set_serial_info(struct e100_serial *info,
|
||||
info->type = new_serial.type;
|
||||
info->close_delay = new_serial.close_delay;
|
||||
info->closing_wait = new_serial.closing_wait;
|
||||
info->port.tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
info->port.low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
check_and_exit:
|
||||
if (info->flags & ASYNC_INITIALIZED) {
|
||||
@@ -4108,7 +4093,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
||||
tty->driver_data = info;
|
||||
info->port.tty = tty;
|
||||
|
||||
tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
|
||||
info->port.low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
|
||||
|
||||
/*
|
||||
* If the port is in the middle of closing, bail out now
|
||||
|
@@ -187,7 +187,6 @@ static inline void dz_receive_chars(struct dz_mux *mux)
|
||||
{
|
||||
struct uart_port *uport;
|
||||
struct dz_port *dport = &mux->dport[0];
|
||||
struct tty_struct *tty = NULL;
|
||||
struct uart_icount *icount;
|
||||
int lines_rx[DZ_NB_PORT] = { [0 ... DZ_NB_PORT - 1] = 0 };
|
||||
unsigned char ch, flag;
|
||||
@@ -197,7 +196,6 @@ static inline void dz_receive_chars(struct dz_mux *mux)
|
||||
while ((status = dz_in(dport, DZ_RBUF)) & DZ_DVAL) {
|
||||
dport = &mux->dport[LINE(status)];
|
||||
uport = &dport->port;
|
||||
tty = uport->state->port.tty; /* point to the proper dev */
|
||||
|
||||
ch = UCHAR(status); /* grab the char */
|
||||
flag = TTY_NORMAL;
|
||||
@@ -249,7 +247,7 @@ static inline void dz_receive_chars(struct dz_mux *mux)
|
||||
}
|
||||
for (i = 0; i < DZ_NB_PORT; i++)
|
||||
if (lines_rx[i])
|
||||
tty_flip_buffer_push(mux->dport[i].port.state->port.tty);
|
||||
tty_flip_buffer_push(&mux->dport[i].port.state->port);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -81,6 +81,7 @@ 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...) \
|
||||
@@ -194,8 +195,7 @@ 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 tty_struct *tty)
|
||||
static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port)
|
||||
{
|
||||
struct uart_port *port = &efm_port->port;
|
||||
|
||||
@@ -237,8 +237,8 @@ static void efm32_uart_rx_chars(struct efm32_uart_port *efm_port,
|
||||
rxdata & UARTn_RXDATAX_RXDATA__MASK))
|
||||
continue;
|
||||
|
||||
if (tty && (rxdata & port->ignore_status_mask) == 0)
|
||||
tty_insert_flip_char(tty,
|
||||
if ((rxdata & port->ignore_status_mask) == 0)
|
||||
tty_insert_flip_char(&port->state->port,
|
||||
rxdata & UARTn_RXDATAX_RXDATA__MASK, flag);
|
||||
}
|
||||
}
|
||||
@@ -249,15 +249,13 @@ static irqreturn_t efm32_uart_rxirq(int irq, void *data)
|
||||
u32 irqflag = efm32_uart_read32(efm_port, UARTn_IF);
|
||||
int handled = IRQ_NONE;
|
||||
struct uart_port *port = &efm_port->port;
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
tty = tty_kref_get(port->state->port.tty);
|
||||
|
||||
if (irqflag & UARTn_IF_RXDATAV) {
|
||||
efm32_uart_write32(efm_port, UARTn_IF_RXDATAV, UARTn_IFC);
|
||||
efm32_uart_rx_chars(efm_port, tty);
|
||||
efm32_uart_rx_chars(efm_port);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
@@ -265,16 +263,12 @@ static irqreturn_t efm32_uart_rxirq(int irq, void *data)
|
||||
if (irqflag & UARTn_IF_RXOF) {
|
||||
efm32_uart_write32(efm_port, UARTn_IF_RXOF, UARTn_IFC);
|
||||
port->icount.overrun++;
|
||||
if (tty)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (tty) {
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
@@ -300,13 +294,8 @@ static irqreturn_t efm32_uart_txirq(int irq, void *data)
|
||||
static int efm32_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct efm32_uart_port *efm_port = to_efm_port(port);
|
||||
u32 location = 0;
|
||||
struct efm32_uart_pdata *pdata = dev_get_platdata(port->dev);
|
||||
int ret;
|
||||
|
||||
if (pdata)
|
||||
location = UARTn_ROUTE_LOCATION(pdata->location);
|
||||
|
||||
ret = clk_enable(efm_port->clk);
|
||||
if (ret) {
|
||||
efm_debug(efm_port, "failed to enable clk\n");
|
||||
@@ -315,7 +304,9 @@ static int efm32_uart_startup(struct uart_port *port)
|
||||
port->uartclk = clk_get_rate(efm_port->clk);
|
||||
|
||||
/* Enable pins at configured location */
|
||||
efm32_uart_write32(efm_port, location | UARTn_ROUTE_RXPEN | UARTn_ROUTE_TXPEN,
|
||||
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,
|
||||
@@ -674,11 +665,24 @@ 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, "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);
|
||||
@@ -738,10 +742,16 @@ static int efm32_uart_probe(struct platform_device *pdev)
|
||||
efm_port->port.flags = UPF_BOOT_AUTOCONF;
|
||||
|
||||
ret = efm32_uart_probe_dt(pdev, efm_port);
|
||||
if (ret > 0)
|
||||
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;
|
||||
}
|
||||
|
||||
if (efm_port->port.line >= 0 &&
|
||||
efm_port->port.line < ARRAY_SIZE(efm32_uart_ports))
|
||||
efm32_uart_ports[efm_port->port.line] = efm_port;
|
||||
|
@@ -734,7 +734,7 @@ static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
|
||||
static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
|
||||
{
|
||||
short int count, rcv_buff;
|
||||
struct tty_struct *tty = icom_port->uart_port.state->port.tty;
|
||||
struct tty_port *port = &icom_port->uart_port.state->port;
|
||||
unsigned short int status;
|
||||
struct uart_icount *icount;
|
||||
unsigned long offset;
|
||||
@@ -761,7 +761,7 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
|
||||
/* Block copy all but the last byte as this may have status */
|
||||
if (count > 0) {
|
||||
first = icom_port->recv_buf[offset];
|
||||
tty_insert_flip_string(tty, icom_port->recv_buf + offset, count - 1);
|
||||
tty_insert_flip_string(port, icom_port->recv_buf + offset, count - 1);
|
||||
}
|
||||
|
||||
icount = &icom_port->uart_port.icount;
|
||||
@@ -812,7 +812,7 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
|
||||
|
||||
}
|
||||
|
||||
tty_insert_flip_char(tty, *(icom_port->recv_buf + offset + count - 1), flag);
|
||||
tty_insert_flip_char(port, *(icom_port->recv_buf + offset + count - 1), flag);
|
||||
|
||||
if (status & SA_FLAGS_OVERRUN)
|
||||
/*
|
||||
@@ -820,7 +820,7 @@ static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
|
||||
* reported immediately, and doesn't
|
||||
* affect the current character
|
||||
*/
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||
ignore_char:
|
||||
icom_port->statStg->rcv[rcv_buff].flags = 0;
|
||||
icom_port->statStg->rcv[rcv_buff].leLength = 0;
|
||||
@@ -834,7 +834,7 @@ ignore_char:
|
||||
status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
|
||||
}
|
||||
icom_port->next_rcv = rcv_buff;
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(port);
|
||||
}
|
||||
|
||||
static void process_interrupt(u16 port_int_reg,
|
||||
|
@@ -481,7 +481,6 @@ static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
|
||||
unsigned char *tx_buffer;
|
||||
|
||||
tx_buffer = ifx_dev->tx_buffer;
|
||||
memset(tx_buffer, 0, IFX_SPI_TRANSFER_SIZE);
|
||||
|
||||
/* make room for required SPI header */
|
||||
tx_buffer += IFX_SPI_HEADER_OVERHEAD;
|
||||
@@ -615,7 +614,7 @@ static int ifx_port_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
tty->driver_data = ifx_dev;
|
||||
|
||||
/* allows flip string push from int context */
|
||||
tty->low_latency = 1;
|
||||
port->low_latency = 1;
|
||||
|
||||
/* set flag to allows data transfer */
|
||||
set_bit(IFX_SPI_STATE_IO_AVAILABLE, &ifx_dev->flags);
|
||||
@@ -670,12 +669,8 @@ static const struct tty_operations ifx_spi_serial_ops = {
|
||||
static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,
|
||||
unsigned char *chars, size_t size)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&ifx_dev->tty_port);
|
||||
if (!tty)
|
||||
return;
|
||||
tty_insert_flip_string(tty, chars, size);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_insert_flip_string(&ifx_dev->tty_port, chars, size);
|
||||
tty_flip_buffer_push(&ifx_dev->tty_port);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -48,8 +48,8 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <linux/platform_data/serial-imx.h>
|
||||
|
||||
@@ -73,102 +73,102 @@
|
||||
#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
|
||||
|
||||
/* UART Control Register Bit Fields.*/
|
||||
#define URXD_CHARRDY (1<<15)
|
||||
#define URXD_ERR (1<<14)
|
||||
#define URXD_OVRRUN (1<<13)
|
||||
#define URXD_FRMERR (1<<12)
|
||||
#define URXD_BRK (1<<11)
|
||||
#define URXD_PRERR (1<<10)
|
||||
#define UCR1_ADEN (1<<15) /* Auto detect interrupt */
|
||||
#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
|
||||
#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
|
||||
#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
|
||||
#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
|
||||
#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
|
||||
#define UCR1_IREN (1<<7) /* Infrared interface enable */
|
||||
#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
|
||||
#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
|
||||
#define UCR1_SNDBRK (1<<4) /* Send break */
|
||||
#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
|
||||
#define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */
|
||||
#define UCR1_DOZE (1<<1) /* Doze */
|
||||
#define UCR1_UARTEN (1<<0) /* UART enabled */
|
||||
#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */
|
||||
#define UCR2_IRTS (1<<14) /* Ignore RTS pin */
|
||||
#define UCR2_CTSC (1<<13) /* CTS pin control */
|
||||
#define UCR2_CTS (1<<12) /* Clear to send */
|
||||
#define UCR2_ESCEN (1<<11) /* Escape enable */
|
||||
#define UCR2_PREN (1<<8) /* Parity enable */
|
||||
#define UCR2_PROE (1<<7) /* Parity odd/even */
|
||||
#define UCR2_STPB (1<<6) /* Stop */
|
||||
#define UCR2_WS (1<<5) /* Word size */
|
||||
#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */
|
||||
#define UCR2_ATEN (1<<3) /* Aging Timer Enable */
|
||||
#define UCR2_TXEN (1<<2) /* Transmitter enabled */
|
||||
#define UCR2_RXEN (1<<1) /* Receiver enabled */
|
||||
#define UCR2_SRST (1<<0) /* SW reset */
|
||||
#define UCR3_DTREN (1<<13) /* DTR interrupt enable */
|
||||
#define UCR3_PARERREN (1<<12) /* Parity enable */
|
||||
#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */
|
||||
#define UCR3_DSR (1<<10) /* Data set ready */
|
||||
#define UCR3_DCD (1<<9) /* Data carrier detect */
|
||||
#define UCR3_RI (1<<8) /* Ring indicator */
|
||||
#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
|
||||
#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
|
||||
#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
|
||||
#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
|
||||
#define IMX21_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select */
|
||||
#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
|
||||
#define UCR3_BPEN (1<<0) /* Preset registers enable */
|
||||
#define UCR4_CTSTL_SHF 10 /* CTS trigger level shift */
|
||||
#define UCR4_CTSTL_MASK 0x3F /* CTS trigger is 6 bits wide */
|
||||
#define UCR4_INVR (1<<9) /* Inverted infrared reception */
|
||||
#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */
|
||||
#define UCR4_WKEN (1<<7) /* Wake interrupt enable */
|
||||
#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */
|
||||
#define UCR4_IRSC (1<<5) /* IR special case */
|
||||
#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */
|
||||
#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */
|
||||
#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
|
||||
#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
|
||||
#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
|
||||
#define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */
|
||||
#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
|
||||
#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7)
|
||||
#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
|
||||
#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
|
||||
#define USR1_RTSS (1<<14) /* RTS pin status */
|
||||
#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */
|
||||
#define USR1_RTSD (1<<12) /* RTS delta */
|
||||
#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
|
||||
#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
|
||||
#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */
|
||||
#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */
|
||||
#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
|
||||
#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */
|
||||
#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */
|
||||
#define USR2_ADET (1<<15) /* Auto baud rate detect complete */
|
||||
#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */
|
||||
#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */
|
||||
#define USR2_IDLE (1<<12) /* Idle condition */
|
||||
#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */
|
||||
#define USR2_WAKE (1<<7) /* Wake */
|
||||
#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */
|
||||
#define USR2_TXDC (1<<3) /* Transmitter complete */
|
||||
#define USR2_BRCD (1<<2) /* Break condition */
|
||||
#define USR2_ORE (1<<1) /* Overrun error */
|
||||
#define USR2_RDR (1<<0) /* Recv data ready */
|
||||
#define UTS_FRCPERR (1<<13) /* Force parity error */
|
||||
#define UTS_LOOP (1<<12) /* Loop tx and rx */
|
||||
#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */
|
||||
#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */
|
||||
#define UTS_TXFULL (1<<4) /* TxFIFO full */
|
||||
#define UTS_RXFULL (1<<3) /* RxFIFO full */
|
||||
#define UTS_SOFTRST (1<<0) /* Software reset */
|
||||
#define URXD_CHARRDY (1<<15)
|
||||
#define URXD_ERR (1<<14)
|
||||
#define URXD_OVRRUN (1<<13)
|
||||
#define URXD_FRMERR (1<<12)
|
||||
#define URXD_BRK (1<<11)
|
||||
#define URXD_PRERR (1<<10)
|
||||
#define UCR1_ADEN (1<<15) /* Auto detect interrupt */
|
||||
#define UCR1_ADBR (1<<14) /* Auto detect baud rate */
|
||||
#define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */
|
||||
#define UCR1_IDEN (1<<12) /* Idle condition interrupt */
|
||||
#define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */
|
||||
#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */
|
||||
#define UCR1_IREN (1<<7) /* Infrared interface enable */
|
||||
#define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */
|
||||
#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
|
||||
#define UCR1_SNDBRK (1<<4) /* Send break */
|
||||
#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
|
||||
#define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */
|
||||
#define UCR1_DOZE (1<<1) /* Doze */
|
||||
#define UCR1_UARTEN (1<<0) /* UART enabled */
|
||||
#define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */
|
||||
#define UCR2_IRTS (1<<14) /* Ignore RTS pin */
|
||||
#define UCR2_CTSC (1<<13) /* CTS pin control */
|
||||
#define UCR2_CTS (1<<12) /* Clear to send */
|
||||
#define UCR2_ESCEN (1<<11) /* Escape enable */
|
||||
#define UCR2_PREN (1<<8) /* Parity enable */
|
||||
#define UCR2_PROE (1<<7) /* Parity odd/even */
|
||||
#define UCR2_STPB (1<<6) /* Stop */
|
||||
#define UCR2_WS (1<<5) /* Word size */
|
||||
#define UCR2_RTSEN (1<<4) /* Request to send interrupt enable */
|
||||
#define UCR2_ATEN (1<<3) /* Aging Timer Enable */
|
||||
#define UCR2_TXEN (1<<2) /* Transmitter enabled */
|
||||
#define UCR2_RXEN (1<<1) /* Receiver enabled */
|
||||
#define UCR2_SRST (1<<0) /* SW reset */
|
||||
#define UCR3_DTREN (1<<13) /* DTR interrupt enable */
|
||||
#define UCR3_PARERREN (1<<12) /* Parity enable */
|
||||
#define UCR3_FRAERREN (1<<11) /* Frame error interrupt enable */
|
||||
#define UCR3_DSR (1<<10) /* Data set ready */
|
||||
#define UCR3_DCD (1<<9) /* Data carrier detect */
|
||||
#define UCR3_RI (1<<8) /* Ring indicator */
|
||||
#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */
|
||||
#define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */
|
||||
#define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */
|
||||
#define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */
|
||||
#define IMX21_UCR3_RXDMUXSEL (1<<2) /* RXD Muxed Input Select */
|
||||
#define UCR3_INVT (1<<1) /* Inverted Infrared transmission */
|
||||
#define UCR3_BPEN (1<<0) /* Preset registers enable */
|
||||
#define UCR4_CTSTL_SHF 10 /* CTS trigger level shift */
|
||||
#define UCR4_CTSTL_MASK 0x3F /* CTS trigger is 6 bits wide */
|
||||
#define UCR4_INVR (1<<9) /* Inverted infrared reception */
|
||||
#define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */
|
||||
#define UCR4_WKEN (1<<7) /* Wake interrupt enable */
|
||||
#define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */
|
||||
#define UCR4_IRSC (1<<5) /* IR special case */
|
||||
#define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */
|
||||
#define UCR4_BKEN (1<<2) /* Break condition interrupt enable */
|
||||
#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
|
||||
#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
|
||||
#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
|
||||
#define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */
|
||||
#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
|
||||
#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7)
|
||||
#define UFCR_TXTL_SHF 10 /* Transmitter trigger level shift */
|
||||
#define USR1_PARITYERR (1<<15) /* Parity error interrupt flag */
|
||||
#define USR1_RTSS (1<<14) /* RTS pin status */
|
||||
#define USR1_TRDY (1<<13) /* Transmitter ready interrupt/dma flag */
|
||||
#define USR1_RTSD (1<<12) /* RTS delta */
|
||||
#define USR1_ESCF (1<<11) /* Escape seq interrupt flag */
|
||||
#define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */
|
||||
#define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */
|
||||
#define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */
|
||||
#define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */
|
||||
#define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */
|
||||
#define USR1_AWAKE (1<<4) /* Aysnc wake interrupt flag */
|
||||
#define USR2_ADET (1<<15) /* Auto baud rate detect complete */
|
||||
#define USR2_TXFE (1<<14) /* Transmit buffer FIFO empty */
|
||||
#define USR2_DTRF (1<<13) /* DTR edge interrupt flag */
|
||||
#define USR2_IDLE (1<<12) /* Idle condition */
|
||||
#define USR2_IRINT (1<<8) /* Serial infrared interrupt flag */
|
||||
#define USR2_WAKE (1<<7) /* Wake */
|
||||
#define USR2_RTSF (1<<4) /* RTS edge interrupt flag */
|
||||
#define USR2_TXDC (1<<3) /* Transmitter complete */
|
||||
#define USR2_BRCD (1<<2) /* Break condition */
|
||||
#define USR2_ORE (1<<1) /* Overrun error */
|
||||
#define USR2_RDR (1<<0) /* Recv data ready */
|
||||
#define UTS_FRCPERR (1<<13) /* Force parity error */
|
||||
#define UTS_LOOP (1<<12) /* Loop tx and rx */
|
||||
#define UTS_TXEMPTY (1<<6) /* TxFIFO empty */
|
||||
#define UTS_RXEMPTY (1<<5) /* RxFIFO empty */
|
||||
#define UTS_TXFULL (1<<4) /* TxFIFO full */
|
||||
#define UTS_RXFULL (1<<3) /* RxFIFO full */
|
||||
#define UTS_SOFTRST (1<<0) /* Software reset */
|
||||
|
||||
/* We've been assigned a range on the "Low-density serial ports" major */
|
||||
#define SERIAL_IMX_MAJOR 207
|
||||
#define MINOR_START 16
|
||||
#define SERIAL_IMX_MAJOR 207
|
||||
#define MINOR_START 16
|
||||
#define DEV_NAME "ttymxc"
|
||||
|
||||
/*
|
||||
@@ -199,7 +199,7 @@ struct imx_port {
|
||||
struct uart_port port;
|
||||
struct timer_list timer;
|
||||
unsigned int old_status;
|
||||
int txirq,rxirq,rtsirq;
|
||||
int txirq, rxirq, rtsirq;
|
||||
unsigned int have_rtscts:1;
|
||||
unsigned int use_irda:1;
|
||||
unsigned int irda_inv_rx:1;
|
||||
@@ -397,7 +397,7 @@ static void imx_stop_rx(struct uart_port *port)
|
||||
unsigned long temp;
|
||||
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
|
||||
writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -490,9 +490,8 @@ static irqreturn_t imx_txint(int irq, void *dev_id)
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock,flags);
|
||||
if (sport->port.x_char)
|
||||
{
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
if (sport->port.x_char) {
|
||||
/* Send next char */
|
||||
writel(sport->port.x_char, sport->port.membase + URTX0);
|
||||
goto out;
|
||||
@@ -509,18 +508,18 @@ static irqreturn_t imx_txint(int irq, void *dev_id)
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&sport->port.lock,flags);
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t imx_rxint(int irq, void *dev_id)
|
||||
{
|
||||
struct imx_port *sport = dev_id;
|
||||
unsigned int rx,flg,ignored = 0;
|
||||
struct tty_struct *tty = sport->port.state->port.tty;
|
||||
unsigned int rx, flg, ignored = 0;
|
||||
struct tty_port *port = &sport->port.state->port;
|
||||
unsigned long flags, temp;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock,flags);
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
while (readl(sport->port.membase + USR2) & USR2_RDR) {
|
||||
flg = TTY_NORMAL;
|
||||
@@ -570,12 +569,12 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
|
||||
#endif
|
||||
}
|
||||
|
||||
tty_insert_flip_char(tty, rx, flg);
|
||||
tty_insert_flip_char(port, rx, flg);
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&sport->port.lock,flags);
|
||||
tty_flip_buffer_push(tty);
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
tty_flip_buffer_push(port);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -654,7 +653,7 @@ static void imx_break_ctl(struct uart_port *port, int break_state)
|
||||
|
||||
temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
|
||||
|
||||
if ( break_state != 0 )
|
||||
if (break_state != 0)
|
||||
temp |= UCR1_SNDBRK;
|
||||
|
||||
writel(temp, sport->port.membase + UCR1);
|
||||
@@ -696,8 +695,8 @@ static int imx_startup(struct uart_port *port)
|
||||
temp |= UCR4_IRSC;
|
||||
|
||||
/* set the trigger level for CTS */
|
||||
temp &= ~(UCR4_CTSTL_MASK<< UCR4_CTSTL_SHF);
|
||||
temp |= CTSTL<< UCR4_CTSTL_SHF;
|
||||
temp &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF);
|
||||
temp |= CTSTL << UCR4_CTSTL_SHF;
|
||||
|
||||
writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
|
||||
|
||||
@@ -799,7 +798,7 @@ static int imx_startup(struct uart_port *port)
|
||||
* Enable modem status interrupts
|
||||
*/
|
||||
imx_enable_ms(&sport->port);
|
||||
spin_unlock_irqrestore(&sport->port.lock,flags);
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
|
||||
if (USE_IRDA(sport)) {
|
||||
struct imxuart_platform_data *pdata;
|
||||
@@ -909,7 +908,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
ucr2 = UCR2_SRST | UCR2_IRTS;
|
||||
|
||||
if (termios->c_cflag & CRTSCTS) {
|
||||
if( sport->have_rtscts ) {
|
||||
if (sport->have_rtscts) {
|
||||
ucr2 &= ~UCR2_IRTS;
|
||||
ucr2 |= UCR2_CTSC;
|
||||
} else {
|
||||
@@ -969,12 +968,12 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
|
||||
sport->port.membase + UCR1);
|
||||
|
||||
while ( !(readl(sport->port.membase + USR2) & USR2_TXDC))
|
||||
while (!(readl(sport->port.membase + USR2) & USR2_TXDC))
|
||||
barrier();
|
||||
|
||||
/* then, disable everything */
|
||||
old_txrxen = readl(sport->port.membase + UCR2);
|
||||
writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN),
|
||||
writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN),
|
||||
sport->port.membase + UCR2);
|
||||
old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
|
||||
|
||||
@@ -1212,9 +1211,15 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
|
||||
struct imx_port *sport = imx_ports[co->index];
|
||||
struct imx_port_ucrs old_ucr;
|
||||
unsigned int ucr1;
|
||||
unsigned long flags;
|
||||
unsigned long flags = 0;
|
||||
int locked = 1;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
if (sport->port.sysrq)
|
||||
locked = 0;
|
||||
else if (oops_in_progress)
|
||||
locked = spin_trylock_irqsave(&sport->port.lock, flags);
|
||||
else
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
/*
|
||||
* First, save UCR1/2/3 and then disable interrupts
|
||||
@@ -1241,7 +1246,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count)
|
||||
|
||||
imx_port_ucrs_restore(&sport->port, &old_ucr);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
if (locked)
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1255,7 +1261,7 @@ imx_console_get_options(struct imx_port *sport, int *baud,
|
||||
|
||||
if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) {
|
||||
/* ok, the port was enabled */
|
||||
unsigned int ucr2, ubir,ubmr, uartclk;
|
||||
unsigned int ucr2, ubir, ubmr, uartclk;
|
||||
unsigned int baud_raw;
|
||||
unsigned int ucfr_rfdiv;
|
||||
|
||||
@@ -1301,8 +1307,8 @@ imx_console_get_options(struct imx_port *sport, int *baud,
|
||||
*baud = (baud_raw + 50) / 100 * 100;
|
||||
}
|
||||
|
||||
if(*baud != baud_raw)
|
||||
printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",
|
||||
if (*baud != baud_raw)
|
||||
pr_info("Console IMX rounded baud rate from %d to %d\n",
|
||||
baud_raw, *baud);
|
||||
}
|
||||
}
|
||||
@@ -1324,7 +1330,7 @@ imx_console_setup(struct console *co, char *options)
|
||||
if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
|
||||
co->index = 0;
|
||||
sport = imx_ports[co->index];
|
||||
if(sport == NULL)
|
||||
if (sport == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
if (options)
|
||||
@@ -1462,7 +1468,7 @@ static int serial_imx_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
struct pinctrl *pinctrl;
|
||||
|
||||
sport = kzalloc(sizeof(*sport), GFP_KERNEL);
|
||||
sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
|
||||
if (!sport)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -1470,19 +1476,15 @@ static int serial_imx_probe(struct platform_device *pdev)
|
||||
if (ret > 0)
|
||||
serial_imx_probe_pdata(sport, pdev);
|
||||
else if (ret < 0)
|
||||
goto free;
|
||||
return ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
ret = -ENODEV;
|
||||
goto free;
|
||||
}
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
base = ioremap(res->start, PAGE_SIZE);
|
||||
if (!base) {
|
||||
ret = -ENOMEM;
|
||||
goto free;
|
||||
}
|
||||
base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE);
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
sport->port.dev = &pdev->dev;
|
||||
sport->port.mapbase = res->start;
|
||||
@@ -1504,21 +1506,21 @@ static int serial_imx_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(pinctrl)) {
|
||||
ret = PTR_ERR(pinctrl);
|
||||
dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret);
|
||||
goto unmap;
|
||||
return ret;
|
||||
}
|
||||
|
||||
sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
|
||||
if (IS_ERR(sport->clk_ipg)) {
|
||||
ret = PTR_ERR(sport->clk_ipg);
|
||||
dev_err(&pdev->dev, "failed to get ipg clk: %d\n", ret);
|
||||
goto unmap;
|
||||
return ret;
|
||||
}
|
||||
|
||||
sport->clk_per = devm_clk_get(&pdev->dev, "per");
|
||||
if (IS_ERR(sport->clk_per)) {
|
||||
ret = PTR_ERR(sport->clk_per);
|
||||
dev_err(&pdev->dev, "failed to get per clk: %d\n", ret);
|
||||
goto unmap;
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_prepare_enable(sport->clk_per);
|
||||
@@ -1547,11 +1549,6 @@ deinit:
|
||||
clkput:
|
||||
clk_disable_unprepare(sport->clk_per);
|
||||
clk_disable_unprepare(sport->clk_ipg);
|
||||
unmap:
|
||||
iounmap(sport->port.membase);
|
||||
free:
|
||||
kfree(sport);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1572,9 +1569,6 @@ static int serial_imx_remove(struct platform_device *pdev)
|
||||
if (pdata && pdata->exit)
|
||||
pdata->exit(pdev);
|
||||
|
||||
iounmap(sport->port.membase);
|
||||
kfree(sport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1596,7 +1590,7 @@ static int __init imx_serial_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
printk(KERN_INFO "Serial: IMX driver\n");
|
||||
pr_info("Serial: IMX driver\n");
|
||||
|
||||
ret = uart_register_driver(&imx_reg);
|
||||
if (ret)
|
||||
|
@@ -1000,7 +1000,7 @@ ioc3_change_speed(struct uart_port *the_port,
|
||||
|
||||
the_port->ignore_status_mask = N_ALL_INPUT;
|
||||
|
||||
state->port.tty->low_latency = 1;
|
||||
state->port.low_latency = 1;
|
||||
|
||||
if (iflag & IGNPAR)
|
||||
the_port->ignore_status_mask &= ~(N_PARITY_ERROR
|
||||
@@ -1393,7 +1393,6 @@ static inline int do_read(struct uart_port *the_port, char *buf, int len)
|
||||
*/
|
||||
static int receive_chars(struct uart_port *the_port)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned char ch[MAX_CHARS];
|
||||
int read_count = 0, read_room, flip = 0;
|
||||
struct uart_state *state = the_port->state;
|
||||
@@ -1403,25 +1402,23 @@ static int receive_chars(struct uart_port *the_port)
|
||||
/* Make sure all the pointers are "good" ones */
|
||||
if (!state)
|
||||
return 0;
|
||||
if (!state->port.tty)
|
||||
return 0;
|
||||
|
||||
if (!(port->ip_flags & INPUT_ENABLE))
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&the_port->lock, pflags);
|
||||
tty = state->port.tty;
|
||||
|
||||
read_count = do_read(the_port, ch, MAX_CHARS);
|
||||
if (read_count > 0) {
|
||||
flip = 1;
|
||||
read_room = tty_insert_flip_string(tty, ch, read_count);
|
||||
read_room = tty_insert_flip_string(&state->port, ch,
|
||||
read_count);
|
||||
the_port->icount.rx += read_count;
|
||||
}
|
||||
spin_unlock_irqrestore(&the_port->lock, pflags);
|
||||
|
||||
if (flip)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&state->port);
|
||||
|
||||
return read_count;
|
||||
}
|
||||
|
@@ -1740,7 +1740,7 @@ ioc4_change_speed(struct uart_port *the_port,
|
||||
|
||||
the_port->ignore_status_mask = N_ALL_INPUT;
|
||||
|
||||
state->port.tty->low_latency = 1;
|
||||
state->port.low_latency = 1;
|
||||
|
||||
if (iflag & IGNPAR)
|
||||
the_port->ignore_status_mask &= ~(N_PARITY_ERROR
|
||||
@@ -2340,7 +2340,6 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf,
|
||||
*/
|
||||
static void receive_chars(struct uart_port *the_port)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned char ch[IOC4_MAX_CHARS];
|
||||
int read_count, request_count = IOC4_MAX_CHARS;
|
||||
struct uart_icount *icount;
|
||||
@@ -2350,26 +2349,23 @@ static void receive_chars(struct uart_port *the_port)
|
||||
/* Make sure all the pointers are "good" ones */
|
||||
if (!state)
|
||||
return;
|
||||
if (!state->port.tty)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&the_port->lock, pflags);
|
||||
tty = state->port.tty;
|
||||
|
||||
request_count = tty_buffer_request_room(tty, IOC4_MAX_CHARS);
|
||||
request_count = tty_buffer_request_room(&state->port, IOC4_MAX_CHARS);
|
||||
|
||||
if (request_count > 0) {
|
||||
icount = &the_port->icount;
|
||||
read_count = do_read(the_port, ch, request_count);
|
||||
if (read_count > 0) {
|
||||
tty_insert_flip_string(tty, ch, read_count);
|
||||
tty_insert_flip_string(&state->port, ch, read_count);
|
||||
icount->rx += read_count;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&the_port->lock, pflags);
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&state->port);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2883,6 +2879,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
|
||||
/* error exits that give back resources */
|
||||
out5:
|
||||
ioc4_serial_remove_one(idd);
|
||||
return ret;
|
||||
out4:
|
||||
kfree(soft);
|
||||
out3:
|
||||
|
@@ -248,17 +248,12 @@ static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up,
|
||||
#define Rx_BRK 0x0100 /* BREAK event software flag. */
|
||||
#define Rx_SYS 0x0200 /* SysRq event software flag. */
|
||||
|
||||
static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
|
||||
static bool ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
|
||||
struct zilog_channel *channel)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned char ch, flag;
|
||||
unsigned int r1;
|
||||
|
||||
tty = NULL;
|
||||
if (up->port.state != NULL &&
|
||||
up->port.state->port.tty != NULL)
|
||||
tty = up->port.state->port.tty;
|
||||
bool push = up->port.state != NULL;
|
||||
|
||||
for (;;) {
|
||||
ch = readb(&channel->control);
|
||||
@@ -312,10 +307,10 @@ static struct tty_struct *ip22zilog_receive_chars(struct uart_ip22zilog_port *up
|
||||
if (uart_handle_sysrq_char(&up->port, ch))
|
||||
continue;
|
||||
|
||||
if (tty)
|
||||
if (push)
|
||||
uart_insert_char(&up->port, r1, Rx_OVR, ch, flag);
|
||||
}
|
||||
return tty;
|
||||
return push;
|
||||
}
|
||||
|
||||
static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
|
||||
@@ -438,21 +433,20 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
|
||||
while (up) {
|
||||
struct zilog_channel *channel
|
||||
= ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
struct tty_struct *tty;
|
||||
unsigned char r3;
|
||||
bool push = false;
|
||||
|
||||
spin_lock(&up->port.lock);
|
||||
r3 = read_zsreg(channel, R3);
|
||||
|
||||
/* Channel A */
|
||||
tty = NULL;
|
||||
if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
|
||||
writeb(RES_H_IUS, &channel->control);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
if (r3 & CHARxIP)
|
||||
tty = ip22zilog_receive_chars(up, channel);
|
||||
push = ip22zilog_receive_chars(up, channel);
|
||||
if (r3 & CHAEXT)
|
||||
ip22zilog_status_handle(up, channel);
|
||||
if (r3 & CHATxIP)
|
||||
@@ -460,22 +454,22 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
|
||||
}
|
||||
spin_unlock(&up->port.lock);
|
||||
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (push)
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
|
||||
/* Channel B */
|
||||
up = up->next;
|
||||
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
push = false;
|
||||
|
||||
spin_lock(&up->port.lock);
|
||||
tty = NULL;
|
||||
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
|
||||
writeb(RES_H_IUS, &channel->control);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
if (r3 & CHBRxIP)
|
||||
tty = ip22zilog_receive_chars(up, channel);
|
||||
push = ip22zilog_receive_chars(up, channel);
|
||||
if (r3 & CHBEXT)
|
||||
ip22zilog_status_handle(up, channel);
|
||||
if (r3 & CHBTxIP)
|
||||
@@ -483,8 +477,8 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
|
||||
}
|
||||
spin_unlock(&up->port.lock);
|
||||
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (push)
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
|
||||
up = up->next;
|
||||
}
|
||||
|
@@ -521,6 +521,7 @@ void jsm_input(struct jsm_channel *ch)
|
||||
{
|
||||
struct jsm_board *bd;
|
||||
struct tty_struct *tp;
|
||||
struct tty_port *port;
|
||||
u32 rmask;
|
||||
u16 head;
|
||||
u16 tail;
|
||||
@@ -536,7 +537,8 @@ void jsm_input(struct jsm_channel *ch)
|
||||
if (!ch)
|
||||
return;
|
||||
|
||||
tp = ch->uart_port.state->port.tty;
|
||||
port = &ch->uart_port.state->port;
|
||||
tp = port->tty;
|
||||
|
||||
bd = ch->ch_bd;
|
||||
if(!bd)
|
||||
@@ -600,7 +602,7 @@ void jsm_input(struct jsm_channel *ch)
|
||||
return;
|
||||
}
|
||||
|
||||
len = tty_buffer_request_room(tp, data_len);
|
||||
len = tty_buffer_request_room(port, data_len);
|
||||
n = len;
|
||||
|
||||
/*
|
||||
@@ -629,16 +631,16 @@ void jsm_input(struct jsm_channel *ch)
|
||||
* format it likes.
|
||||
*/
|
||||
if (*(ch->ch_equeue +tail +i) & UART_LSR_BI)
|
||||
tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_BREAK);
|
||||
tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_BREAK);
|
||||
else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE)
|
||||
tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY);
|
||||
tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_PARITY);
|
||||
else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
|
||||
tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME);
|
||||
tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_FRAME);
|
||||
else
|
||||
tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
|
||||
tty_insert_flip_char(port, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
|
||||
}
|
||||
} else {
|
||||
tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ;
|
||||
tty_insert_flip_string(port, ch->ch_rqueue + tail, s);
|
||||
}
|
||||
tail += s;
|
||||
n -= s;
|
||||
@@ -652,7 +654,7 @@ void jsm_input(struct jsm_channel *ch)
|
||||
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
|
||||
|
||||
/* Tell the tty layer its okay to "eat" the data now */
|
||||
tty_flip_buffer_push(tp);
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
jsm_dbg(IOCTL, &ch->ch_bd->pci_dev, "finish\n");
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/tick.h>
|
||||
@@ -202,7 +203,6 @@ bool kgdb_nmi_poll_knock(void)
|
||||
static void kgdb_nmi_tty_receiver(unsigned long data)
|
||||
{
|
||||
struct kgdb_nmi_tty_priv *priv = (void *)data;
|
||||
struct tty_struct *tty;
|
||||
char ch;
|
||||
|
||||
tasklet_schedule(&priv->tlet);
|
||||
@@ -210,16 +210,9 @@ static void kgdb_nmi_tty_receiver(unsigned long data)
|
||||
if (likely(!kgdb_nmi_tty_enabled || !kfifo_len(&priv->fifo)))
|
||||
return;
|
||||
|
||||
/* Port is there, but tty might be hung up, check. */
|
||||
tty = tty_port_tty_get(kgdb_nmi_port);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
while (kfifo_out(&priv->fifo, &ch, 1))
|
||||
tty_insert_flip_char(priv->port.tty, ch, TTY_NORMAL);
|
||||
tty_flip_buffer_push(priv->port.tty);
|
||||
|
||||
tty_kref_put(tty);
|
||||
tty_insert_flip_char(&priv->port, ch, TTY_NORMAL);
|
||||
tty_flip_buffer_push(&priv->port);
|
||||
}
|
||||
|
||||
static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
|
@@ -162,21 +162,16 @@ lqasc_enable_ms(struct uart_port *port)
|
||||
static int
|
||||
lqasc_rx_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->state->port);
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int ch = 0, rsr = 0, fifocnt;
|
||||
|
||||
if (!tty) {
|
||||
dev_dbg(port->dev, "%s:tty is busy now", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
fifocnt =
|
||||
ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
|
||||
fifocnt = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK;
|
||||
while (fifocnt--) {
|
||||
u8 flag = TTY_NORMAL;
|
||||
ch = ltq_r8(port->membase + LTQ_ASC_RBUF);
|
||||
rsr = (ltq_r32(port->membase + LTQ_ASC_STATE)
|
||||
& ASCSTATE_ANY) | UART_DUMMY_UER_RX;
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
port->icount.rx++;
|
||||
|
||||
/*
|
||||
@@ -208,7 +203,7 @@ lqasc_rx_chars(struct uart_port *port)
|
||||
}
|
||||
|
||||
if ((rsr & port->ignore_status_mask) == 0)
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(tport, ch, flag);
|
||||
|
||||
if (rsr & ASCSTATE_ROE)
|
||||
/*
|
||||
@@ -216,11 +211,12 @@ lqasc_rx_chars(struct uart_port *port)
|
||||
* immediately, and doesn't affect the current
|
||||
* character
|
||||
*/
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
}
|
||||
|
||||
if (ch != 0)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -257,17 +257,8 @@ static void __serial_uart_flush(struct uart_port *port)
|
||||
|
||||
static void __serial_lpc32xx_rx(struct uart_port *port)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int tmp, flag;
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->state->port);
|
||||
|
||||
if (!tty) {
|
||||
/* Discard data: no tty available */
|
||||
while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) &
|
||||
LPC32XX_HSU_RX_EMPTY))
|
||||
;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read data from FIFO and push into terminal */
|
||||
tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
|
||||
@@ -281,15 +272,14 @@ static void __serial_lpc32xx_rx(struct uart_port *port)
|
||||
LPC32XX_HSUART_IIR(port->membase));
|
||||
port->icount.frame++;
|
||||
flag = TTY_FRAME;
|
||||
tty_insert_flip_char(tty, 0, TTY_FRAME);
|
||||
tty_insert_flip_char(tport, 0, TTY_FRAME);
|
||||
}
|
||||
|
||||
tty_insert_flip_char(tty, (tmp & 0xFF), flag);
|
||||
tty_insert_flip_char(tport, (tmp & 0xFF), flag);
|
||||
|
||||
tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
static void __serial_lpc32xx_tx(struct uart_port *port)
|
||||
@@ -332,7 +322,7 @@ exit_tx:
|
||||
static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->state->port);
|
||||
struct tty_port *tport = &port->state->port;
|
||||
u32 status;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
@@ -356,17 +346,14 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
|
||||
writel(LPC32XX_HSU_RX_OE_INT,
|
||||
LPC32XX_HSUART_IIR(port->membase));
|
||||
port->icount.overrun++;
|
||||
if (tty) {
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_schedule_flip(tty);
|
||||
}
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
tty_schedule_flip(tport);
|
||||
}
|
||||
|
||||
/* Data received? */
|
||||
if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) {
|
||||
__serial_lpc32xx_rx(port);
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
/* Transmit data request? */
|
||||
@@ -376,7 +363,6 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
tty_kref_put(tty);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -300,7 +300,7 @@ static void m32r_sio_enable_ms(struct uart_port *port)
|
||||
|
||||
static void receive_chars(struct uart_sio_port *up, int *status)
|
||||
{
|
||||
struct tty_struct *tty = up->port.state->port.tty;
|
||||
struct tty_port *port = &up->port.state->port;
|
||||
unsigned char ch;
|
||||
unsigned char flag;
|
||||
int max_count = 256;
|
||||
@@ -355,7 +355,7 @@ static void receive_chars(struct uart_sio_port *up, int *status)
|
||||
if (uart_handle_sysrq_char(&up->port, ch))
|
||||
goto ignore_char;
|
||||
if ((*status & up->port.ignore_status_mask) == 0)
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(port, ch, flag);
|
||||
|
||||
if (*status & UART_LSR_OE) {
|
||||
/*
|
||||
@@ -363,12 +363,12 @@ static void receive_chars(struct uart_sio_port *up, int *status)
|
||||
* immediately, and doesn't affect the current
|
||||
* character.
|
||||
*/
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||
}
|
||||
ignore_char:
|
||||
*status = serial_in(up, UART_LSR);
|
||||
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(port);
|
||||
}
|
||||
|
||||
static void transmit_chars(struct uart_sio_port *up)
|
||||
|
@@ -310,8 +310,8 @@ static void max3100_work(struct work_struct *w)
|
||||
}
|
||||
}
|
||||
|
||||
if (rxchars > 16 && s->port.state->port.tty != NULL) {
|
||||
tty_flip_buffer_push(s->port.state->port.tty);
|
||||
if (rxchars > 16) {
|
||||
tty_flip_buffer_push(&s->port.state->port);
|
||||
rxchars = 0;
|
||||
}
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
@@ -323,8 +323,8 @@ static void max3100_work(struct work_struct *w)
|
||||
(!uart_circ_empty(xmit) &&
|
||||
!uart_tx_stopped(&s->port))));
|
||||
|
||||
if (rxchars > 0 && s->port.state->port.tty != NULL)
|
||||
tty_flip_buffer_push(s->port.state->port.tty);
|
||||
if (rxchars > 0)
|
||||
tty_flip_buffer_push(&s->port.state->port);
|
||||
}
|
||||
|
||||
static irqreturn_t max3100_irq(int irqno, void *dev_id)
|
||||
@@ -529,7 +529,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
MAX3100_STATUS_OE;
|
||||
|
||||
/* we are sending char from a workqueue so enable */
|
||||
s->port.state->port.tty->low_latency = 1;
|
||||
s->port.state->port.low_latency = 1;
|
||||
|
||||
if (s->poll_time > 0)
|
||||
del_timer_sync(&s->timer);
|
||||
|
@@ -460,10 +460,6 @@ static int max310x_set_ref_clk(struct max310x_port *s)
|
||||
static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen)
|
||||
{
|
||||
unsigned int sts = 0, ch = 0, flag;
|
||||
struct tty_struct *tty = tty_port_tty_get(&s->port.state->port);
|
||||
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
if (unlikely(rxlen >= MAX310X_FIFO_SIZE)) {
|
||||
dev_warn(s->port.dev, "Possible RX FIFO overrun %d\n", rxlen);
|
||||
@@ -516,9 +512,7 @@ static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen)
|
||||
ch, flag);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(&s->port.state->port);
|
||||
}
|
||||
|
||||
static void max310x_handle_tx(struct max310x_port *s)
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/coldfire.h>
|
||||
#include <asm/mcfsim.h>
|
||||
#include <asm/mcfuart.h>
|
||||
@@ -55,6 +56,7 @@ struct mcf_uart {
|
||||
struct uart_port port;
|
||||
unsigned int sigs; /* Local copy of line sigs */
|
||||
unsigned char imr; /* Local IMR mirror */
|
||||
struct serial_rs485 rs485; /* RS485 settings */
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -101,6 +103,12 @@ static void mcf_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
||||
|
||||
if (pp->rs485.flags & SER_RS485_ENABLED) {
|
||||
/* Enable Transmitter */
|
||||
writeb(MCFUART_UCR_TXENABLE, port->membase + MCFUART_UCR);
|
||||
/* Manually assert RTS */
|
||||
writeb(MCFUART_UOP_RTS, port->membase + MCFUART_UOP1);
|
||||
}
|
||||
pp->imr |= MCFUART_UIR_TXREADY;
|
||||
writeb(pp->imr, port->membase + MCFUART_UIMR);
|
||||
}
|
||||
@@ -196,6 +204,7 @@ static void mcf_shutdown(struct uart_port *port)
|
||||
static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
||||
unsigned long flags;
|
||||
unsigned int baud, baudclk;
|
||||
#if defined(CONFIG_M5272)
|
||||
@@ -248,6 +257,11 @@ static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
mr2 |= MCFUART_MR2_TXCTS;
|
||||
}
|
||||
|
||||
if (pp->rs485.flags & SER_RS485_ENABLED) {
|
||||
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||
mr2 |= MCFUART_MR2_TXRTS;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
writeb(MCFUART_UCR_CMDRESETRX, port->membase + MCFUART_UCR);
|
||||
@@ -310,7 +324,7 @@ static void mcf_rx_chars(struct mcf_uart *pp)
|
||||
uart_insert_char(port, status, MCFUART_USR_RXOVERRUN, ch, flag);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(port->state->port.tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
@@ -342,6 +356,10 @@ static void mcf_tx_chars(struct mcf_uart *pp)
|
||||
if (xmit->head == xmit->tail) {
|
||||
pp->imr &= ~MCFUART_UIR_TXREADY;
|
||||
writeb(pp->imr, port->membase + MCFUART_UIMR);
|
||||
/* Disable TX to negate RTS automatically */
|
||||
if (pp->rs485.flags & SER_RS485_ENABLED)
|
||||
writeb(MCFUART_UCR_TXDISABLE,
|
||||
port->membase + MCFUART_UCR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,6 +436,58 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Enable or disable the RS485 support */
|
||||
static void mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
{
|
||||
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
||||
unsigned long flags;
|
||||
unsigned char mr1, mr2;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
/* Get mode registers */
|
||||
mr1 = readb(port->membase + MCFUART_UMR);
|
||||
mr2 = readb(port->membase + MCFUART_UMR);
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
dev_dbg(port->dev, "Setting UART to RS485\n");
|
||||
/* Automatically negate RTS after TX completes */
|
||||
mr2 |= MCFUART_MR2_TXRTS;
|
||||
} else {
|
||||
dev_dbg(port->dev, "Setting UART to RS232\n");
|
||||
mr2 &= ~MCFUART_MR2_TXRTS;
|
||||
}
|
||||
writeb(mr1, port->membase + MCFUART_UMR);
|
||||
writeb(mr2, port->membase + MCFUART_UMR);
|
||||
pp->rs485 = *rs485;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static int mcf_ioctl(struct uart_port *port, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case TIOCSRS485: {
|
||||
struct serial_rs485 rs485;
|
||||
if (copy_from_user(&rs485, (struct serial_rs485 *)arg,
|
||||
sizeof(struct serial_rs485)))
|
||||
return -EFAULT;
|
||||
mcf_config_rs485(port, &rs485);
|
||||
break;
|
||||
}
|
||||
case TIOCGRS485: {
|
||||
struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
|
||||
if (copy_to_user((struct serial_rs485 *)arg, &pp->rs485,
|
||||
sizeof(struct serial_rs485)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* Define the basic serial functions we support.
|
||||
*/
|
||||
@@ -438,6 +508,7 @@ static const struct uart_ops mcf_uart_ops = {
|
||||
.release_port = mcf_release_port,
|
||||
.config_port = mcf_config_port,
|
||||
.verify_port = mcf_verify_port,
|
||||
.ioctl = mcf_ioctl,
|
||||
};
|
||||
|
||||
static struct mcf_uart mcf_ports[4];
|
||||
|
@@ -387,12 +387,9 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
|
||||
struct hsu_dma_buffer *dbuf = &up->rxbuf;
|
||||
struct hsu_dma_chan *chan = up->rxc;
|
||||
struct uart_port *port = &up->port;
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
int count;
|
||||
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
/*
|
||||
* First need to know how many is already transferred,
|
||||
* then check if its a timeout DMA irq, and return
|
||||
@@ -423,7 +420,7 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
|
||||
* explicitly set tail to 0. So head will
|
||||
* always be greater than tail.
|
||||
*/
|
||||
tty_insert_flip_string(tty, dbuf->buf, count);
|
||||
tty_insert_flip_string(tport, dbuf->buf, count);
|
||||
port->icount.rx += count;
|
||||
|
||||
dma_sync_single_for_device(up->port.dev, dbuf->dma_addr,
|
||||
@@ -437,7 +434,7 @@ void hsu_dma_rx(struct uart_hsu_port *up, u32 int_sts)
|
||||
| (0x1 << 16)
|
||||
| (0x1 << 24) /* timeout bit, see HSU Errata 1 */
|
||||
);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
chan_writel(chan, HSU_CH_CR, 0x3);
|
||||
|
||||
@@ -460,13 +457,9 @@ static void serial_hsu_stop_rx(struct uart_port *port)
|
||||
|
||||
static inline void receive_chars(struct uart_hsu_port *up, int *status)
|
||||
{
|
||||
struct tty_struct *tty = up->port.state->port.tty;
|
||||
unsigned int ch, flag;
|
||||
unsigned int max_count = 256;
|
||||
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
do {
|
||||
ch = serial_in(up, UART_RX);
|
||||
flag = TTY_NORMAL;
|
||||
@@ -522,7 +515,7 @@ static inline void receive_chars(struct uart_hsu_port *up, int *status)
|
||||
ignore_char:
|
||||
*status = serial_in(up, UART_LSR);
|
||||
} while ((*status & UART_LSR_DR) && max_count--);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
}
|
||||
|
||||
static void transmit_chars(struct uart_hsu_port *up)
|
||||
|
@@ -941,7 +941,7 @@ static struct uart_ops mpc52xx_uart_ops = {
|
||||
static inline int
|
||||
mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char ch, flag;
|
||||
unsigned short status;
|
||||
|
||||
@@ -986,20 +986,20 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
||||
out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
|
||||
|
||||
}
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(tport, ch, flag);
|
||||
if (status & MPC52xx_PSC_SR_OE) {
|
||||
/*
|
||||
* Overrun is special, since it's
|
||||
* reported immediately, and doesn't
|
||||
* affect the current character
|
||||
*/
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
port->icount.overrun++;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
spin_lock(&port->lock);
|
||||
|
||||
return psc_ops->raw_rx_rdy(port);
|
||||
|
@@ -937,7 +937,7 @@ static int serial_polled;
|
||||
static int mpsc_rx_intr(struct mpsc_port_info *pi)
|
||||
{
|
||||
struct mpsc_rx_desc *rxre;
|
||||
struct tty_struct *tty = pi->port.state->port.tty;
|
||||
struct tty_port *port = &pi->port.state->port;
|
||||
u32 cmdstat, bytes_in, i;
|
||||
int rc = 0;
|
||||
u8 *bp;
|
||||
@@ -968,10 +968,9 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi)
|
||||
}
|
||||
#endif
|
||||
/* Following use of tty struct directly is deprecated */
|
||||
if (unlikely(tty_buffer_request_room(tty, bytes_in)
|
||||
< bytes_in)) {
|
||||
if (tty->low_latency)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (tty_buffer_request_room(port, bytes_in) < bytes_in) {
|
||||
if (port->low_latency)
|
||||
tty_flip_buffer_push(port);
|
||||
/*
|
||||
* If this failed then we will throw away the bytes
|
||||
* but must do so to clear interrupts.
|
||||
@@ -1040,10 +1039,10 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi)
|
||||
| SDMA_DESC_CMDSTAT_FR
|
||||
| SDMA_DESC_CMDSTAT_OR)))
|
||||
&& !(cmdstat & pi->port.ignore_status_mask)) {
|
||||
tty_insert_flip_char(tty, *bp, flag);
|
||||
tty_insert_flip_char(port, *bp, flag);
|
||||
} else {
|
||||
for (i=0; i<bytes_in; i++)
|
||||
tty_insert_flip_char(tty, *bp++, TTY_NORMAL);
|
||||
tty_insert_flip_char(port, *bp++, TTY_NORMAL);
|
||||
|
||||
pi->port.icount.rx += bytes_in;
|
||||
}
|
||||
@@ -1081,7 +1080,7 @@ next_frame:
|
||||
if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
|
||||
mpsc_start_rx(pi);
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(port);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@@ -339,7 +339,7 @@ static int
|
||||
receive_chars(struct uart_max3110 *max, unsigned short *str, int len)
|
||||
{
|
||||
struct uart_port *port = &max->port;
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *tport;
|
||||
char buf[M3110_RX_FIFO_DEPTH];
|
||||
int r, w, usable;
|
||||
|
||||
@@ -347,9 +347,7 @@ receive_chars(struct uart_max3110 *max, unsigned short *str, int len)
|
||||
if (!port->state)
|
||||
return 0;
|
||||
|
||||
tty = tty_port_tty_get(&port->state->port);
|
||||
if (!tty)
|
||||
return 0;
|
||||
tport = &port->state->port;
|
||||
|
||||
for (r = 0, w = 0; r < len; r++) {
|
||||
if (str[r] & MAX3110_BREAK &&
|
||||
@@ -364,20 +362,17 @@ receive_chars(struct uart_max3110 *max, unsigned short *str, int len)
|
||||
}
|
||||
}
|
||||
|
||||
if (!w) {
|
||||
tty_kref_put(tty);
|
||||
if (!w)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (r = 0; w; r += usable, w -= usable) {
|
||||
usable = tty_buffer_request_room(tty, w);
|
||||
usable = tty_buffer_request_room(tport, w);
|
||||
if (usable) {
|
||||
tty_insert_flip_string(tty, buf + r, usable);
|
||||
tty_insert_flip_string(tport, buf + r, usable);
|
||||
port->icount.rx += usable;
|
||||
}
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
return r;
|
||||
}
|
||||
@@ -493,7 +488,7 @@ static int serial_m3110_startup(struct uart_port *port)
|
||||
| WC_BAUD_DR2;
|
||||
|
||||
/* as we use thread to handle tx/rx, need set low latency */
|
||||
port->state->port.tty->low_latency = 1;
|
||||
port->state->port.low_latency = 1;
|
||||
|
||||
if (max->irq) {
|
||||
max->read_thread = NULL;
|
||||
|
@@ -91,14 +91,14 @@ static void msm_enable_ms(struct uart_port *port)
|
||||
|
||||
static void handle_rx_dm(struct uart_port *port, unsigned int misr)
|
||||
{
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int sr;
|
||||
int count = 0;
|
||||
struct msm_port *msm_port = UART_TO_MSM(port);
|
||||
|
||||
if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
|
||||
port->icount.overrun++;
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
|
||||
}
|
||||
|
||||
@@ -132,12 +132,12 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr)
|
||||
port->icount.frame++;
|
||||
|
||||
/* TODO: handle sysrq */
|
||||
tty_insert_flip_string(tty, (char *) &c,
|
||||
tty_insert_flip_string(tport, (char *)&c,
|
||||
(count > 4) ? 4 : count);
|
||||
count -= 4;
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
if (misr & (UART_IMR_RXSTALE))
|
||||
msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR);
|
||||
msm_write(port, 0xFFFFFF, UARTDM_DMRX);
|
||||
@@ -146,7 +146,7 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr)
|
||||
|
||||
static void handle_rx(struct uart_port *port)
|
||||
{
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned int sr;
|
||||
|
||||
/*
|
||||
@@ -155,7 +155,7 @@ static void handle_rx(struct uart_port *port)
|
||||
*/
|
||||
if ((msm_read(port, UART_SR) & UART_SR_OVERRUN)) {
|
||||
port->icount.overrun++;
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR);
|
||||
}
|
||||
|
||||
@@ -186,10 +186,10 @@ static void handle_rx(struct uart_port *port)
|
||||
}
|
||||
|
||||
if (!uart_handle_sysrq_char(port, c))
|
||||
tty_insert_flip_char(tty, c, flag);
|
||||
tty_insert_flip_char(tport, c, flag);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
static void reset_dm_count(struct uart_port *port)
|
||||
|
@@ -908,6 +908,7 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
|
||||
unsigned long flags;
|
||||
unsigned int flush;
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port;
|
||||
struct uart_port *uport;
|
||||
struct msm_hs_port *msm_uport;
|
||||
|
||||
@@ -917,7 +918,8 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
|
||||
spin_lock_irqsave(&uport->lock, flags);
|
||||
clk_enable(msm_uport->clk);
|
||||
|
||||
tty = uport->state->port.tty;
|
||||
port = &uport->state->port;
|
||||
tty = port->tty;
|
||||
|
||||
msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
|
||||
|
||||
@@ -926,7 +928,7 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
|
||||
/* overflow is not connect to data in a FIFO */
|
||||
if (unlikely((status & UARTDM_SR_OVERRUN_BMSK) &&
|
||||
(uport->read_status_mask & CREAD))) {
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||
uport->icount.buf_overrun++;
|
||||
error_f = 1;
|
||||
}
|
||||
@@ -939,7 +941,7 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
|
||||
uport->icount.parity++;
|
||||
error_f = 1;
|
||||
if (uport->ignore_status_mask & IGNPAR)
|
||||
tty_insert_flip_char(tty, 0, TTY_PARITY);
|
||||
tty_insert_flip_char(port, 0, TTY_PARITY);
|
||||
}
|
||||
|
||||
if (error_f)
|
||||
@@ -959,7 +961,7 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
|
||||
rx_count = msm_hs_read(uport, UARTDM_RX_TOTAL_SNAP_ADDR);
|
||||
|
||||
if (0 != (uport->read_status_mask & CREAD)) {
|
||||
retval = tty_insert_flip_string(tty, msm_uport->rx.buffer,
|
||||
retval = tty_insert_flip_string(port, msm_uport->rx.buffer,
|
||||
rx_count);
|
||||
BUG_ON(retval != rx_count);
|
||||
}
|
||||
@@ -979,9 +981,8 @@ static void msm_hs_tty_flip_buffer_work(struct work_struct *work)
|
||||
{
|
||||
struct msm_hs_port *msm_uport =
|
||||
container_of(work, struct msm_hs_port, rx.tty_work);
|
||||
struct tty_struct *tty = msm_uport->uport.state->port.tty;
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&msm_uport->uport.state->port);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1344,7 +1345,6 @@ static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev)
|
||||
unsigned long flags;
|
||||
struct msm_hs_port *msm_uport = dev;
|
||||
struct uart_port *uport = &msm_uport->uport;
|
||||
struct tty_struct *tty = NULL;
|
||||
|
||||
spin_lock_irqsave(&uport->lock, flags);
|
||||
if (msm_uport->clk_state == MSM_HS_CLK_OFF) {
|
||||
@@ -1361,8 +1361,7 @@ static irqreturn_t msm_hs_rx_wakeup_isr(int irq, void *dev)
|
||||
* optionally inject char into tty rx */
|
||||
msm_hs_request_clock_on_locked(uport);
|
||||
if (msm_uport->rx_wakeup.inject_rx) {
|
||||
tty = uport->state->port.tty;
|
||||
tty_insert_flip_char(tty,
|
||||
tty_insert_flip_char(&uport->state->port,
|
||||
msm_uport->rx_wakeup.rx_to_inject,
|
||||
TTY_NORMAL);
|
||||
queue_work(msm_hs_workqueue, &msm_uport->rx.tty_work);
|
||||
@@ -1400,7 +1399,7 @@ static int msm_hs_startup(struct uart_port *uport)
|
||||
|
||||
/* do not let tty layer execute RX in global workqueue, use a
|
||||
* dedicated workqueue managed by this driver */
|
||||
uport->state->port.tty->low_latency = 1;
|
||||
uport->state->port.low_latency = 1;
|
||||
|
||||
/* turn on uart clk */
|
||||
ret = msm_hs_init_clk_locked(uport);
|
||||
|
@@ -70,7 +70,7 @@ static void smd_tty_notify(void *priv, unsigned event)
|
||||
if (avail == 0)
|
||||
break;
|
||||
|
||||
avail = tty_prepare_flip_string(tty, &ptr, avail);
|
||||
avail = tty_prepare_flip_string(&info->port, &ptr, avail);
|
||||
|
||||
if (smd_read(info->ch, ptr, avail) != avail) {
|
||||
/* shouldn't be possible since we're in interrupt
|
||||
@@ -80,7 +80,7 @@ static void smd_tty_notify(void *priv, unsigned event)
|
||||
pr_err("OOPS - smd_tty_buffer mismatch?!");
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&info->port);
|
||||
}
|
||||
|
||||
/* XXX only when writable and necessary */
|
||||
|
@@ -242,8 +242,8 @@ static void mux_write(struct uart_port *port)
|
||||
*/
|
||||
static void mux_read(struct uart_port *port)
|
||||
{
|
||||
struct tty_port *tport = &port->state->port;
|
||||
int data;
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
__u32 start_count = port->icount.rx;
|
||||
|
||||
while(1) {
|
||||
@@ -266,12 +266,11 @@ static void mux_read(struct uart_port *port)
|
||||
if (uart_handle_sysrq_char(port, data & 0xffu))
|
||||
continue;
|
||||
|
||||
tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
|
||||
tty_insert_flip_char(tport, data & 0xFF, TTY_NORMAL);
|
||||
}
|
||||
|
||||
if (start_count != port->icount.rx) {
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
if (start_count != port->icount.rx)
|
||||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -364,7 +364,6 @@ out:
|
||||
|
||||
static void mxs_auart_rx_chars(struct mxs_auart_port *s)
|
||||
{
|
||||
struct tty_struct *tty = s->port.state->port.tty;
|
||||
u32 stat = 0;
|
||||
|
||||
for (;;) {
|
||||
@@ -375,7 +374,7 @@ static void mxs_auart_rx_chars(struct mxs_auart_port *s)
|
||||
}
|
||||
|
||||
writel(stat, s->port.membase + AUART_STAT);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&s->port.state->port);
|
||||
}
|
||||
|
||||
static int mxs_auart_request_port(struct uart_port *u)
|
||||
@@ -459,7 +458,7 @@ static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s);
|
||||
static void dma_rx_callback(void *arg)
|
||||
{
|
||||
struct mxs_auart_port *s = (struct mxs_auart_port *) arg;
|
||||
struct tty_struct *tty = s->port.state->port.tty;
|
||||
struct tty_port *port = &s->port.state->port;
|
||||
int count;
|
||||
u32 stat;
|
||||
|
||||
@@ -470,10 +469,10 @@ static void dma_rx_callback(void *arg)
|
||||
AUART_STAT_PERR | AUART_STAT_FERR);
|
||||
|
||||
count = stat & AUART_STAT_RXCOUNT_MASK;
|
||||
tty_insert_flip_string(tty, s->rx_dma_buf, count);
|
||||
tty_insert_flip_string(port, s->rx_dma_buf, count);
|
||||
|
||||
writel(stat, s->port.membase + AUART_STAT);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
/* start the next DMA for RX. */
|
||||
mxs_auart_dma_prep_rx(s);
|
||||
@@ -552,7 +551,7 @@ static int mxs_auart_dma_init(struct mxs_auart_port *s)
|
||||
return 0;
|
||||
|
||||
/* We do not get the right DMA channels. */
|
||||
if (s->dma_channel_rx == -1 || s->dma_channel_rx == -1)
|
||||
if (s->dma_channel_rx == -1 || s->dma_channel_tx == -1)
|
||||
return -EINVAL;
|
||||
|
||||
/* init for RX */
|
||||
|
@@ -199,7 +199,6 @@ static void netx_txint(struct uart_port *port)
|
||||
static void netx_rxint(struct uart_port *port)
|
||||
{
|
||||
unsigned char rx, flg, status;
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
|
||||
while (!(readl(port->membase + UART_FR) & FR_RXFE)) {
|
||||
rx = readl(port->membase + UART_DR);
|
||||
@@ -237,8 +236,7 @@ static void netx_rxint(struct uart_port *port)
|
||||
uart_insert_char(port, status, SR_OE, rx, flg);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
return;
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static irqreturn_t netx_int(int irq, void *dev_id)
|
||||
|
@@ -128,7 +128,7 @@ static void nwpserial_config_port(struct uart_port *port, int flags)
|
||||
static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct nwpserial_port *up = dev_id;
|
||||
struct tty_struct *tty = up->port.state->port.tty;
|
||||
struct tty_port *port = &up->port.state->port;
|
||||
irqreturn_t ret;
|
||||
unsigned int iir;
|
||||
unsigned char ch;
|
||||
@@ -146,10 +146,10 @@ static irqreturn_t nwpserial_interrupt(int irq, void *dev_id)
|
||||
up->port.icount.rx++;
|
||||
ch = dcr_read(up->dcr_host, UART_RX);
|
||||
if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID)
|
||||
tty_insert_flip_char(tty, ch, TTY_NORMAL);
|
||||
tty_insert_flip_char(port, ch, TTY_NORMAL);
|
||||
} while (dcr_read(up->dcr_host, UART_LSR) & UART_LSR_DR);
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(port);
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
/* clear interrupt */
|
||||
|
@@ -18,7 +18,6 @@
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_serial.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/nwpserial.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -45,8 +44,10 @@ void tegra_serial_handle_break(struct uart_port *p)
|
||||
udelay(1);
|
||||
} while (1);
|
||||
}
|
||||
/* FIXME remove this export when tegra finishes conversion to open firmware */
|
||||
EXPORT_SYMBOL_GPL(tegra_serial_handle_break);
|
||||
#else
|
||||
static inline void tegra_serial_handle_break(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@@ -59,6 +59,7 @@
|
||||
|
||||
/* SCR register bitmasks */
|
||||
#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7)
|
||||
#define OMAP_UART_SCR_TX_TRIG_GRANU1_MASK (1 << 6)
|
||||
#define OMAP_UART_SCR_TX_EMPTY (1 << 3)
|
||||
|
||||
/* FCR register bitmasks */
|
||||
@@ -231,25 +232,43 @@ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
|
||||
pdata->enable_wakeup(up->dev, enable);
|
||||
}
|
||||
|
||||
/*
|
||||
* serial_omap_baud_is_mode16 - check if baud rate is MODE16X
|
||||
* @port: uart port info
|
||||
* @baud: baudrate for which mode needs to be determined
|
||||
*
|
||||
* Returns true if baud rate is MODE16X and false if MODE13X
|
||||
* Original table in OMAP TRM named "UART Mode Baud Rates, Divisor Values,
|
||||
* and Error Rates" determines modes not for all common baud rates.
|
||||
* E.g. for 1000000 baud rate mode must be 16x, but according to that
|
||||
* table it's determined as 13x.
|
||||
*/
|
||||
static bool
|
||||
serial_omap_baud_is_mode16(struct uart_port *port, unsigned int baud)
|
||||
{
|
||||
unsigned int n13 = port->uartclk / (13 * baud);
|
||||
unsigned int n16 = port->uartclk / (16 * baud);
|
||||
int baudAbsDiff13 = baud - (port->uartclk / (13 * n13));
|
||||
int baudAbsDiff16 = baud - (port->uartclk / (16 * n16));
|
||||
if(baudAbsDiff13 < 0)
|
||||
baudAbsDiff13 = -baudAbsDiff13;
|
||||
if(baudAbsDiff16 < 0)
|
||||
baudAbsDiff16 = -baudAbsDiff16;
|
||||
|
||||
return (baudAbsDiff13 > baudAbsDiff16);
|
||||
}
|
||||
|
||||
/*
|
||||
* serial_omap_get_divisor - calculate divisor value
|
||||
* @port: uart port info
|
||||
* @baud: baudrate for which divisor needs to be calculated.
|
||||
*
|
||||
* We have written our own function to get the divisor so as to support
|
||||
* 13x mode. 3Mbps Baudrate as an different divisor.
|
||||
* Reference OMAP TRM Chapter 17:
|
||||
* Table 17-1. UART Mode Baud Rates, Divisor Values, and Error Rates
|
||||
* referring to oversampling - divisor value
|
||||
* baudrate 460,800 to 3,686,400 all have divisor 13
|
||||
* except 3,000,000 which has divisor value 16
|
||||
*/
|
||||
static unsigned int
|
||||
serial_omap_get_divisor(struct uart_port *port, unsigned int baud)
|
||||
{
|
||||
unsigned int divisor;
|
||||
|
||||
if (baud > OMAP_MODE13X_SPEED && baud != 3000000)
|
||||
if (!serial_omap_baud_is_mode16(port, baud))
|
||||
divisor = 13;
|
||||
else
|
||||
divisor = 16;
|
||||
@@ -302,9 +321,6 @@ static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
int count;
|
||||
|
||||
if (!(lsr & UART_LSR_THRE))
|
||||
return;
|
||||
|
||||
if (up->port.x_char) {
|
||||
serial_out(up, UART_TX, up->port.x_char);
|
||||
up->port.icount.tx++;
|
||||
@@ -483,7 +499,6 @@ static void serial_omap_rdi(struct uart_omap_port *up, unsigned int lsr)
|
||||
static irqreturn_t serial_omap_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_omap_port *up = dev_id;
|
||||
struct tty_struct *tty = up->port.state->port.tty;
|
||||
unsigned int iir, lsr;
|
||||
unsigned int type;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
@@ -530,7 +545,7 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id)
|
||||
|
||||
spin_unlock(&up->port.lock);
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
|
||||
pm_runtime_mark_last_busy(up->dev);
|
||||
pm_runtime_put_autosuspend(up->dev);
|
||||
@@ -776,6 +791,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
cval |= UART_LCR_PARITY;
|
||||
if (!(termios->c_cflag & PARODD))
|
||||
cval |= UART_LCR_EPAR;
|
||||
if (termios->c_cflag & CMSPAR)
|
||||
cval |= UART_LCR_SPAR;
|
||||
|
||||
/*
|
||||
* Ask the core to calculate the divisor for us.
|
||||
@@ -845,7 +862,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
serial_out(up, UART_IER, up->ier);
|
||||
serial_out(up, UART_LCR, cval); /* reset DLAB */
|
||||
up->lcr = cval;
|
||||
up->scr = OMAP_UART_SCR_TX_EMPTY;
|
||||
up->scr = 0;
|
||||
|
||||
/* FIFOs and DMA Settings */
|
||||
|
||||
@@ -869,8 +886,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
|
||||
/* FIFO ENABLE, DMA MODE */
|
||||
|
||||
up->scr |= OMAP_UART_SCR_RX_TRIG_GRANU1_MASK;
|
||||
|
||||
/* Set receive FIFO threshold to 16 characters and
|
||||
* transmit FIFO threshold to 16 spaces
|
||||
*/
|
||||
@@ -915,7 +930,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
serial_out(up, UART_EFR, up->efr);
|
||||
serial_out(up, UART_LCR, cval);
|
||||
|
||||
if (baud > 230400 && baud != 3000000)
|
||||
if (!serial_omap_baud_is_mode16(port, baud))
|
||||
up->mdr1 = UART_OMAP_MDR1_13X_MODE;
|
||||
else
|
||||
up->mdr1 = UART_OMAP_MDR1_16X_MODE;
|
||||
|
@@ -14,18 +14,21 @@
|
||||
*along with this program; if not, write to the Free Software
|
||||
*Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#if defined(CONFIG_SERIAL_PCH_UART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
@@ -553,12 +556,26 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf,
|
||||
{
|
||||
int i;
|
||||
u8 rbr, lsr;
|
||||
struct uart_port *port = &priv->port;
|
||||
|
||||
lsr = ioread8(priv->membase + UART_LSR);
|
||||
for (i = 0, lsr = ioread8(priv->membase + UART_LSR);
|
||||
i < rx_size && lsr & UART_LSR_DR;
|
||||
i < rx_size && lsr & (UART_LSR_DR | UART_LSR_BI);
|
||||
lsr = ioread8(priv->membase + UART_LSR)) {
|
||||
rbr = ioread8(priv->membase + PCH_UART_RBR);
|
||||
|
||||
if (lsr & UART_LSR_BI) {
|
||||
port->icount.brk++;
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
}
|
||||
#ifdef SUPPORT_SYSRQ
|
||||
if (port->sysrq) {
|
||||
if (uart_handle_sysrq_char(port, rbr))
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
buf[i++] = rbr;
|
||||
}
|
||||
return i;
|
||||
@@ -591,19 +608,11 @@ static void pch_uart_hal_set_break(struct eg20t_port *priv, int on)
|
||||
static int push_rx(struct eg20t_port *priv, const unsigned char *buf,
|
||||
int size)
|
||||
{
|
||||
struct uart_port *port;
|
||||
struct tty_struct *tty;
|
||||
struct uart_port *port = &priv->port;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
port = &priv->port;
|
||||
tty = tty_port_tty_get(&port->state->port);
|
||||
if (!tty) {
|
||||
dev_dbg(priv->port.dev, "%s:tty is busy now", __func__);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
tty_insert_flip_string(tty, buf, size);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_insert_flip_string(tport, buf, size);
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -629,15 +638,16 @@ static int dma_push_rx(struct eg20t_port *priv, int size)
|
||||
struct tty_struct *tty;
|
||||
int room;
|
||||
struct uart_port *port = &priv->port;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
port = &priv->port;
|
||||
tty = tty_port_tty_get(&port->state->port);
|
||||
tty = tty_port_tty_get(tport);
|
||||
if (!tty) {
|
||||
dev_dbg(priv->port.dev, "%s:tty is busy now", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
room = tty_buffer_request_room(tty, size);
|
||||
room = tty_buffer_request_room(tport, size);
|
||||
|
||||
if (room < size)
|
||||
dev_warn(port->dev, "Rx overrun: dropping %u bytes\n",
|
||||
@@ -645,7 +655,7 @@ static int dma_push_rx(struct eg20t_port *priv, int size)
|
||||
if (!room)
|
||||
return room;
|
||||
|
||||
tty_insert_flip_string(tty, sg_virt(&priv->sg_rx), size);
|
||||
tty_insert_flip_string(tport, sg_virt(&priv->sg_rx), size);
|
||||
|
||||
port->icount.rx += room;
|
||||
tty_kref_put(tty);
|
||||
@@ -743,19 +753,12 @@ static void pch_dma_rx_complete(void *arg)
|
||||
{
|
||||
struct eg20t_port *priv = arg;
|
||||
struct uart_port *port = &priv->port;
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->state->port);
|
||||
int count;
|
||||
|
||||
if (!tty) {
|
||||
dev_dbg(priv->port.dev, "%s:tty is busy now", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
dma_sync_sg_for_cpu(port->dev, &priv->sg_rx, 1, DMA_FROM_DEVICE);
|
||||
count = dma_push_rx(priv, priv->trigger_level);
|
||||
if (count)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
async_tx_ack(priv->desc_rx);
|
||||
pch_uart_hal_enable_interrupt(priv, PCH_UART_HAL_RX_INT |
|
||||
PCH_UART_HAL_RX_ERR_INT);
|
||||
@@ -1037,23 +1040,33 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
|
||||
|
||||
static void pch_uart_err_ir(struct eg20t_port *priv, unsigned int lsr)
|
||||
{
|
||||
u8 fcr = ioread8(priv->membase + UART_FCR);
|
||||
|
||||
/* Reset FIFO */
|
||||
fcr |= UART_FCR_CLEAR_RCVR;
|
||||
iowrite8(fcr, priv->membase + UART_FCR);
|
||||
struct uart_port *port = &priv->port;
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->state->port);
|
||||
char *error_msg[5] = {};
|
||||
int i = 0;
|
||||
|
||||
if (lsr & PCH_UART_LSR_ERR)
|
||||
dev_err(&priv->pdev->dev, "Error data in FIFO\n");
|
||||
error_msg[i++] = "Error data in FIFO\n";
|
||||
|
||||
if (lsr & UART_LSR_FE)
|
||||
dev_err(&priv->pdev->dev, "Framing Error\n");
|
||||
if (lsr & UART_LSR_FE) {
|
||||
port->icount.frame++;
|
||||
error_msg[i++] = " Framing Error\n";
|
||||
}
|
||||
|
||||
if (lsr & UART_LSR_PE)
|
||||
dev_err(&priv->pdev->dev, "Parity Error\n");
|
||||
if (lsr & UART_LSR_PE) {
|
||||
port->icount.parity++;
|
||||
error_msg[i++] = " Parity Error\n";
|
||||
}
|
||||
|
||||
if (lsr & UART_LSR_OE)
|
||||
dev_err(&priv->pdev->dev, "Overrun Error\n");
|
||||
if (lsr & UART_LSR_OE) {
|
||||
port->icount.overrun++;
|
||||
error_msg[i++] = " Overrun Error\n";
|
||||
}
|
||||
|
||||
if (tty == NULL) {
|
||||
for (i = 0; error_msg[i] != NULL; i++)
|
||||
dev_err(&priv->pdev->dev, error_msg[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t pch_uart_interrupt(int irq, void *dev_id)
|
||||
@@ -1564,7 +1577,8 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
|
||||
|
||||
local_irq_save(flags);
|
||||
if (priv->port.sysrq) {
|
||||
spin_lock(&priv->lock);
|
||||
/* call to uart_handle_sysrq_char already took the priv lock */
|
||||
priv_locked = 0;
|
||||
/* serial8250_handle_port() already took the port lock */
|
||||
port_locked = 0;
|
||||
} else if (oops_in_progress) {
|
||||
|
@@ -227,19 +227,19 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
|
||||
write_zsreg(uap, R1, uap->curregs[1]);
|
||||
}
|
||||
|
||||
static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
|
||||
static bool pmz_receive_chars(struct uart_pmac_port *uap)
|
||||
{
|
||||
struct tty_struct *tty = NULL;
|
||||
struct tty_port *port;
|
||||
unsigned char ch, r1, drop, error, flag;
|
||||
int loops = 0;
|
||||
|
||||
/* Sanity check, make sure the old bug is no longer happening */
|
||||
if (uap->port.state == NULL || uap->port.state->port.tty == NULL) {
|
||||
if (uap->port.state == NULL) {
|
||||
WARN_ON(1);
|
||||
(void)read_zsdata(uap);
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
tty = uap->port.state->port.tty;
|
||||
port = &uap->port.state->port;
|
||||
|
||||
while (1) {
|
||||
error = 0;
|
||||
@@ -309,10 +309,10 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
|
||||
|
||||
if (uap->port.ignore_status_mask == 0xff ||
|
||||
(r1 & uap->port.ignore_status_mask) == 0) {
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(port, ch, flag);
|
||||
}
|
||||
if (r1 & Rx_OVR)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||
next_char:
|
||||
/* We can get stuck in an infinite loop getting char 0 when the
|
||||
* line is in a wrong HW state, we break that here.
|
||||
@@ -328,11 +328,11 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
|
||||
break;
|
||||
}
|
||||
|
||||
return tty;
|
||||
return true;
|
||||
flood:
|
||||
pmz_interrupt_control(uap, 0);
|
||||
pmz_error("pmz: rx irq flood !\n");
|
||||
return tty;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pmz_status_handle(struct uart_pmac_port *uap)
|
||||
@@ -453,7 +453,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
|
||||
struct uart_pmac_port *uap_a;
|
||||
struct uart_pmac_port *uap_b;
|
||||
int rc = IRQ_NONE;
|
||||
struct tty_struct *tty;
|
||||
bool push;
|
||||
u8 r3;
|
||||
|
||||
uap_a = pmz_get_port_A(uap);
|
||||
@@ -466,7 +466,7 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
|
||||
pmz_debug("irq, r3: %x\n", r3);
|
||||
#endif
|
||||
/* Channel A */
|
||||
tty = NULL;
|
||||
push = false;
|
||||
if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
|
||||
if (!ZS_IS_OPEN(uap_a)) {
|
||||
pmz_debug("ChanA interrupt while not open !\n");
|
||||
@@ -477,21 +477,21 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
|
||||
if (r3 & CHAEXT)
|
||||
pmz_status_handle(uap_a);
|
||||
if (r3 & CHARxIP)
|
||||
tty = pmz_receive_chars(uap_a);
|
||||
push = pmz_receive_chars(uap_a);
|
||||
if (r3 & CHATxIP)
|
||||
pmz_transmit_chars(uap_a);
|
||||
rc = IRQ_HANDLED;
|
||||
}
|
||||
skip_a:
|
||||
spin_unlock(&uap_a->port.lock);
|
||||
if (tty != NULL)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (push)
|
||||
tty_flip_buffer_push(&uap->port.state->port);
|
||||
|
||||
if (!uap_b)
|
||||
goto out;
|
||||
|
||||
spin_lock(&uap_b->port.lock);
|
||||
tty = NULL;
|
||||
push = false;
|
||||
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
|
||||
if (!ZS_IS_OPEN(uap_b)) {
|
||||
pmz_debug("ChanB interrupt while not open !\n");
|
||||
@@ -502,15 +502,15 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id)
|
||||
if (r3 & CHBEXT)
|
||||
pmz_status_handle(uap_b);
|
||||
if (r3 & CHBRxIP)
|
||||
tty = pmz_receive_chars(uap_b);
|
||||
push = pmz_receive_chars(uap_b);
|
||||
if (r3 & CHBTxIP)
|
||||
pmz_transmit_chars(uap_b);
|
||||
rc = IRQ_HANDLED;
|
||||
}
|
||||
skip_b:
|
||||
spin_unlock(&uap_b->port.lock);
|
||||
if (tty != NULL)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (push)
|
||||
tty_flip_buffer_push(&uap->port.state->port);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
|
@@ -181,7 +181,6 @@ static void pnx8xxx_enable_ms(struct uart_port *port)
|
||||
|
||||
static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
|
||||
{
|
||||
struct tty_struct *tty = sport->port.state->port.tty;
|
||||
unsigned int status, ch, flg;
|
||||
|
||||
status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
|
||||
@@ -238,7 +237,7 @@ static void pnx8xxx_rx_chars(struct pnx8xxx_port *sport)
|
||||
status = FIFO_TO_SM(serial_in(sport, PNX8XXX_FIFO)) |
|
||||
ISTAT_TO_SM(serial_in(sport, PNX8XXX_ISTAT));
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&sport->port.state->port);
|
||||
}
|
||||
|
||||
static void pnx8xxx_tx_chars(struct pnx8xxx_port *sport)
|
||||
|
@@ -98,7 +98,6 @@ static void serial_pxa_stop_rx(struct uart_port *port)
|
||||
|
||||
static inline void receive_chars(struct uart_pxa_port *up, int *status)
|
||||
{
|
||||
struct tty_struct *tty = up->port.state->port.tty;
|
||||
unsigned int ch, flag;
|
||||
int max_count = 256;
|
||||
|
||||
@@ -168,7 +167,7 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status)
|
||||
ignore_char:
|
||||
*status = serial_in(up, UART_LSR);
|
||||
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
|
||||
/* work around Errata #20 according to
|
||||
* Intel(R) PXA27x Processor Family
|
||||
@@ -673,8 +672,7 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
|
||||
unsigned long flags;
|
||||
int locked = 1;
|
||||
|
||||
clk_prepare_enable(up->clk);
|
||||
|
||||
clk_enable(up->clk);
|
||||
local_irq_save(flags);
|
||||
if (up->port.sysrq)
|
||||
locked = 0;
|
||||
@@ -701,8 +699,8 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
|
||||
if (locked)
|
||||
spin_unlock(&up->port.lock);
|
||||
local_irq_restore(flags);
|
||||
clk_disable(up->clk);
|
||||
|
||||
clk_disable_unprepare(up->clk);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
@@ -899,6 +897,12 @@ static int serial_pxa_probe(struct platform_device *dev)
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ret = clk_prepare(sport->clk);
|
||||
if (ret) {
|
||||
clk_put(sport->clk);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
sport->port.type = PORT_PXA;
|
||||
sport->port.iotype = UPIO_MEM;
|
||||
sport->port.mapbase = mmres->start;
|
||||
@@ -930,6 +934,7 @@ static int serial_pxa_probe(struct platform_device *dev)
|
||||
return 0;
|
||||
|
||||
err_clk:
|
||||
clk_unprepare(sport->clk);
|
||||
clk_put(sport->clk);
|
||||
err_free:
|
||||
kfree(sport);
|
||||
@@ -943,6 +948,8 @@ static int serial_pxa_remove(struct platform_device *dev)
|
||||
platform_set_drvdata(dev, NULL);
|
||||
|
||||
uart_remove_one_port(&serial_pxa_reg, &sport->port);
|
||||
|
||||
clk_unprepare(sport->clk);
|
||||
clk_put(sport->clk);
|
||||
kfree(sport);
|
||||
|
||||
|
885
drivers/tty/serial/rp2.c
Normal file
885
drivers/tty/serial/rp2.c
Normal file
@@ -0,0 +1,885 @@
|
||||
/*
|
||||
* Driver for Comtrol RocketPort EXPRESS/INFINITY cards
|
||||
*
|
||||
* Copyright (C) 2012 Kevin Cernekee <cernekee@gmail.com>
|
||||
*
|
||||
* Inspired by, and loosely based on:
|
||||
*
|
||||
* ar933x_uart.c
|
||||
* Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
|
||||
*
|
||||
* rocketport_infinity_express-linux-1.20.tar.gz
|
||||
* Copyright (C) 2004-2011 Comtrol, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define DRV_NAME "rp2"
|
||||
|
||||
#define RP2_FW_NAME "rp2.fw"
|
||||
#define RP2_UCODE_BYTES 0x3f
|
||||
|
||||
#define PORTS_PER_ASIC 16
|
||||
#define ALL_PORTS_MASK (BIT(PORTS_PER_ASIC) - 1)
|
||||
|
||||
#define UART_CLOCK 44236800
|
||||
#define DEFAULT_BAUD_DIV (UART_CLOCK / (9600 * 16))
|
||||
#define FIFO_SIZE 512
|
||||
|
||||
/* BAR0 registers */
|
||||
#define RP2_FPGA_CTL0 0x110
|
||||
#define RP2_FPGA_CTL1 0x11c
|
||||
#define RP2_IRQ_MASK 0x1ec
|
||||
#define RP2_IRQ_MASK_EN_m BIT(0)
|
||||
#define RP2_IRQ_STATUS 0x1f0
|
||||
|
||||
/* BAR1 registers */
|
||||
#define RP2_ASIC_SPACING 0x1000
|
||||
#define RP2_ASIC_OFFSET(i) ((i) << ilog2(RP2_ASIC_SPACING))
|
||||
|
||||
#define RP2_PORT_BASE 0x000
|
||||
#define RP2_PORT_SPACING 0x040
|
||||
|
||||
#define RP2_UCODE_BASE 0x400
|
||||
#define RP2_UCODE_SPACING 0x80
|
||||
|
||||
#define RP2_CLK_PRESCALER 0xc00
|
||||
#define RP2_CH_IRQ_STAT 0xc04
|
||||
#define RP2_CH_IRQ_MASK 0xc08
|
||||
#define RP2_ASIC_IRQ 0xd00
|
||||
#define RP2_ASIC_IRQ_EN_m BIT(20)
|
||||
#define RP2_GLOBAL_CMD 0xd0c
|
||||
#define RP2_ASIC_CFG 0xd04
|
||||
|
||||
/* port registers */
|
||||
#define RP2_DATA_DWORD 0x000
|
||||
|
||||
#define RP2_DATA_BYTE 0x008
|
||||
#define RP2_DATA_BYTE_ERR_PARITY_m BIT(8)
|
||||
#define RP2_DATA_BYTE_ERR_OVERRUN_m BIT(9)
|
||||
#define RP2_DATA_BYTE_ERR_FRAMING_m BIT(10)
|
||||
#define RP2_DATA_BYTE_BREAK_m BIT(11)
|
||||
|
||||
/* This lets uart_insert_char() drop bytes received on a !CREAD port */
|
||||
#define RP2_DUMMY_READ BIT(16)
|
||||
|
||||
#define RP2_DATA_BYTE_EXCEPTION_MASK (RP2_DATA_BYTE_ERR_PARITY_m | \
|
||||
RP2_DATA_BYTE_ERR_OVERRUN_m | \
|
||||
RP2_DATA_BYTE_ERR_FRAMING_m | \
|
||||
RP2_DATA_BYTE_BREAK_m)
|
||||
|
||||
#define RP2_RX_FIFO_COUNT 0x00c
|
||||
#define RP2_TX_FIFO_COUNT 0x00e
|
||||
|
||||
#define RP2_CHAN_STAT 0x010
|
||||
#define RP2_CHAN_STAT_RXDATA_m BIT(0)
|
||||
#define RP2_CHAN_STAT_DCD_m BIT(3)
|
||||
#define RP2_CHAN_STAT_DSR_m BIT(4)
|
||||
#define RP2_CHAN_STAT_CTS_m BIT(5)
|
||||
#define RP2_CHAN_STAT_RI_m BIT(6)
|
||||
#define RP2_CHAN_STAT_OVERRUN_m BIT(13)
|
||||
#define RP2_CHAN_STAT_DSR_CHANGED_m BIT(16)
|
||||
#define RP2_CHAN_STAT_CTS_CHANGED_m BIT(17)
|
||||
#define RP2_CHAN_STAT_CD_CHANGED_m BIT(18)
|
||||
#define RP2_CHAN_STAT_RI_CHANGED_m BIT(22)
|
||||
#define RP2_CHAN_STAT_TXEMPTY_m BIT(25)
|
||||
|
||||
#define RP2_CHAN_STAT_MS_CHANGED_MASK (RP2_CHAN_STAT_DSR_CHANGED_m | \
|
||||
RP2_CHAN_STAT_CTS_CHANGED_m | \
|
||||
RP2_CHAN_STAT_CD_CHANGED_m | \
|
||||
RP2_CHAN_STAT_RI_CHANGED_m)
|
||||
|
||||
#define RP2_TXRX_CTL 0x014
|
||||
#define RP2_TXRX_CTL_MSRIRQ_m BIT(0)
|
||||
#define RP2_TXRX_CTL_RXIRQ_m BIT(2)
|
||||
#define RP2_TXRX_CTL_RX_TRIG_s 3
|
||||
#define RP2_TXRX_CTL_RX_TRIG_m (0x3 << RP2_TXRX_CTL_RX_TRIG_s)
|
||||
#define RP2_TXRX_CTL_RX_TRIG_1 (0x1 << RP2_TXRX_CTL_RX_TRIG_s)
|
||||
#define RP2_TXRX_CTL_RX_TRIG_256 (0x2 << RP2_TXRX_CTL_RX_TRIG_s)
|
||||
#define RP2_TXRX_CTL_RX_TRIG_448 (0x3 << RP2_TXRX_CTL_RX_TRIG_s)
|
||||
#define RP2_TXRX_CTL_RX_EN_m BIT(5)
|
||||
#define RP2_TXRX_CTL_RTSFLOW_m BIT(6)
|
||||
#define RP2_TXRX_CTL_DTRFLOW_m BIT(7)
|
||||
#define RP2_TXRX_CTL_TX_TRIG_s 16
|
||||
#define RP2_TXRX_CTL_TX_TRIG_m (0x3 << RP2_TXRX_CTL_RX_TRIG_s)
|
||||
#define RP2_TXRX_CTL_DSRFLOW_m BIT(18)
|
||||
#define RP2_TXRX_CTL_TXIRQ_m BIT(19)
|
||||
#define RP2_TXRX_CTL_CTSFLOW_m BIT(23)
|
||||
#define RP2_TXRX_CTL_TX_EN_m BIT(24)
|
||||
#define RP2_TXRX_CTL_RTS_m BIT(25)
|
||||
#define RP2_TXRX_CTL_DTR_m BIT(26)
|
||||
#define RP2_TXRX_CTL_LOOP_m BIT(27)
|
||||
#define RP2_TXRX_CTL_BREAK_m BIT(28)
|
||||
#define RP2_TXRX_CTL_CMSPAR_m BIT(29)
|
||||
#define RP2_TXRX_CTL_nPARODD_m BIT(30)
|
||||
#define RP2_TXRX_CTL_PARENB_m BIT(31)
|
||||
|
||||
#define RP2_UART_CTL 0x018
|
||||
#define RP2_UART_CTL_MODE_s 0
|
||||
#define RP2_UART_CTL_MODE_m (0x7 << RP2_UART_CTL_MODE_s)
|
||||
#define RP2_UART_CTL_MODE_rs232 (0x1 << RP2_UART_CTL_MODE_s)
|
||||
#define RP2_UART_CTL_FLUSH_RX_m BIT(3)
|
||||
#define RP2_UART_CTL_FLUSH_TX_m BIT(4)
|
||||
#define RP2_UART_CTL_RESET_CH_m BIT(5)
|
||||
#define RP2_UART_CTL_XMIT_EN_m BIT(6)
|
||||
#define RP2_UART_CTL_DATABITS_s 8
|
||||
#define RP2_UART_CTL_DATABITS_m (0x3 << RP2_UART_CTL_DATABITS_s)
|
||||
#define RP2_UART_CTL_DATABITS_8 (0x3 << RP2_UART_CTL_DATABITS_s)
|
||||
#define RP2_UART_CTL_DATABITS_7 (0x2 << RP2_UART_CTL_DATABITS_s)
|
||||
#define RP2_UART_CTL_DATABITS_6 (0x1 << RP2_UART_CTL_DATABITS_s)
|
||||
#define RP2_UART_CTL_DATABITS_5 (0x0 << RP2_UART_CTL_DATABITS_s)
|
||||
#define RP2_UART_CTL_STOPBITS_m BIT(10)
|
||||
|
||||
#define RP2_BAUD 0x01c
|
||||
|
||||
/* ucode registers */
|
||||
#define RP2_TX_SWFLOW 0x02
|
||||
#define RP2_TX_SWFLOW_ena 0x81
|
||||
#define RP2_TX_SWFLOW_dis 0x9d
|
||||
|
||||
#define RP2_RX_SWFLOW 0x0c
|
||||
#define RP2_RX_SWFLOW_ena 0x81
|
||||
#define RP2_RX_SWFLOW_dis 0x8d
|
||||
|
||||
#define RP2_RX_FIFO 0x37
|
||||
#define RP2_RX_FIFO_ena 0x08
|
||||
#define RP2_RX_FIFO_dis 0x81
|
||||
|
||||
static struct uart_driver rp2_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = DRV_NAME,
|
||||
.dev_name = "ttyRP",
|
||||
.nr = CONFIG_SERIAL_RP2_NR_UARTS,
|
||||
};
|
||||
|
||||
struct rp2_card;
|
||||
|
||||
struct rp2_uart_port {
|
||||
struct uart_port port;
|
||||
int idx;
|
||||
int ignore_rx;
|
||||
struct rp2_card *card;
|
||||
void __iomem *asic_base;
|
||||
void __iomem *base;
|
||||
void __iomem *ucode;
|
||||
};
|
||||
|
||||
struct rp2_card {
|
||||
struct pci_dev *pdev;
|
||||
struct rp2_uart_port *ports;
|
||||
int n_ports;
|
||||
int initialized_ports;
|
||||
int minor_start;
|
||||
int smpte;
|
||||
void __iomem *bar0;
|
||||
void __iomem *bar1;
|
||||
spinlock_t card_lock;
|
||||
struct completion fw_loaded;
|
||||
};
|
||||
|
||||
#define RP_ID(prod) PCI_VDEVICE(RP, (prod))
|
||||
#define RP_CAP(ports, smpte) (((ports) << 8) | ((smpte) << 0))
|
||||
|
||||
static inline void rp2_decode_cap(const struct pci_device_id *id,
|
||||
int *ports, int *smpte)
|
||||
{
|
||||
*ports = id->driver_data >> 8;
|
||||
*smpte = id->driver_data & 0xff;
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(rp2_minor_lock);
|
||||
static int rp2_minor_next;
|
||||
|
||||
static int rp2_alloc_ports(int n_ports)
|
||||
{
|
||||
int ret = -ENOSPC;
|
||||
|
||||
spin_lock(&rp2_minor_lock);
|
||||
if (rp2_minor_next + n_ports <= CONFIG_SERIAL_RP2_NR_UARTS) {
|
||||
/* sorry, no support for hot unplugging individual cards */
|
||||
ret = rp2_minor_next;
|
||||
rp2_minor_next += n_ports;
|
||||
}
|
||||
spin_unlock(&rp2_minor_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline struct rp2_uart_port *port_to_up(struct uart_port *port)
|
||||
{
|
||||
return container_of(port, struct rp2_uart_port, port);
|
||||
}
|
||||
|
||||
static void rp2_rmw(struct rp2_uart_port *up, int reg,
|
||||
u32 clr_bits, u32 set_bits)
|
||||
{
|
||||
u32 tmp = readl(up->base + reg);
|
||||
tmp &= ~clr_bits;
|
||||
tmp |= set_bits;
|
||||
writel(tmp, up->base + reg);
|
||||
}
|
||||
|
||||
static void rp2_rmw_clr(struct rp2_uart_port *up, int reg, u32 val)
|
||||
{
|
||||
rp2_rmw(up, reg, val, 0);
|
||||
}
|
||||
|
||||
static void rp2_rmw_set(struct rp2_uart_port *up, int reg, u32 val)
|
||||
{
|
||||
rp2_rmw(up, reg, 0, val);
|
||||
}
|
||||
|
||||
static void rp2_mask_ch_irq(struct rp2_uart_port *up, int ch_num,
|
||||
int is_enabled)
|
||||
{
|
||||
unsigned long flags, irq_mask;
|
||||
|
||||
spin_lock_irqsave(&up->card->card_lock, flags);
|
||||
|
||||
irq_mask = readl(up->asic_base + RP2_CH_IRQ_MASK);
|
||||
if (is_enabled)
|
||||
irq_mask &= ~BIT(ch_num);
|
||||
else
|
||||
irq_mask |= BIT(ch_num);
|
||||
writel(irq_mask, up->asic_base + RP2_CH_IRQ_MASK);
|
||||
|
||||
spin_unlock_irqrestore(&up->card->card_lock, flags);
|
||||
}
|
||||
|
||||
static unsigned int rp2_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct rp2_uart_port *up = port_to_up(port);
|
||||
unsigned long tx_fifo_bytes, flags;
|
||||
|
||||
/*
|
||||
* This should probably check the transmitter, not the FIFO.
|
||||
* But the TXEMPTY bit doesn't seem to work unless the TX IRQ is
|
||||
* enabled.
|
||||
*/
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
tx_fifo_bytes = readw(up->base + RP2_TX_FIFO_COUNT);
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
|
||||
return tx_fifo_bytes ? 0 : TIOCSER_TEMT;
|
||||
}
|
||||
|
||||
static unsigned int rp2_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct rp2_uart_port *up = port_to_up(port);
|
||||
u32 status;
|
||||
|
||||
status = readl(up->base + RP2_CHAN_STAT);
|
||||
return ((status & RP2_CHAN_STAT_DCD_m) ? TIOCM_CAR : 0) |
|
||||
((status & RP2_CHAN_STAT_DSR_m) ? TIOCM_DSR : 0) |
|
||||
((status & RP2_CHAN_STAT_CTS_m) ? TIOCM_CTS : 0) |
|
||||
((status & RP2_CHAN_STAT_RI_m) ? TIOCM_RI : 0);
|
||||
}
|
||||
|
||||
static void rp2_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
rp2_rmw(port_to_up(port), RP2_TXRX_CTL,
|
||||
RP2_TXRX_CTL_DTR_m | RP2_TXRX_CTL_RTS_m | RP2_TXRX_CTL_LOOP_m,
|
||||
((mctrl & TIOCM_DTR) ? RP2_TXRX_CTL_DTR_m : 0) |
|
||||
((mctrl & TIOCM_RTS) ? RP2_TXRX_CTL_RTS_m : 0) |
|
||||
((mctrl & TIOCM_LOOP) ? RP2_TXRX_CTL_LOOP_m : 0));
|
||||
}
|
||||
|
||||
static void rp2_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
rp2_rmw_set(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_TXIRQ_m);
|
||||
}
|
||||
|
||||
static void rp2_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
rp2_rmw_clr(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_TXIRQ_m);
|
||||
}
|
||||
|
||||
static void rp2_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
rp2_rmw_clr(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_RXIRQ_m);
|
||||
}
|
||||
|
||||
static void rp2_uart_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
rp2_rmw(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_BREAK_m,
|
||||
break_state ? RP2_TXRX_CTL_BREAK_m : 0);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void rp2_uart_enable_ms(struct uart_port *port)
|
||||
{
|
||||
rp2_rmw_set(port_to_up(port), RP2_TXRX_CTL, RP2_TXRX_CTL_MSRIRQ_m);
|
||||
}
|
||||
|
||||
static void __rp2_uart_set_termios(struct rp2_uart_port *up,
|
||||
unsigned long cfl,
|
||||
unsigned long ifl,
|
||||
unsigned int baud_div)
|
||||
{
|
||||
/* baud rate divisor (calculated elsewhere). 0 = divide-by-1 */
|
||||
writew(baud_div - 1, up->base + RP2_BAUD);
|
||||
|
||||
/* data bits and stop bits */
|
||||
rp2_rmw(up, RP2_UART_CTL,
|
||||
RP2_UART_CTL_STOPBITS_m | RP2_UART_CTL_DATABITS_m,
|
||||
((cfl & CSTOPB) ? RP2_UART_CTL_STOPBITS_m : 0) |
|
||||
(((cfl & CSIZE) == CS8) ? RP2_UART_CTL_DATABITS_8 : 0) |
|
||||
(((cfl & CSIZE) == CS7) ? RP2_UART_CTL_DATABITS_7 : 0) |
|
||||
(((cfl & CSIZE) == CS6) ? RP2_UART_CTL_DATABITS_6 : 0) |
|
||||
(((cfl & CSIZE) == CS5) ? RP2_UART_CTL_DATABITS_5 : 0));
|
||||
|
||||
/* parity and hardware flow control */
|
||||
rp2_rmw(up, RP2_TXRX_CTL,
|
||||
RP2_TXRX_CTL_PARENB_m | RP2_TXRX_CTL_nPARODD_m |
|
||||
RP2_TXRX_CTL_CMSPAR_m | RP2_TXRX_CTL_DTRFLOW_m |
|
||||
RP2_TXRX_CTL_DSRFLOW_m | RP2_TXRX_CTL_RTSFLOW_m |
|
||||
RP2_TXRX_CTL_CTSFLOW_m,
|
||||
((cfl & PARENB) ? RP2_TXRX_CTL_PARENB_m : 0) |
|
||||
((cfl & PARODD) ? 0 : RP2_TXRX_CTL_nPARODD_m) |
|
||||
((cfl & CMSPAR) ? RP2_TXRX_CTL_CMSPAR_m : 0) |
|
||||
((cfl & CRTSCTS) ? (RP2_TXRX_CTL_RTSFLOW_m |
|
||||
RP2_TXRX_CTL_CTSFLOW_m) : 0));
|
||||
|
||||
/* XON/XOFF software flow control */
|
||||
writeb((ifl & IXON) ? RP2_TX_SWFLOW_ena : RP2_TX_SWFLOW_dis,
|
||||
up->ucode + RP2_TX_SWFLOW);
|
||||
writeb((ifl & IXOFF) ? RP2_RX_SWFLOW_ena : RP2_RX_SWFLOW_dis,
|
||||
up->ucode + RP2_RX_SWFLOW);
|
||||
}
|
||||
|
||||
static void rp2_uart_set_termios(struct uart_port *port,
|
||||
struct ktermios *new,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct rp2_uart_port *up = port_to_up(port);
|
||||
unsigned long flags;
|
||||
unsigned int baud, baud_div;
|
||||
|
||||
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
|
||||
baud_div = uart_get_divisor(port, baud);
|
||||
|
||||
if (tty_termios_baud_rate(new))
|
||||
tty_termios_encode_baud_rate(new, baud, baud);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* ignore all characters if CREAD is not set */
|
||||
port->ignore_status_mask = (new->c_cflag & CREAD) ? 0 : RP2_DUMMY_READ;
|
||||
|
||||
__rp2_uart_set_termios(up, new->c_cflag, new->c_iflag, baud_div);
|
||||
uart_update_timeout(port, new->c_cflag, baud);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void rp2_rx_chars(struct rp2_uart_port *up)
|
||||
{
|
||||
u16 bytes = readw(up->base + RP2_RX_FIFO_COUNT);
|
||||
struct tty_port *port = &up->port.state->port;
|
||||
|
||||
for (; bytes != 0; bytes--) {
|
||||
u32 byte = readw(up->base + RP2_DATA_BYTE) | RP2_DUMMY_READ;
|
||||
char ch = byte & 0xff;
|
||||
|
||||
if (likely(!(byte & RP2_DATA_BYTE_EXCEPTION_MASK))) {
|
||||
if (!uart_handle_sysrq_char(&up->port, ch))
|
||||
uart_insert_char(&up->port, byte, 0, ch,
|
||||
TTY_NORMAL);
|
||||
} else {
|
||||
char flag = TTY_NORMAL;
|
||||
|
||||
if (byte & RP2_DATA_BYTE_BREAK_m)
|
||||
flag = TTY_BREAK;
|
||||
else if (byte & RP2_DATA_BYTE_ERR_FRAMING_m)
|
||||
flag = TTY_FRAME;
|
||||
else if (byte & RP2_DATA_BYTE_ERR_PARITY_m)
|
||||
flag = TTY_PARITY;
|
||||
uart_insert_char(&up->port, byte,
|
||||
RP2_DATA_BYTE_ERR_OVERRUN_m, ch, flag);
|
||||
}
|
||||
up->port.icount.rx++;
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(port);
|
||||
}
|
||||
|
||||
static void rp2_tx_chars(struct rp2_uart_port *up)
|
||||
{
|
||||
u16 max_tx = FIFO_SIZE - readw(up->base + RP2_TX_FIFO_COUNT);
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
|
||||
if (uart_tx_stopped(&up->port)) {
|
||||
rp2_uart_stop_tx(&up->port);
|
||||
return;
|
||||
}
|
||||
|
||||
for (; max_tx != 0; max_tx--) {
|
||||
if (up->port.x_char) {
|
||||
writeb(up->port.x_char, up->base + RP2_DATA_BYTE);
|
||||
up->port.x_char = 0;
|
||||
up->port.icount.tx++;
|
||||
continue;
|
||||
}
|
||||
if (uart_circ_empty(xmit)) {
|
||||
rp2_uart_stop_tx(&up->port);
|
||||
break;
|
||||
}
|
||||
writeb(xmit->buf[xmit->tail], up->base + RP2_DATA_BYTE);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
}
|
||||
|
||||
static void rp2_ch_interrupt(struct rp2_uart_port *up)
|
||||
{
|
||||
u32 status;
|
||||
|
||||
spin_lock(&up->port.lock);
|
||||
|
||||
/*
|
||||
* The IRQ status bits are clear-on-write. Other status bits in
|
||||
* this register aren't, so it's harmless to write to them.
|
||||
*/
|
||||
status = readl(up->base + RP2_CHAN_STAT);
|
||||
writel(status, up->base + RP2_CHAN_STAT);
|
||||
|
||||
if (status & RP2_CHAN_STAT_RXDATA_m)
|
||||
rp2_rx_chars(up);
|
||||
if (status & RP2_CHAN_STAT_TXEMPTY_m)
|
||||
rp2_tx_chars(up);
|
||||
if (status & RP2_CHAN_STAT_MS_CHANGED_MASK)
|
||||
wake_up_interruptible(&up->port.state->port.delta_msr_wait);
|
||||
|
||||
spin_unlock(&up->port.lock);
|
||||
}
|
||||
|
||||
static int rp2_asic_interrupt(struct rp2_card *card, unsigned int asic_id)
|
||||
{
|
||||
void __iomem *base = card->bar1 + RP2_ASIC_OFFSET(asic_id);
|
||||
int ch, handled = 0;
|
||||
unsigned long status = readl(base + RP2_CH_IRQ_STAT) &
|
||||
~readl(base + RP2_CH_IRQ_MASK);
|
||||
|
||||
for_each_set_bit(ch, &status, PORTS_PER_ASIC) {
|
||||
rp2_ch_interrupt(&card->ports[ch]);
|
||||
handled++;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
static irqreturn_t rp2_uart_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct rp2_card *card = dev_id;
|
||||
int handled;
|
||||
|
||||
handled = rp2_asic_interrupt(card, 0);
|
||||
if (card->n_ports >= PORTS_PER_ASIC)
|
||||
handled += rp2_asic_interrupt(card, 1);
|
||||
|
||||
return handled ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static inline void rp2_flush_fifos(struct rp2_uart_port *up)
|
||||
{
|
||||
rp2_rmw_set(up, RP2_UART_CTL,
|
||||
RP2_UART_CTL_FLUSH_RX_m | RP2_UART_CTL_FLUSH_TX_m);
|
||||
readl(up->base + RP2_UART_CTL);
|
||||
udelay(10);
|
||||
rp2_rmw_clr(up, RP2_UART_CTL,
|
||||
RP2_UART_CTL_FLUSH_RX_m | RP2_UART_CTL_FLUSH_TX_m);
|
||||
}
|
||||
|
||||
static int rp2_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct rp2_uart_port *up = port_to_up(port);
|
||||
|
||||
rp2_flush_fifos(up);
|
||||
rp2_rmw(up, RP2_TXRX_CTL, RP2_TXRX_CTL_MSRIRQ_m, RP2_TXRX_CTL_RXIRQ_m);
|
||||
rp2_rmw(up, RP2_TXRX_CTL, RP2_TXRX_CTL_RX_TRIG_m,
|
||||
RP2_TXRX_CTL_RX_TRIG_1);
|
||||
rp2_rmw(up, RP2_CHAN_STAT, 0, 0);
|
||||
rp2_mask_ch_irq(up, up->idx, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rp2_uart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct rp2_uart_port *up = port_to_up(port);
|
||||
unsigned long flags;
|
||||
|
||||
rp2_uart_break_ctl(port, 0);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
rp2_mask_ch_irq(up, up->idx, 0);
|
||||
rp2_rmw(up, RP2_CHAN_STAT, 0, 0);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static const char *rp2_uart_type(struct uart_port *port)
|
||||
{
|
||||
return (port->type == PORT_RP2) ? "RocketPort 2 UART" : NULL;
|
||||
}
|
||||
|
||||
static void rp2_uart_release_port(struct uart_port *port)
|
||||
{
|
||||
/* Nothing to release ... */
|
||||
}
|
||||
|
||||
static int rp2_uart_request_port(struct uart_port *port)
|
||||
{
|
||||
/* UARTs always present */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rp2_uart_config_port(struct uart_port *port, int flags)
|
||||
{
|
||||
if (flags & UART_CONFIG_TYPE)
|
||||
port->type = PORT_RP2;
|
||||
}
|
||||
|
||||
static int rp2_uart_verify_port(struct uart_port *port,
|
||||
struct serial_struct *ser)
|
||||
{
|
||||
if (ser->type != PORT_UNKNOWN && ser->type != PORT_RP2)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct uart_ops rp2_uart_ops = {
|
||||
.tx_empty = rp2_uart_tx_empty,
|
||||
.set_mctrl = rp2_uart_set_mctrl,
|
||||
.get_mctrl = rp2_uart_get_mctrl,
|
||||
.stop_tx = rp2_uart_stop_tx,
|
||||
.start_tx = rp2_uart_start_tx,
|
||||
.stop_rx = rp2_uart_stop_rx,
|
||||
.enable_ms = rp2_uart_enable_ms,
|
||||
.break_ctl = rp2_uart_break_ctl,
|
||||
.startup = rp2_uart_startup,
|
||||
.shutdown = rp2_uart_shutdown,
|
||||
.set_termios = rp2_uart_set_termios,
|
||||
.type = rp2_uart_type,
|
||||
.release_port = rp2_uart_release_port,
|
||||
.request_port = rp2_uart_request_port,
|
||||
.config_port = rp2_uart_config_port,
|
||||
.verify_port = rp2_uart_verify_port,
|
||||
};
|
||||
|
||||
static void rp2_reset_asic(struct rp2_card *card, unsigned int asic_id)
|
||||
{
|
||||
void __iomem *base = card->bar1 + RP2_ASIC_OFFSET(asic_id);
|
||||
u32 clk_cfg;
|
||||
|
||||
writew(1, base + RP2_GLOBAL_CMD);
|
||||
readw(base + RP2_GLOBAL_CMD);
|
||||
msleep(100);
|
||||
writel(0, base + RP2_CLK_PRESCALER);
|
||||
|
||||
/* TDM clock configuration */
|
||||
clk_cfg = readw(base + RP2_ASIC_CFG);
|
||||
clk_cfg = (clk_cfg & ~BIT(8)) | BIT(9);
|
||||
writew(clk_cfg, base + RP2_ASIC_CFG);
|
||||
|
||||
/* IRQ routing */
|
||||
writel(ALL_PORTS_MASK, base + RP2_CH_IRQ_MASK);
|
||||
writel(RP2_ASIC_IRQ_EN_m, base + RP2_ASIC_IRQ);
|
||||
}
|
||||
|
||||
static void rp2_init_card(struct rp2_card *card)
|
||||
{
|
||||
writel(4, card->bar0 + RP2_FPGA_CTL0);
|
||||
writel(0, card->bar0 + RP2_FPGA_CTL1);
|
||||
|
||||
rp2_reset_asic(card, 0);
|
||||
if (card->n_ports >= PORTS_PER_ASIC)
|
||||
rp2_reset_asic(card, 1);
|
||||
|
||||
writel(RP2_IRQ_MASK_EN_m, card->bar0 + RP2_IRQ_MASK);
|
||||
}
|
||||
|
||||
static void rp2_init_port(struct rp2_uart_port *up, const struct firmware *fw)
|
||||
{
|
||||
int i;
|
||||
|
||||
writel(RP2_UART_CTL_RESET_CH_m, up->base + RP2_UART_CTL);
|
||||
readl(up->base + RP2_UART_CTL);
|
||||
udelay(1);
|
||||
|
||||
writel(0, up->base + RP2_TXRX_CTL);
|
||||
writel(0, up->base + RP2_UART_CTL);
|
||||
readl(up->base + RP2_UART_CTL);
|
||||
udelay(1);
|
||||
|
||||
rp2_flush_fifos(up);
|
||||
|
||||
for (i = 0; i < min_t(int, fw->size, RP2_UCODE_BYTES); i++)
|
||||
writeb(fw->data[i], up->ucode + i);
|
||||
|
||||
__rp2_uart_set_termios(up, CS8 | CREAD | CLOCAL, 0, DEFAULT_BAUD_DIV);
|
||||
rp2_uart_set_mctrl(&up->port, 0);
|
||||
|
||||
writeb(RP2_RX_FIFO_ena, up->ucode + RP2_RX_FIFO);
|
||||
rp2_rmw(up, RP2_UART_CTL, RP2_UART_CTL_MODE_m,
|
||||
RP2_UART_CTL_XMIT_EN_m | RP2_UART_CTL_MODE_rs232);
|
||||
rp2_rmw_set(up, RP2_TXRX_CTL,
|
||||
RP2_TXRX_CTL_TX_EN_m | RP2_TXRX_CTL_RX_EN_m);
|
||||
}
|
||||
|
||||
static void rp2_remove_ports(struct rp2_card *card)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < card->initialized_ports; i++)
|
||||
uart_remove_one_port(&rp2_uart_driver, &card->ports[i].port);
|
||||
card->initialized_ports = 0;
|
||||
}
|
||||
|
||||
static void rp2_fw_cb(const struct firmware *fw, void *context)
|
||||
{
|
||||
struct rp2_card *card = context;
|
||||
resource_size_t phys_base;
|
||||
int i, rc = -ENOENT;
|
||||
|
||||
if (!fw) {
|
||||
dev_err(&card->pdev->dev, "cannot find '%s' firmware image\n",
|
||||
RP2_FW_NAME);
|
||||
goto no_fw;
|
||||
}
|
||||
|
||||
phys_base = pci_resource_start(card->pdev, 1);
|
||||
|
||||
for (i = 0; i < card->n_ports; i++) {
|
||||
struct rp2_uart_port *rp = &card->ports[i];
|
||||
struct uart_port *p;
|
||||
int j = (unsigned)i % PORTS_PER_ASIC;
|
||||
|
||||
rp->asic_base = card->bar1;
|
||||
rp->base = card->bar1 + RP2_PORT_BASE + j*RP2_PORT_SPACING;
|
||||
rp->ucode = card->bar1 + RP2_UCODE_BASE + j*RP2_UCODE_SPACING;
|
||||
rp->card = card;
|
||||
rp->idx = j;
|
||||
|
||||
p = &rp->port;
|
||||
p->line = card->minor_start + i;
|
||||
p->dev = &card->pdev->dev;
|
||||
p->type = PORT_RP2;
|
||||
p->iotype = UPIO_MEM32;
|
||||
p->uartclk = UART_CLOCK;
|
||||
p->regshift = 2;
|
||||
p->fifosize = FIFO_SIZE;
|
||||
p->ops = &rp2_uart_ops;
|
||||
p->irq = card->pdev->irq;
|
||||
p->membase = rp->base;
|
||||
p->mapbase = phys_base + RP2_PORT_BASE + j*RP2_PORT_SPACING;
|
||||
|
||||
if (i >= PORTS_PER_ASIC) {
|
||||
rp->asic_base += RP2_ASIC_SPACING;
|
||||
rp->base += RP2_ASIC_SPACING;
|
||||
rp->ucode += RP2_ASIC_SPACING;
|
||||
p->mapbase += RP2_ASIC_SPACING;
|
||||
}
|
||||
|
||||
rp2_init_port(rp, fw);
|
||||
rc = uart_add_one_port(&rp2_uart_driver, p);
|
||||
if (rc) {
|
||||
dev_err(&card->pdev->dev,
|
||||
"error registering port %d: %d\n", i, rc);
|
||||
rp2_remove_ports(card);
|
||||
break;
|
||||
}
|
||||
card->initialized_ports++;
|
||||
}
|
||||
|
||||
release_firmware(fw);
|
||||
no_fw:
|
||||
/*
|
||||
* rp2_fw_cb() is called from a workqueue long after rp2_probe()
|
||||
* has already returned success. So if something failed here,
|
||||
* we'll just leave the now-dormant device in place until somebody
|
||||
* unbinds it.
|
||||
*/
|
||||
if (rc)
|
||||
dev_warn(&card->pdev->dev, "driver initialization failed\n");
|
||||
|
||||
complete(&card->fw_loaded);
|
||||
}
|
||||
|
||||
static int rp2_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct rp2_card *card;
|
||||
struct rp2_uart_port *ports;
|
||||
void __iomem * const *bars;
|
||||
int rc;
|
||||
|
||||
card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
|
||||
if (!card)
|
||||
return -ENOMEM;
|
||||
pci_set_drvdata(pdev, card);
|
||||
spin_lock_init(&card->card_lock);
|
||||
init_completion(&card->fw_loaded);
|
||||
|
||||
rc = pcim_enable_device(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pcim_iomap_regions_request_all(pdev, 0x03, DRV_NAME);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
bars = pcim_iomap_table(pdev);
|
||||
card->bar0 = bars[0];
|
||||
card->bar1 = bars[1];
|
||||
card->pdev = pdev;
|
||||
|
||||
rp2_decode_cap(id, &card->n_ports, &card->smpte);
|
||||
dev_info(&pdev->dev, "found new card with %d ports\n", card->n_ports);
|
||||
|
||||
card->minor_start = rp2_alloc_ports(card->n_ports);
|
||||
if (card->minor_start < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"too many ports (try increasing CONFIG_SERIAL_RP2_NR_UARTS)\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rp2_init_card(card);
|
||||
|
||||
ports = devm_kzalloc(&pdev->dev, sizeof(*ports) * card->n_ports,
|
||||
GFP_KERNEL);
|
||||
if (!ports)
|
||||
return -ENOMEM;
|
||||
card->ports = ports;
|
||||
|
||||
rc = devm_request_irq(&pdev->dev, pdev->irq, rp2_uart_interrupt,
|
||||
IRQF_SHARED, DRV_NAME, card);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/*
|
||||
* Only catastrophic errors (e.g. ENOMEM) are reported here.
|
||||
* If the FW image is missing, we'll find out in rp2_fw_cb()
|
||||
* and print an error message.
|
||||
*/
|
||||
rc = request_firmware_nowait(THIS_MODULE, 1, RP2_FW_NAME, &pdev->dev,
|
||||
GFP_KERNEL, card, rp2_fw_cb);
|
||||
if (rc)
|
||||
return rc;
|
||||
dev_dbg(&pdev->dev, "waiting for firmware blob...\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rp2_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct rp2_card *card = pci_get_drvdata(pdev);
|
||||
|
||||
wait_for_completion(&card->fw_loaded);
|
||||
rp2_remove_ports(card);
|
||||
}
|
||||
|
||||
static DEFINE_PCI_DEVICE_TABLE(rp2_pci_tbl) = {
|
||||
|
||||
/* RocketPort INFINITY cards */
|
||||
|
||||
{ RP_ID(0x0040), RP_CAP(8, 0) }, /* INF Octa, RJ45, selectable */
|
||||
{ RP_ID(0x0041), RP_CAP(32, 0) }, /* INF 32, ext interface */
|
||||
{ RP_ID(0x0042), RP_CAP(8, 0) }, /* INF Octa, ext interface */
|
||||
{ RP_ID(0x0043), RP_CAP(16, 0) }, /* INF 16, ext interface */
|
||||
{ RP_ID(0x0044), RP_CAP(4, 0) }, /* INF Quad, DB, selectable */
|
||||
{ RP_ID(0x0045), RP_CAP(8, 0) }, /* INF Octa, DB, selectable */
|
||||
{ RP_ID(0x0046), RP_CAP(4, 0) }, /* INF Quad, ext interface */
|
||||
{ RP_ID(0x0047), RP_CAP(4, 0) }, /* INF Quad, RJ45 */
|
||||
{ RP_ID(0x004a), RP_CAP(4, 0) }, /* INF Plus, Quad */
|
||||
{ RP_ID(0x004b), RP_CAP(8, 0) }, /* INF Plus, Octa */
|
||||
{ RP_ID(0x004c), RP_CAP(8, 0) }, /* INF III, Octa */
|
||||
{ RP_ID(0x004d), RP_CAP(4, 0) }, /* INF III, Quad */
|
||||
{ RP_ID(0x004e), RP_CAP(2, 0) }, /* INF Plus, 2, RS232 */
|
||||
{ RP_ID(0x004f), RP_CAP(2, 1) }, /* INF Plus, 2, SMPTE */
|
||||
{ RP_ID(0x0050), RP_CAP(4, 0) }, /* INF Plus, Quad, RJ45 */
|
||||
{ RP_ID(0x0051), RP_CAP(8, 0) }, /* INF Plus, Octa, RJ45 */
|
||||
{ RP_ID(0x0052), RP_CAP(8, 1) }, /* INF Octa, SMPTE */
|
||||
|
||||
/* RocketPort EXPRESS cards */
|
||||
|
||||
{ RP_ID(0x0060), RP_CAP(8, 0) }, /* EXP Octa, RJ45, selectable */
|
||||
{ RP_ID(0x0061), RP_CAP(32, 0) }, /* EXP 32, ext interface */
|
||||
{ RP_ID(0x0062), RP_CAP(8, 0) }, /* EXP Octa, ext interface */
|
||||
{ RP_ID(0x0063), RP_CAP(16, 0) }, /* EXP 16, ext interface */
|
||||
{ RP_ID(0x0064), RP_CAP(4, 0) }, /* EXP Quad, DB, selectable */
|
||||
{ RP_ID(0x0065), RP_CAP(8, 0) }, /* EXP Octa, DB, selectable */
|
||||
{ RP_ID(0x0066), RP_CAP(4, 0) }, /* EXP Quad, ext interface */
|
||||
{ RP_ID(0x0067), RP_CAP(4, 0) }, /* EXP Quad, RJ45 */
|
||||
{ RP_ID(0x0068), RP_CAP(8, 0) }, /* EXP Octa, RJ11 */
|
||||
{ RP_ID(0x0072), RP_CAP(8, 1) }, /* EXP Octa, SMPTE */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, rp2_pci_tbl);
|
||||
|
||||
static struct pci_driver rp2_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = rp2_pci_tbl,
|
||||
.probe = rp2_probe,
|
||||
.remove = rp2_remove,
|
||||
};
|
||||
|
||||
static int __init rp2_uart_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = uart_register_driver(&rp2_uart_driver);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = pci_register_driver(&rp2_pci_driver);
|
||||
if (rc) {
|
||||
uart_unregister_driver(&rp2_uart_driver);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rp2_uart_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&rp2_pci_driver);
|
||||
uart_unregister_driver(&rp2_uart_driver);
|
||||
}
|
||||
|
||||
module_init(rp2_uart_init);
|
||||
module_exit(rp2_uart_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Comtrol RocketPort EXPRESS/INFINITY driver");
|
||||
MODULE_AUTHOR("Kevin Cernekee <cernekee@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_FIRMWARE(RP2_FW_NAME);
|
@@ -188,7 +188,6 @@ static void sa1100_enable_ms(struct uart_port *port)
|
||||
static void
|
||||
sa1100_rx_chars(struct sa1100_port *sport)
|
||||
{
|
||||
struct tty_struct *tty = sport->port.state->port.tty;
|
||||
unsigned int status, ch, flg;
|
||||
|
||||
status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
|
||||
@@ -233,7 +232,7 @@ sa1100_rx_chars(struct sa1100_port *sport)
|
||||
status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
|
||||
UTSR0_TO_SM(UART_GET_UTSR0(sport));
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&sport->port.state->port);
|
||||
}
|
||||
|
||||
static void sa1100_tx_chars(struct sa1100_port *sport)
|
||||
|
@@ -47,7 +47,6 @@
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/map.h>
|
||||
|
||||
#include <plat/regs-serial.h>
|
||||
#include <plat/clock.h>
|
||||
@@ -221,7 +220,6 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
|
||||
{
|
||||
struct s3c24xx_uart_port *ourport = dev_id;
|
||||
struct uart_port *port = &ourport->port;
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
unsigned int ufcon, ch, flag, ufstat, uerstat;
|
||||
unsigned long flags;
|
||||
int max_count = 64;
|
||||
@@ -299,7 +297,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id)
|
||||
ignore_char:
|
||||
continue;
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
@@ -1143,8 +1141,13 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
||||
|
||||
dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
|
||||
|
||||
port->membase = devm_ioremap(port->dev, res->start, resource_size(res));
|
||||
if (!port->membase) {
|
||||
dev_err(port->dev, "failed to remap controller address\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
port->mapbase = res->start;
|
||||
port->membase = S3C_VA_UART + (res->start & 0xfffff);
|
||||
ret = platform_get_irq(platdev, 0);
|
||||
if (ret < 0)
|
||||
port->irq = 0;
|
||||
@@ -1724,8 +1727,6 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = {
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
|
||||
#else
|
||||
#define s3c24xx_uart_dt_match NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver samsung_serial_driver = {
|
||||
@@ -1736,7 +1737,7 @@ static struct platform_driver samsung_serial_driver = {
|
||||
.name = "samsung-uart",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = SERIAL_SAMSUNG_PM_OPS,
|
||||
.of_match_table = s3c24xx_uart_dt_match,
|
||||
.of_match_table = of_match_ptr(s3c24xx_uart_dt_match),
|
||||
},
|
||||
};
|
||||
|
||||
|
@@ -384,7 +384,7 @@ static void sbd_receive_chars(struct sbd_port *sport)
|
||||
uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(uport->state->port.tty);
|
||||
tty_flip_buffer_push(&uport->state->port);
|
||||
}
|
||||
|
||||
static void sbd_transmit_chars(struct sbd_port *sport)
|
||||
|
@@ -136,16 +136,17 @@ static void sc26xx_disable_irq(struct uart_port *port, int mask)
|
||||
WRITE_SC(port, IMR, up->imr);
|
||||
}
|
||||
|
||||
static struct tty_struct *receive_chars(struct uart_port *port)
|
||||
static bool receive_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_struct *tty = NULL;
|
||||
struct tty_port *tport = NULL;
|
||||
int limit = 10000;
|
||||
unsigned char ch;
|
||||
char flag;
|
||||
u8 status;
|
||||
|
||||
/* FIXME what is this trying to achieve? */
|
||||
if (port->state != NULL) /* Unopened serial console */
|
||||
tty = port->state->port.tty;
|
||||
tport = &port->state->port;
|
||||
|
||||
while (limit-- > 0) {
|
||||
status = READ_SC_PORT(port, SR);
|
||||
@@ -185,9 +186,9 @@ static struct tty_struct *receive_chars(struct uart_port *port)
|
||||
if (status & port->ignore_status_mask)
|
||||
continue;
|
||||
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(tport, ch, flag);
|
||||
}
|
||||
return tty;
|
||||
return !!tport;
|
||||
}
|
||||
|
||||
static void transmit_chars(struct uart_port *port)
|
||||
@@ -217,36 +218,36 @@ static void transmit_chars(struct uart_port *port)
|
||||
static irqreturn_t sc26xx_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_sc26xx_port *up = dev_id;
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
bool push;
|
||||
u8 isr;
|
||||
|
||||
spin_lock_irqsave(&up->port[0].lock, flags);
|
||||
|
||||
tty = NULL;
|
||||
push = false;
|
||||
isr = READ_SC(&up->port[0], ISR);
|
||||
if (isr & ISR_TXRDYA)
|
||||
transmit_chars(&up->port[0]);
|
||||
if (isr & ISR_RXRDYA)
|
||||
tty = receive_chars(&up->port[0]);
|
||||
push = receive_chars(&up->port[0]);
|
||||
|
||||
spin_unlock(&up->port[0].lock);
|
||||
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (push)
|
||||
tty_flip_buffer_push(&up->port[0].state->port);
|
||||
|
||||
spin_lock(&up->port[1].lock);
|
||||
|
||||
tty = NULL;
|
||||
push = false;
|
||||
if (isr & ISR_TXRDYB)
|
||||
transmit_chars(&up->port[1]);
|
||||
if (isr & ISR_RXRDYB)
|
||||
tty = receive_chars(&up->port[1]);
|
||||
push = receive_chars(&up->port[1]);
|
||||
|
||||
spin_unlock_irqrestore(&up->port[1].lock, flags);
|
||||
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (push)
|
||||
tty_flip_buffer_push(&up->port[1].state->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -24,8 +24,9 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/sccnxp.h>
|
||||
#include <linux/platform_data/serial-sccnxp.h>
|
||||
|
||||
#define SCCNXP_NAME "uart-sccnxp"
|
||||
#define SCCNXP_MAJOR 204
|
||||
@@ -107,6 +108,7 @@ enum {
|
||||
struct sccnxp_port {
|
||||
struct uart_driver uart;
|
||||
struct uart_port port[SCCNXP_MAX_UARTS];
|
||||
bool opened[SCCNXP_MAX_UARTS];
|
||||
|
||||
const char *name;
|
||||
int irq;
|
||||
@@ -123,7 +125,10 @@ struct sccnxp_port {
|
||||
struct console console;
|
||||
#endif
|
||||
|
||||
struct mutex sccnxp_mutex;
|
||||
spinlock_t lock;
|
||||
|
||||
bool poll;
|
||||
struct timer_list timer;
|
||||
|
||||
struct sccnxp_pdata pdata;
|
||||
};
|
||||
@@ -175,14 +180,12 @@ static int sccnxp_update_best_err(int a, int b, int *besterr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct baud_table {
|
||||
static const struct {
|
||||
u8 csr;
|
||||
u8 acr;
|
||||
u8 mr0;
|
||||
int baud;
|
||||
};
|
||||
|
||||
const struct baud_table baud_std[] = {
|
||||
} baud_std[] = {
|
||||
{ 0, ACR_BAUD0, MR0_BAUD_NORMAL, 50, },
|
||||
{ 0, ACR_BAUD1, MR0_BAUD_NORMAL, 75, },
|
||||
{ 1, ACR_BAUD0, MR0_BAUD_NORMAL, 110, },
|
||||
@@ -286,10 +289,6 @@ static void sccnxp_handle_rx(struct uart_port *port)
|
||||
{
|
||||
u8 sr;
|
||||
unsigned int ch, flag;
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->state->port);
|
||||
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
sr = sccnxp_port_read(port, SCCNXP_SR_REG);
|
||||
@@ -305,14 +304,19 @@ static void sccnxp_handle_rx(struct uart_port *port)
|
||||
if (unlikely(sr)) {
|
||||
if (sr & SR_BRK) {
|
||||
port->icount.brk++;
|
||||
sccnxp_port_write(port, SCCNXP_CR_REG,
|
||||
CR_CMD_BREAK_RESET);
|
||||
if (uart_handle_break(port))
|
||||
continue;
|
||||
} else if (sr & SR_PE)
|
||||
port->icount.parity++;
|
||||
else if (sr & SR_FE)
|
||||
port->icount.frame++;
|
||||
else if (sr & SR_OVR)
|
||||
else if (sr & SR_OVR) {
|
||||
port->icount.overrun++;
|
||||
sccnxp_port_write(port, SCCNXP_CR_REG,
|
||||
CR_CMD_STATUS_RESET);
|
||||
}
|
||||
|
||||
sr &= port->read_status_mask;
|
||||
if (sr & SR_BRK)
|
||||
@@ -334,9 +338,7 @@ static void sccnxp_handle_rx(struct uart_port *port)
|
||||
uart_insert_char(port, sr, SR_OVR, ch, flag);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void sccnxp_handle_tx(struct uart_port *port)
|
||||
@@ -378,31 +380,48 @@ static void sccnxp_handle_tx(struct uart_port *port)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
static irqreturn_t sccnxp_ist(int irq, void *dev_id)
|
||||
static void sccnxp_handle_events(struct sccnxp_port *s)
|
||||
{
|
||||
int i;
|
||||
u8 isr;
|
||||
struct sccnxp_port *s = (struct sccnxp_port *)dev_id;
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
|
||||
for (;;) {
|
||||
do {
|
||||
isr = sccnxp_read(&s->port[0], SCCNXP_ISR_REG);
|
||||
isr &= s->imr;
|
||||
if (!isr)
|
||||
break;
|
||||
|
||||
dev_dbg(s->port[0].dev, "IRQ status: 0x%02x\n", isr);
|
||||
|
||||
for (i = 0; i < s->uart.nr; i++) {
|
||||
if (isr & ISR_RXRDY(i))
|
||||
if (s->opened[i] && (isr & ISR_RXRDY(i)))
|
||||
sccnxp_handle_rx(&s->port[i]);
|
||||
if (isr & ISR_TXRDY(i))
|
||||
if (s->opened[i] && (isr & ISR_TXRDY(i)))
|
||||
sccnxp_handle_tx(&s->port[i]);
|
||||
}
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
static void sccnxp_timer(unsigned long data)
|
||||
{
|
||||
struct sccnxp_port *s = (struct sccnxp_port *)data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
sccnxp_handle_events(s);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
|
||||
if (!timer_pending(&s->timer))
|
||||
mod_timer(&s->timer, jiffies +
|
||||
usecs_to_jiffies(s->pdata.poll_time_us));
|
||||
}
|
||||
|
||||
static irqreturn_t sccnxp_ist(int irq, void *dev_id)
|
||||
{
|
||||
struct sccnxp_port *s = (struct sccnxp_port *)dev_id;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
sccnxp_handle_events(s);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -410,8 +429,9 @@ static irqreturn_t sccnxp_ist(int irq, void *dev_id)
|
||||
static void sccnxp_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
|
||||
/* Set direction to output */
|
||||
if (s->flags & SCCNXP_HAVE_IO)
|
||||
@@ -419,7 +439,7 @@ static void sccnxp_start_tx(struct uart_port *port)
|
||||
|
||||
sccnxp_enable_irq(port, IMR_TXRDY);
|
||||
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
}
|
||||
|
||||
static void sccnxp_stop_tx(struct uart_port *port)
|
||||
@@ -430,20 +450,22 @@ static void sccnxp_stop_tx(struct uart_port *port)
|
||||
static void sccnxp_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE);
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
}
|
||||
|
||||
static unsigned int sccnxp_tx_empty(struct uart_port *port)
|
||||
{
|
||||
u8 val;
|
||||
unsigned long flags;
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
val = sccnxp_port_read(port, SCCNXP_SR_REG);
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
|
||||
return (val & SR_TXEMT) ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
@@ -456,28 +478,30 @@ static void sccnxp_enable_ms(struct uart_port *port)
|
||||
static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned long flags;
|
||||
|
||||
if (!(s->flags & SCCNXP_HAVE_IO))
|
||||
return;
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
|
||||
sccnxp_set_bit(port, DTR_OP, mctrl & TIOCM_DTR);
|
||||
sccnxp_set_bit(port, RTS_OP, mctrl & TIOCM_RTS);
|
||||
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
}
|
||||
|
||||
static unsigned int sccnxp_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
u8 bitmask, ipr;
|
||||
unsigned long flags;
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
|
||||
|
||||
if (!(s->flags & SCCNXP_HAVE_IO))
|
||||
return mctrl;
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
|
||||
ipr = ~sccnxp_read(port, SCCNXP_IPCR_REG);
|
||||
|
||||
@@ -506,7 +530,7 @@ static unsigned int sccnxp_get_mctrl(struct uart_port *port)
|
||||
mctrl |= (ipr & bitmask) ? TIOCM_RNG : 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
|
||||
return mctrl;
|
||||
}
|
||||
@@ -514,21 +538,23 @@ static unsigned int sccnxp_get_mctrl(struct uart_port *port)
|
||||
static void sccnxp_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
sccnxp_port_write(port, SCCNXP_CR_REG, break_state ?
|
||||
CR_CMD_START_BREAK : CR_CMD_STOP_BREAK);
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
}
|
||||
|
||||
static void sccnxp_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios, struct ktermios *old)
|
||||
{
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned long flags;
|
||||
u8 mr1, mr2;
|
||||
int baud;
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
|
||||
/* Mask termios capabilities we don't support */
|
||||
termios->c_cflag &= ~CMSPAR;
|
||||
@@ -595,20 +621,22 @@ static void sccnxp_set_termios(struct uart_port *port,
|
||||
/* Update timeout according to new baud rate */
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
|
||||
/* Report actual baudrate back to core */
|
||||
if (tty_termios_baud_rate(termios))
|
||||
tty_termios_encode_baud_rate(termios, baud, baud);
|
||||
|
||||
/* Enable RX & TX */
|
||||
sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_ENABLE | CR_TX_ENABLE);
|
||||
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
}
|
||||
|
||||
static int sccnxp_startup(struct uart_port *port)
|
||||
{
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
|
||||
if (s->flags & SCCNXP_HAVE_IO) {
|
||||
/* Outputs are controlled manually */
|
||||
@@ -627,7 +655,9 @@ static int sccnxp_startup(struct uart_port *port)
|
||||
/* Enable RX interrupt */
|
||||
sccnxp_enable_irq(port, IMR_RXRDY);
|
||||
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
s->opened[port->line] = 1;
|
||||
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -635,8 +665,11 @@ static int sccnxp_startup(struct uart_port *port)
|
||||
static void sccnxp_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct sccnxp_port *s = dev_get_drvdata(port->dev);
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
|
||||
s->opened[port->line] = 0;
|
||||
|
||||
/* Disable interrupts */
|
||||
sccnxp_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
|
||||
@@ -648,7 +681,7 @@ static void sccnxp_shutdown(struct uart_port *port)
|
||||
if (s->flags & SCCNXP_HAVE_IO)
|
||||
sccnxp_set_bit(port, DIR_OP, 0);
|
||||
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
}
|
||||
|
||||
static const char *sccnxp_type(struct uart_port *port)
|
||||
@@ -722,10 +755,11 @@ static void sccnxp_console_write(struct console *co, const char *c, unsigned n)
|
||||
{
|
||||
struct sccnxp_port *s = (struct sccnxp_port *)co->data;
|
||||
struct uart_port *port = &s->port[co->index];
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&s->sccnxp_mutex);
|
||||
spin_lock_irqsave(&s->lock, flags);
|
||||
uart_console_write(port, c, n, sccnxp_console_putchar);
|
||||
mutex_unlock(&s->sccnxp_mutex);
|
||||
spin_unlock_irqrestore(&s->lock, flags);
|
||||
}
|
||||
|
||||
static int sccnxp_console_setup(struct console *co, char *options)
|
||||
@@ -764,7 +798,7 @@ static int sccnxp_probe(struct platform_device *pdev)
|
||||
}
|
||||
platform_set_drvdata(pdev, s);
|
||||
|
||||
mutex_init(&s->sccnxp_mutex);
|
||||
spin_lock_init(&s->lock);
|
||||
|
||||
/* Individual chip settings */
|
||||
switch (chiptype) {
|
||||
@@ -861,11 +895,19 @@ static int sccnxp_probe(struct platform_device *pdev)
|
||||
} else
|
||||
memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata));
|
||||
|
||||
s->irq = platform_get_irq(pdev, 0);
|
||||
if (s->irq <= 0) {
|
||||
dev_err(&pdev->dev, "Missing irq resource data\n");
|
||||
ret = -ENXIO;
|
||||
goto err_out;
|
||||
if (s->pdata.poll_time_us) {
|
||||
dev_info(&pdev->dev, "Using poll mode, resolution %u usecs\n",
|
||||
s->pdata.poll_time_us);
|
||||
s->poll = 1;
|
||||
}
|
||||
|
||||
if (!s->poll) {
|
||||
s->irq = platform_get_irq(pdev, 0);
|
||||
if (s->irq < 0) {
|
||||
dev_err(&pdev->dev, "Missing irq resource data\n");
|
||||
ret = -ENXIO;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check input frequency */
|
||||
@@ -929,13 +971,23 @@ static int sccnxp_probe(struct platform_device *pdev)
|
||||
if (s->pdata.init)
|
||||
s->pdata.init();
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL, sccnxp_ist,
|
||||
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), s);
|
||||
if (!ret)
|
||||
return 0;
|
||||
if (!s->poll) {
|
||||
ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL,
|
||||
sccnxp_ist,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), s);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq);
|
||||
dev_err(&pdev->dev, "Unable to reguest IRQ %i\n", s->irq);
|
||||
} else {
|
||||
init_timer(&s->timer);
|
||||
setup_timer(&s->timer, sccnxp_timer, (unsigned long)s);
|
||||
mod_timer(&s->timer, jiffies +
|
||||
usecs_to_jiffies(s->pdata.poll_time_us));
|
||||
return 0;
|
||||
}
|
||||
|
||||
err_out:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
@@ -948,7 +1000,10 @@ static int sccnxp_remove(struct platform_device *pdev)
|
||||
int i;
|
||||
struct sccnxp_port *s = platform_get_drvdata(pdev);
|
||||
|
||||
devm_free_irq(&pdev->dev, s->irq, s);
|
||||
if (!s->poll)
|
||||
devm_free_irq(&pdev->dev, s->irq, s);
|
||||
else
|
||||
del_timer_sync(&s->timer);
|
||||
|
||||
for (i = 0; i < s->uart.nr; i++)
|
||||
uart_remove_one_port(&s->uart, &s->port[i]);
|
||||
|
1401
drivers/tty/serial/serial-tegra.c
Normal file
1401
drivers/tty/serial/serial-tegra.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -59,7 +59,8 @@ static struct lock_class_key port_lock_key;
|
||||
static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
|
||||
struct ktermios *old_termios);
|
||||
static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
|
||||
static void uart_change_pm(struct uart_state *state, int pm_state);
|
||||
static void uart_change_pm(struct uart_state *state,
|
||||
enum uart_pm_state pm_state);
|
||||
|
||||
static void uart_port_shutdown(struct tty_port *port);
|
||||
|
||||
@@ -866,9 +867,7 @@ 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;
|
||||
if (port->tty)
|
||||
port->tty->low_latency =
|
||||
(uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
|
||||
port->low_latency = (uport->flags & UPF_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
check_and_exit:
|
||||
retval = 0;
|
||||
@@ -1308,9 +1307,10 @@ static void uart_set_termios(struct tty_struct *tty,
|
||||
}
|
||||
|
||||
/*
|
||||
* In 2.4.5, calls to this will be serialized via the BKL in
|
||||
* linux/drivers/char/tty_io.c:tty_release()
|
||||
* linux/drivers/char/tty_io.c:do_tty_handup()
|
||||
* Calls to uart_close() are serialised via the tty_lock in
|
||||
* drivers/tty/tty_io.c:tty_release()
|
||||
* drivers/tty/tty_io.c:do_tty_hangup()
|
||||
* This runs from a workqueue and can sleep for a _short_ time only.
|
||||
*/
|
||||
static void uart_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
@@ -1365,7 +1365,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
} else if (!uart_console(uport)) {
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
uart_change_pm(state, 3);
|
||||
uart_change_pm(state, UART_PM_STATE_OFF);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
}
|
||||
|
||||
@@ -1437,10 +1437,9 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called with the BKL held in
|
||||
* linux/drivers/char/tty_io.c:do_tty_hangup()
|
||||
* We're called from the eventd thread, so we can sleep for
|
||||
* a _short_ time only.
|
||||
* Calls to uart_hangup() are serialised by the tty_lock in
|
||||
* drivers/tty/tty_io.c:do_tty_hangup()
|
||||
* This runs from a workqueue and can sleep for a _short_ time only.
|
||||
*/
|
||||
static void uart_hangup(struct tty_struct *tty)
|
||||
{
|
||||
@@ -1521,8 +1520,8 @@ static void uart_dtr_rts(struct tty_port *port, int onoff)
|
||||
}
|
||||
|
||||
/*
|
||||
* calls to uart_open are serialised by the BKL in
|
||||
* fs/char_dev.c:chrdev_open()
|
||||
* Calls to uart_open are serialised by the tty_lock in
|
||||
* drivers/tty/tty_io.c:tty_open()
|
||||
* Note that if this fails, then uart_close() _will_ be called.
|
||||
*
|
||||
* In time, we want to scrap the "opening nonpresent ports"
|
||||
@@ -1564,7 +1563,8 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
|
||||
*/
|
||||
tty->driver_data = state;
|
||||
state->uart_port->state = state;
|
||||
tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
|
||||
state->port.low_latency =
|
||||
(state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
|
||||
tty_port_tty_set(port, tty);
|
||||
|
||||
/*
|
||||
@@ -1579,7 +1579,7 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
|
||||
* Make sure the device is in D0 state.
|
||||
*/
|
||||
if (port->count == 1)
|
||||
uart_change_pm(state, 0);
|
||||
uart_change_pm(state, UART_PM_STATE_ON);
|
||||
|
||||
/*
|
||||
* Start up the serial port.
|
||||
@@ -1620,7 +1620,7 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
|
||||
{
|
||||
struct uart_state *state = drv->state + i;
|
||||
struct tty_port *port = &state->port;
|
||||
int pm_state;
|
||||
enum uart_pm_state pm_state;
|
||||
struct uart_port *uport = state->uart_port;
|
||||
char stat_buf[32];
|
||||
unsigned int status;
|
||||
@@ -1645,12 +1645,12 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
|
||||
if (capable(CAP_SYS_ADMIN)) {
|
||||
mutex_lock(&port->mutex);
|
||||
pm_state = state->pm_state;
|
||||
if (pm_state)
|
||||
uart_change_pm(state, 0);
|
||||
if (pm_state != UART_PM_STATE_ON)
|
||||
uart_change_pm(state, UART_PM_STATE_ON);
|
||||
spin_lock_irq(&uport->lock);
|
||||
status = uport->ops->get_mctrl(uport);
|
||||
spin_unlock_irq(&uport->lock);
|
||||
if (pm_state)
|
||||
if (pm_state != UART_PM_STATE_ON)
|
||||
uart_change_pm(state, pm_state);
|
||||
mutex_unlock(&port->mutex);
|
||||
|
||||
@@ -1897,7 +1897,8 @@ EXPORT_SYMBOL_GPL(uart_set_options);
|
||||
*
|
||||
* Locking: port->mutex has to be held
|
||||
*/
|
||||
static void uart_change_pm(struct uart_state *state, int pm_state)
|
||||
static void uart_change_pm(struct uart_state *state,
|
||||
enum uart_pm_state pm_state)
|
||||
{
|
||||
struct uart_port *port = state->uart_port;
|
||||
|
||||
@@ -1982,7 +1983,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
console_stop(uport->cons);
|
||||
|
||||
if (console_suspend_enabled || !uart_console(uport))
|
||||
uart_change_pm(state, 3);
|
||||
uart_change_pm(state, UART_PM_STATE_OFF);
|
||||
|
||||
mutex_unlock(&port->mutex);
|
||||
|
||||
@@ -2027,7 +2028,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
termios = port->tty->termios;
|
||||
|
||||
if (console_suspend_enabled)
|
||||
uart_change_pm(state, 0);
|
||||
uart_change_pm(state, UART_PM_STATE_ON);
|
||||
uport->ops->set_termios(uport, &termios, NULL);
|
||||
if (console_suspend_enabled)
|
||||
console_start(uport->cons);
|
||||
@@ -2037,7 +2038,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
const struct uart_ops *ops = uport->ops;
|
||||
int ret;
|
||||
|
||||
uart_change_pm(state, 0);
|
||||
uart_change_pm(state, UART_PM_STATE_ON);
|
||||
spin_lock_irq(&uport->lock);
|
||||
ops->set_mctrl(uport, 0);
|
||||
spin_unlock_irq(&uport->lock);
|
||||
@@ -2137,7 +2138,7 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
|
||||
uart_report_port(drv, port);
|
||||
|
||||
/* Power up port for set_mctrl() */
|
||||
uart_change_pm(state, 0);
|
||||
uart_change_pm(state, UART_PM_STATE_ON);
|
||||
|
||||
/*
|
||||
* Ensure that the modem control lines are de-activated.
|
||||
@@ -2161,7 +2162,7 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
|
||||
* console if we have one.
|
||||
*/
|
||||
if (!uart_console(port))
|
||||
uart_change_pm(state, 3);
|
||||
uart_change_pm(state, UART_PM_STATE_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2588,7 +2589,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
}
|
||||
|
||||
state->uart_port = uport;
|
||||
state->pm_state = -1;
|
||||
state->pm_state = UART_PM_STATE_UNDEFINED;
|
||||
|
||||
uport->cons = drv->cons;
|
||||
uport->state = state;
|
||||
@@ -2642,6 +2643,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
{
|
||||
struct uart_state *state = drv->state + uport->line;
|
||||
struct tty_port *port = &state->port;
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(in_interrupt());
|
||||
|
||||
@@ -2656,6 +2658,11 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
* succeeding while we shut down the port.
|
||||
*/
|
||||
mutex_lock(&port->mutex);
|
||||
if (!state->uart_port) {
|
||||
mutex_unlock(&port->mutex);
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
uport->flags |= UPF_DEAD;
|
||||
mutex_unlock(&port->mutex);
|
||||
|
||||
@@ -2679,9 +2686,10 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
uport->type = PORT_UNKNOWN;
|
||||
|
||||
state->uart_port = NULL;
|
||||
out:
|
||||
mutex_unlock(&port_mutex);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2715,22 +2723,17 @@ EXPORT_SYMBOL(uart_match_port);
|
||||
*/
|
||||
void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
|
||||
{
|
||||
struct uart_state *state = uport->state;
|
||||
struct tty_port *port = &state->port;
|
||||
struct tty_ldisc *ld = NULL;
|
||||
struct pps_event_time ts;
|
||||
struct tty_port *port = &uport->state->port;
|
||||
struct tty_struct *tty = port->tty;
|
||||
struct tty_ldisc *ld = tty ? tty_ldisc_ref(tty) : NULL;
|
||||
|
||||
if (tty)
|
||||
ld = tty_ldisc_ref(tty);
|
||||
if (ld && ld->ops->dcd_change)
|
||||
pps_get_ts(&ts);
|
||||
if (ld) {
|
||||
if (ld->ops->dcd_change)
|
||||
ld->ops->dcd_change(tty, status);
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
|
||||
uport->icount.dcd++;
|
||||
#ifdef CONFIG_HARD_PPS
|
||||
if ((uport->flags & UPF_HARDPPS_CD) && status)
|
||||
hardpps();
|
||||
#endif
|
||||
|
||||
if (port->flags & ASYNC_CHECK_CD) {
|
||||
if (status)
|
||||
@@ -2738,11 +2741,6 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
|
||||
else if (tty)
|
||||
tty_hangup(tty);
|
||||
}
|
||||
|
||||
if (ld && ld->ops->dcd_change)
|
||||
ld->ops->dcd_change(tty, status, &ts);
|
||||
if (ld)
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
|
||||
|
||||
@@ -2790,10 +2788,10 @@ EXPORT_SYMBOL_GPL(uart_handle_cts_change);
|
||||
void uart_insert_char(struct uart_port *port, unsigned int status,
|
||||
unsigned int overrun, unsigned int ch, unsigned int flag)
|
||||
{
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
if ((status & port->ignore_status_mask & ~overrun) == 0)
|
||||
if (tty_insert_flip_char(tty, ch, flag) == 0)
|
||||
if (tty_insert_flip_char(tport, ch, flag) == 0)
|
||||
++port->icount.buf_overrun;
|
||||
|
||||
/*
|
||||
@@ -2801,7 +2799,7 @@ void uart_insert_char(struct uart_port *port, unsigned int status,
|
||||
* it doesn't affect the current character.
|
||||
*/
|
||||
if (status & ~port->ignore_status_mask & overrun)
|
||||
if (tty_insert_flip_char(tty, 0, TTY_OVERRUN) == 0)
|
||||
if (tty_insert_flip_char(tport, 0, TTY_OVERRUN) == 0)
|
||||
++port->icount.buf_overrun;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_insert_char);
|
||||
|
@@ -153,7 +153,6 @@ static void ks8695uart_disable_ms(struct uart_port *port)
|
||||
static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
unsigned int status, ch, lsr, flg, max_count = 256;
|
||||
|
||||
status = UART_GET_LSR(port); /* clears pending LSR interrupts */
|
||||
@@ -200,7 +199,7 @@ static irqreturn_t ks8695uart_rx_chars(int irq, void *dev_id)
|
||||
ignore_char:
|
||||
status = UART_GET_LSR(port);
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -277,7 +277,6 @@ static void serial_txx9_initialize(struct uart_port *port)
|
||||
static inline void
|
||||
receive_chars(struct uart_txx9_port *up, unsigned int *status)
|
||||
{
|
||||
struct tty_struct *tty = up->port.state->port.tty;
|
||||
unsigned char ch;
|
||||
unsigned int disr = *status;
|
||||
int max_count = 256;
|
||||
@@ -346,7 +345,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status)
|
||||
disr = sio_in(up, TXX9_SIDISR);
|
||||
} while (!(disr & TXX9_SIDISR_UVALID) && (max_count-- > 0));
|
||||
spin_unlock(&up->port.lock);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
spin_lock(&up->port.lock);
|
||||
*status = disr;
|
||||
}
|
||||
|
@@ -596,7 +596,7 @@ static void sci_transmit_chars(struct uart_port *port)
|
||||
static void sci_receive_chars(struct uart_port *port)
|
||||
{
|
||||
struct sci_port *sci_port = to_sci_port(port);
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
int i, count, copied = 0;
|
||||
unsigned short status;
|
||||
unsigned char flag;
|
||||
@@ -607,7 +607,7 @@ static void sci_receive_chars(struct uart_port *port)
|
||||
|
||||
while (1) {
|
||||
/* Don't copy more bytes than there is room for in the buffer */
|
||||
count = tty_buffer_request_room(tty, sci_rxfill(port));
|
||||
count = tty_buffer_request_room(tport, sci_rxfill(port));
|
||||
|
||||
/* If for any reason we can't copy more data, we're done! */
|
||||
if (count == 0)
|
||||
@@ -619,7 +619,7 @@ static void sci_receive_chars(struct uart_port *port)
|
||||
sci_port->break_flag)
|
||||
count = 0;
|
||||
else
|
||||
tty_insert_flip_char(tty, c, TTY_NORMAL);
|
||||
tty_insert_flip_char(tport, c, TTY_NORMAL);
|
||||
} else {
|
||||
for (i = 0; i < count; i++) {
|
||||
char c = serial_port_in(port, SCxRDR);
|
||||
@@ -661,7 +661,7 @@ static void sci_receive_chars(struct uart_port *port)
|
||||
} else
|
||||
flag = TTY_NORMAL;
|
||||
|
||||
tty_insert_flip_char(tty, c, flag);
|
||||
tty_insert_flip_char(tport, c, flag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,7 +674,7 @@ static void sci_receive_chars(struct uart_port *port)
|
||||
|
||||
if (copied) {
|
||||
/* Tell the rest of the system the news. New characters! */
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
} else {
|
||||
serial_port_in(port, SCxSR); /* dummy read */
|
||||
serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
|
||||
@@ -720,7 +720,7 @@ static int sci_handle_errors(struct uart_port *port)
|
||||
{
|
||||
int copied = 0;
|
||||
unsigned short status = serial_port_in(port, SCxSR);
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
|
||||
/*
|
||||
@@ -731,7 +731,7 @@ static int sci_handle_errors(struct uart_port *port)
|
||||
port->icount.overrun++;
|
||||
|
||||
/* overrun error */
|
||||
if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
|
||||
if (tty_insert_flip_char(tport, 0, TTY_OVERRUN))
|
||||
copied++;
|
||||
|
||||
dev_notice(port->dev, "overrun error");
|
||||
@@ -755,7 +755,7 @@ static int sci_handle_errors(struct uart_port *port)
|
||||
|
||||
dev_dbg(port->dev, "BREAK detected\n");
|
||||
|
||||
if (tty_insert_flip_char(tty, 0, TTY_BREAK))
|
||||
if (tty_insert_flip_char(tport, 0, TTY_BREAK))
|
||||
copied++;
|
||||
}
|
||||
|
||||
@@ -763,7 +763,7 @@ static int sci_handle_errors(struct uart_port *port)
|
||||
/* frame error */
|
||||
port->icount.frame++;
|
||||
|
||||
if (tty_insert_flip_char(tty, 0, TTY_FRAME))
|
||||
if (tty_insert_flip_char(tport, 0, TTY_FRAME))
|
||||
copied++;
|
||||
|
||||
dev_notice(port->dev, "frame error\n");
|
||||
@@ -774,21 +774,21 @@ static int sci_handle_errors(struct uart_port *port)
|
||||
/* parity error */
|
||||
port->icount.parity++;
|
||||
|
||||
if (tty_insert_flip_char(tty, 0, TTY_PARITY))
|
||||
if (tty_insert_flip_char(tport, 0, TTY_PARITY))
|
||||
copied++;
|
||||
|
||||
dev_notice(port->dev, "parity error");
|
||||
}
|
||||
|
||||
if (copied)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
return copied;
|
||||
}
|
||||
|
||||
static int sci_handle_fifo_overrun(struct uart_port *port)
|
||||
{
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
struct plat_sci_reg *reg;
|
||||
int copied = 0;
|
||||
@@ -802,8 +802,8 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
|
||||
|
||||
port->icount.overrun++;
|
||||
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
dev_notice(port->dev, "overrun error\n");
|
||||
copied++;
|
||||
@@ -816,7 +816,7 @@ static int sci_handle_breaks(struct uart_port *port)
|
||||
{
|
||||
int copied = 0;
|
||||
unsigned short status = serial_port_in(port, SCxSR);
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
struct sci_port *s = to_sci_port(port);
|
||||
|
||||
if (uart_handle_break(port))
|
||||
@@ -831,14 +831,14 @@ static int sci_handle_breaks(struct uart_port *port)
|
||||
port->icount.brk++;
|
||||
|
||||
/* Notify of BREAK */
|
||||
if (tty_insert_flip_char(tty, 0, TTY_BREAK))
|
||||
if (tty_insert_flip_char(tport, 0, TTY_BREAK))
|
||||
copied++;
|
||||
|
||||
dev_dbg(port->dev, "BREAK detected\n");
|
||||
}
|
||||
|
||||
if (copied)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
copied += sci_handle_fifo_overrun(port);
|
||||
|
||||
@@ -1259,13 +1259,13 @@ static void sci_dma_tx_complete(void *arg)
|
||||
}
|
||||
|
||||
/* Locking: called with port lock held */
|
||||
static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty,
|
||||
size_t count)
|
||||
static int sci_dma_rx_push(struct sci_port *s, size_t count)
|
||||
{
|
||||
struct uart_port *port = &s->port;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
int i, active, room;
|
||||
|
||||
room = tty_buffer_request_room(tty, count);
|
||||
room = tty_buffer_request_room(tport, count);
|
||||
|
||||
if (s->active_rx == s->cookie_rx[0]) {
|
||||
active = 0;
|
||||
@@ -1283,7 +1283,7 @@ static int sci_dma_rx_push(struct sci_port *s, struct tty_struct *tty,
|
||||
return room;
|
||||
|
||||
for (i = 0; i < room; i++)
|
||||
tty_insert_flip_char(tty, ((u8 *)sg_virt(&s->sg_rx[active]))[i],
|
||||
tty_insert_flip_char(tport, ((u8 *)sg_virt(&s->sg_rx[active]))[i],
|
||||
TTY_NORMAL);
|
||||
|
||||
port->icount.rx += room;
|
||||
@@ -1295,7 +1295,6 @@ static void sci_dma_rx_complete(void *arg)
|
||||
{
|
||||
struct sci_port *s = arg;
|
||||
struct uart_port *port = &s->port;
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
unsigned long flags;
|
||||
int count;
|
||||
|
||||
@@ -1303,14 +1302,14 @@ static void sci_dma_rx_complete(void *arg)
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
count = sci_dma_rx_push(s, tty, s->buf_len_rx);
|
||||
count = sci_dma_rx_push(s, s->buf_len_rx);
|
||||
|
||||
mod_timer(&s->rx_timer, jiffies + s->rx_timeout);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (count)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
|
||||
schedule_work(&s->work_rx);
|
||||
}
|
||||
@@ -1404,7 +1403,6 @@ static void work_fn_rx(struct work_struct *work)
|
||||
if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) !=
|
||||
DMA_SUCCESS) {
|
||||
/* Handle incomplete DMA receive */
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct dma_chan *chan = s->chan_rx;
|
||||
struct shdma_desc *sh_desc = container_of(desc,
|
||||
struct shdma_desc, async_tx);
|
||||
@@ -1416,11 +1414,11 @@ static void work_fn_rx(struct work_struct *work)
|
||||
sh_desc->partial, sh_desc->cookie);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
count = sci_dma_rx_push(s, tty, sh_desc->partial);
|
||||
count = sci_dma_rx_push(s, sh_desc->partial);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (count)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
|
||||
sci_submit_rx(s);
|
||||
|
||||
|
@@ -75,6 +75,20 @@ static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = {
|
||||
.line = 2,
|
||||
},
|
||||
},
|
||||
[3] = {
|
||||
.port = {
|
||||
.iotype = UPIO_MEM,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 3,
|
||||
},
|
||||
},
|
||||
[4] = {
|
||||
.port = {
|
||||
.iotype = UPIO_MEM,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 4,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port)
|
||||
@@ -192,11 +206,6 @@ static unsigned int
|
||||
sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
|
||||
{
|
||||
unsigned int ch, rx_count = 0;
|
||||
struct tty_struct *tty;
|
||||
|
||||
tty = tty_port_tty_get(&port->state->port);
|
||||
if (!tty)
|
||||
return -ENODEV;
|
||||
|
||||
while (!(rd_regl(port, SIRFUART_RX_FIFO_STATUS) &
|
||||
SIRFUART_FIFOEMPTY_MASK(port))) {
|
||||
@@ -210,8 +219,7 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count)
|
||||
}
|
||||
|
||||
port->icount.rx += rx_count;
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_kref_put(tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
|
||||
return rx_count;
|
||||
}
|
||||
@@ -245,6 +253,7 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
|
||||
struct uart_port *port = &sirfport->port;
|
||||
struct uart_state *state = port->state;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
spin_lock(&port->lock);
|
||||
intr_status = rd_regl(port, SIRFUART_INT_STATUS);
|
||||
wr_regl(port, SIRFUART_INT_STATUS, intr_status);
|
||||
intr_status &= rd_regl(port, SIRFUART_INT_EN);
|
||||
@@ -254,6 +263,7 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id)
|
||||
goto recv_char;
|
||||
uart_insert_char(port, intr_status,
|
||||
SIRFUART_RX_OFLOW, 0, TTY_BREAK);
|
||||
spin_unlock(&port->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
if (intr_status & SIRFUART_RX_OFLOW)
|
||||
@@ -286,6 +296,7 @@ recv_char:
|
||||
sirfsoc_uart_pio_rx_chars(port, SIRFSOC_UART_IO_RX_MAX_CNT);
|
||||
if (intr_status & SIRFUART_TX_INT_EN) {
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
spin_unlock(&port->lock);
|
||||
return IRQ_HANDLED;
|
||||
} else {
|
||||
sirfsoc_uart_pio_tx_chars(sirfport,
|
||||
@@ -296,6 +307,7 @@ recv_char:
|
||||
sirfsoc_uart_stop_tx(port);
|
||||
}
|
||||
}
|
||||
spin_unlock(&port->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -345,7 +357,6 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
|
||||
unsigned long ioclk_rate;
|
||||
unsigned long config_reg = 0;
|
||||
unsigned long baud_rate;
|
||||
unsigned long setted_baud;
|
||||
@@ -357,7 +368,6 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
|
||||
int threshold_div;
|
||||
int temp;
|
||||
|
||||
ioclk_rate = 150000000;
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
default:
|
||||
case CS8:
|
||||
@@ -413,14 +423,17 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
|
||||
sirfsoc_uart_disable_ms(port);
|
||||
}
|
||||
|
||||
/* common rate: fast calculation */
|
||||
for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
|
||||
if (baud_rate == baudrate_to_regv[ic].baud_rate)
|
||||
clk_div_reg = baudrate_to_regv[ic].reg_val;
|
||||
if (port->uartclk == 150000000) {
|
||||
/* common rate: fast calculation */
|
||||
for (ic = 0; ic < SIRF_BAUD_RATE_SUPPORT_NR; ic++)
|
||||
if (baud_rate == baudrate_to_regv[ic].baud_rate)
|
||||
clk_div_reg = baudrate_to_regv[ic].reg_val;
|
||||
}
|
||||
|
||||
setted_baud = baud_rate;
|
||||
/* arbitary rate setting */
|
||||
if (unlikely(clk_div_reg == 0))
|
||||
clk_div_reg = sirfsoc_calc_sample_div(baud_rate, ioclk_rate,
|
||||
clk_div_reg = sirfsoc_calc_sample_div(baud_rate, port->uartclk,
|
||||
&setted_baud);
|
||||
wr_regl(port, SIRFUART_DIVISOR, clk_div_reg);
|
||||
|
||||
@@ -679,6 +692,14 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
sirfport->clk = clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(sirfport->clk)) {
|
||||
ret = PTR_ERR(sirfport->clk);
|
||||
goto clk_err;
|
||||
}
|
||||
clk_prepare_enable(sirfport->clk);
|
||||
port->uartclk = clk_get_rate(sirfport->clk);
|
||||
|
||||
port->ops = &sirfsoc_uart_ops;
|
||||
spin_lock_init(&port->lock);
|
||||
|
||||
@@ -692,6 +713,9 @@ int sirfsoc_uart_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
port_err:
|
||||
clk_disable_unprepare(sirfport->clk);
|
||||
clk_put(sirfport->clk);
|
||||
clk_err:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
if (sirfport->hw_flow_ctrl)
|
||||
pinctrl_put(sirfport->p);
|
||||
@@ -706,6 +730,8 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
if (sirfport->hw_flow_ctrl)
|
||||
pinctrl_put(sirfport->p);
|
||||
clk_disable_unprepare(sirfport->clk);
|
||||
clk_put(sirfport->clk);
|
||||
uart_remove_one_port(&sirfsoc_uart_drv, port);
|
||||
return 0;
|
||||
}
|
||||
@@ -729,6 +755,7 @@ static int sirfsoc_uart_resume(struct platform_device *pdev)
|
||||
|
||||
static struct of_device_id sirfsoc_uart_ids[] = {
|
||||
{ .compatible = "sirf,prima2-uart", },
|
||||
{ .compatible = "sirf,marco-uart", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sirfsoc_serial_of_match);
|
||||
|
@@ -139,7 +139,7 @@
|
||||
#define SIRFSOC_UART_MINOR 0
|
||||
#define SIRFUART_PORT_NAME "sirfsoc-uart"
|
||||
#define SIRFUART_MAP_SIZE 0x200
|
||||
#define SIRFSOC_UART_NR 3
|
||||
#define SIRFSOC_UART_NR 5
|
||||
#define SIRFSOC_PORT_TYPE 0xa5
|
||||
|
||||
/* Baud Rate Calculation */
|
||||
@@ -163,6 +163,7 @@ struct sirfsoc_uart_port {
|
||||
|
||||
struct uart_port port;
|
||||
struct pinctrl *p;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
/* Hardware Flow Control */
|
||||
|
@@ -457,8 +457,8 @@ static int sn_debug_printf(const char *fmt, ...)
|
||||
static void
|
||||
sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
|
||||
{
|
||||
struct tty_port *tport = NULL;
|
||||
int ch;
|
||||
struct tty_struct *tty;
|
||||
|
||||
if (!port) {
|
||||
printk(KERN_ERR "sn_receive_chars - port NULL so can't receive\n");
|
||||
@@ -472,11 +472,7 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
|
||||
|
||||
if (port->sc_port.state) {
|
||||
/* The serial_core stuffs are initialized, use them */
|
||||
tty = port->sc_port.state->port.tty;
|
||||
}
|
||||
else {
|
||||
/* Not registered yet - can't pass to tty layer. */
|
||||
tty = NULL;
|
||||
tport = &port->sc_port.state->port;
|
||||
}
|
||||
|
||||
while (port->sc_ops->sal_input_pending()) {
|
||||
@@ -516,15 +512,15 @@ sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
|
||||
#endif /* CONFIG_MAGIC_SYSRQ */
|
||||
|
||||
/* record the character to pass up to the tty layer */
|
||||
if (tty) {
|
||||
if(tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0)
|
||||
if (tport) {
|
||||
if (tty_insert_flip_char(tport, ch, TTY_NORMAL) == 0)
|
||||
break;
|
||||
}
|
||||
port->sc_port.icount.rx++;
|
||||
}
|
||||
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (tport)
|
||||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -72,7 +72,7 @@ static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
|
||||
}
|
||||
}
|
||||
|
||||
static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
|
||||
static int receive_chars_getchar(struct uart_port *port)
|
||||
{
|
||||
int saw_console_brk = 0;
|
||||
int limit = 10000;
|
||||
@@ -99,7 +99,7 @@ static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
|
||||
uart_handle_dcd_change(port, 1);
|
||||
}
|
||||
|
||||
if (tty == NULL) {
|
||||
if (port->state == NULL) {
|
||||
uart_handle_sysrq_char(port, c);
|
||||
continue;
|
||||
}
|
||||
@@ -109,13 +109,13 @@ static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
|
||||
if (uart_handle_sysrq_char(port, c))
|
||||
continue;
|
||||
|
||||
tty_insert_flip_char(tty, c, TTY_NORMAL);
|
||||
tty_insert_flip_char(&port->state->port, c, TTY_NORMAL);
|
||||
}
|
||||
|
||||
return saw_console_brk;
|
||||
}
|
||||
|
||||
static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
|
||||
static int receive_chars_read(struct uart_port *port)
|
||||
{
|
||||
int saw_console_brk = 0;
|
||||
int limit = 10000;
|
||||
@@ -152,12 +152,13 @@ static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
|
||||
for (i = 0; i < bytes_read; i++)
|
||||
uart_handle_sysrq_char(port, con_read_page[i]);
|
||||
|
||||
if (tty == NULL)
|
||||
if (port->state == NULL)
|
||||
continue;
|
||||
|
||||
port->icount.rx += bytes_read;
|
||||
|
||||
tty_insert_flip_string(tty, con_read_page, bytes_read);
|
||||
tty_insert_flip_string(&port->state->port, con_read_page,
|
||||
bytes_read);
|
||||
}
|
||||
|
||||
return saw_console_brk;
|
||||
@@ -165,7 +166,7 @@ static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
|
||||
|
||||
struct sunhv_ops {
|
||||
void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
|
||||
int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
|
||||
int (*receive_chars)(struct uart_port *port);
|
||||
};
|
||||
|
||||
static struct sunhv_ops bychar_ops = {
|
||||
@@ -180,17 +181,17 @@ static struct sunhv_ops bywrite_ops = {
|
||||
|
||||
static struct sunhv_ops *sunhv_ops = &bychar_ops;
|
||||
|
||||
static struct tty_struct *receive_chars(struct uart_port *port)
|
||||
static struct tty_port *receive_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_struct *tty = NULL;
|
||||
struct tty_port *tport = NULL;
|
||||
|
||||
if (port->state != NULL) /* Unopened serial console */
|
||||
tty = port->state->port.tty;
|
||||
tport = &port->state->port;
|
||||
|
||||
if (sunhv_ops->receive_chars(port, tty))
|
||||
if (sunhv_ops->receive_chars(port))
|
||||
sun_do_break();
|
||||
|
||||
return tty;
|
||||
return tport;
|
||||
}
|
||||
|
||||
static void transmit_chars(struct uart_port *port)
|
||||
@@ -213,16 +214,16 @@ static void transmit_chars(struct uart_port *port)
|
||||
static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *tport;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
tty = receive_chars(port);
|
||||
tport = receive_chars(port);
|
||||
transmit_chars(port);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (tport)
|
||||
tty_flip_buffer_push(tport);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -107,11 +107,11 @@ static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up)
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
static struct tty_struct *
|
||||
static struct tty_port *
|
||||
receive_chars(struct uart_sunsab_port *up,
|
||||
union sab82532_irq_status *stat)
|
||||
{
|
||||
struct tty_struct *tty = NULL;
|
||||
struct tty_port *port = NULL;
|
||||
unsigned char buf[32];
|
||||
int saw_console_brk = 0;
|
||||
int free_fifo = 0;
|
||||
@@ -119,7 +119,7 @@ receive_chars(struct uart_sunsab_port *up,
|
||||
int i;
|
||||
|
||||
if (up->port.state != NULL) /* Unopened serial console */
|
||||
tty = up->port.state->port.tty;
|
||||
port = &up->port.state->port;
|
||||
|
||||
/* Read number of BYTES (Character + Status) available. */
|
||||
if (stat->sreg.isr0 & SAB82532_ISR0_RPF) {
|
||||
@@ -136,7 +136,7 @@ receive_chars(struct uart_sunsab_port *up,
|
||||
if (stat->sreg.isr0 & SAB82532_ISR0_TIME) {
|
||||
sunsab_cec_wait(up);
|
||||
writeb(SAB82532_CMDR_RFRD, &up->regs->w.cmdr);
|
||||
return tty;
|
||||
return port;
|
||||
}
|
||||
|
||||
if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
|
||||
@@ -160,11 +160,6 @@ receive_chars(struct uart_sunsab_port *up,
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned char ch = buf[i], flag;
|
||||
|
||||
if (tty == NULL) {
|
||||
uart_handle_sysrq_char(&up->port, ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
flag = TTY_NORMAL;
|
||||
up->port.icount.rx++;
|
||||
|
||||
@@ -213,15 +208,15 @@ receive_chars(struct uart_sunsab_port *up,
|
||||
|
||||
if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&
|
||||
(stat->sreg.isr1 & ((up->port.ignore_status_mask >> 8) & 0xff)) == 0)
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(port, ch, flag);
|
||||
if (stat->sreg.isr0 & SAB82532_ISR0_RFO)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||
}
|
||||
|
||||
if (saw_console_brk)
|
||||
sun_do_break();
|
||||
|
||||
return tty;
|
||||
return port;
|
||||
}
|
||||
|
||||
static void sunsab_stop_tx(struct uart_port *);
|
||||
@@ -304,7 +299,7 @@ static void check_status(struct uart_sunsab_port *up,
|
||||
static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_sunsab_port *up = dev_id;
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port = NULL;
|
||||
union sab82532_irq_status status;
|
||||
unsigned long flags;
|
||||
unsigned char gis;
|
||||
@@ -318,12 +313,11 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
|
||||
if (gis & 2)
|
||||
status.sreg.isr1 = readb(&up->regs->r.isr1);
|
||||
|
||||
tty = NULL;
|
||||
if (status.stat) {
|
||||
if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
|
||||
SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
|
||||
(status.sreg.isr1 & SAB82532_ISR1_BRK))
|
||||
tty = receive_chars(up, &status);
|
||||
port = receive_chars(up, &status);
|
||||
if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
|
||||
(status.sreg.isr1 & SAB82532_ISR1_CSC))
|
||||
check_status(up, &status);
|
||||
@@ -333,8 +327,8 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
|
||||
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (port)
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
@@ -315,10 +315,10 @@ static void sunsu_enable_ms(struct uart_port *port)
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
}
|
||||
|
||||
static struct tty_struct *
|
||||
static void
|
||||
receive_chars(struct uart_sunsu_port *up, unsigned char *status)
|
||||
{
|
||||
struct tty_struct *tty = up->port.state->port.tty;
|
||||
struct tty_port *port = &up->port.state->port;
|
||||
unsigned char ch, flag;
|
||||
int max_count = 256;
|
||||
int saw_console_brk = 0;
|
||||
@@ -376,22 +376,20 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
|
||||
if (uart_handle_sysrq_char(&up->port, ch))
|
||||
goto ignore_char;
|
||||
if ((*status & up->port.ignore_status_mask) == 0)
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(port, ch, flag);
|
||||
if (*status & UART_LSR_OE)
|
||||
/*
|
||||
* Overrun is special, since it's reported
|
||||
* immediately, and doesn't affect the current
|
||||
* character.
|
||||
*/
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||
ignore_char:
|
||||
*status = serial_inp(up, UART_LSR);
|
||||
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
|
||||
|
||||
if (saw_console_brk)
|
||||
sun_do_break();
|
||||
|
||||
return tty;
|
||||
}
|
||||
|
||||
static void transmit_chars(struct uart_sunsu_port *up)
|
||||
@@ -460,20 +458,16 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
||||
do {
|
||||
struct tty_struct *tty;
|
||||
|
||||
status = serial_inp(up, UART_LSR);
|
||||
tty = NULL;
|
||||
if (status & UART_LSR_DR)
|
||||
tty = receive_chars(up, &status);
|
||||
receive_chars(up, &status);
|
||||
check_modem_status(up);
|
||||
if (status & UART_LSR_THRE)
|
||||
transmit_chars(up);
|
||||
|
||||
spin_unlock_irqrestore(&up->port.lock, flags);
|
||||
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
tty_flip_buffer_push(&up->port.state->port);
|
||||
|
||||
spin_lock_irqsave(&up->port.lock, flags);
|
||||
|
||||
|
@@ -323,17 +323,15 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
|
||||
}
|
||||
}
|
||||
|
||||
static struct tty_struct *
|
||||
static struct tty_port *
|
||||
sunzilog_receive_chars(struct uart_sunzilog_port *up,
|
||||
struct zilog_channel __iomem *channel)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port = NULL;
|
||||
unsigned char ch, r1, flag;
|
||||
|
||||
tty = NULL;
|
||||
if (up->port.state != NULL && /* Unopened serial console */
|
||||
up->port.state->port.tty != NULL) /* Keyboard || mouse */
|
||||
tty = up->port.state->port.tty;
|
||||
if (up->port.state != NULL) /* Unopened serial console */
|
||||
port = &up->port.state->port;
|
||||
|
||||
for (;;) {
|
||||
|
||||
@@ -366,11 +364,6 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tty == NULL) {
|
||||
uart_handle_sysrq_char(&up->port, ch);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* A real serial line, record the character and status. */
|
||||
flag = TTY_NORMAL;
|
||||
up->port.icount.rx++;
|
||||
@@ -400,13 +393,13 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
|
||||
|
||||
if (up->port.ignore_status_mask == 0xff ||
|
||||
(r1 & up->port.ignore_status_mask) == 0) {
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(port, ch, flag);
|
||||
}
|
||||
if (r1 & Rx_OVR)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||
}
|
||||
|
||||
return tty;
|
||||
return port;
|
||||
}
|
||||
|
||||
static void sunzilog_status_handle(struct uart_sunzilog_port *up,
|
||||
@@ -539,21 +532,21 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
|
||||
while (up) {
|
||||
struct zilog_channel __iomem *channel
|
||||
= ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port;
|
||||
unsigned char r3;
|
||||
|
||||
spin_lock(&up->port.lock);
|
||||
r3 = read_zsreg(channel, R3);
|
||||
|
||||
/* Channel A */
|
||||
tty = NULL;
|
||||
port = NULL;
|
||||
if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
|
||||
writeb(RES_H_IUS, &channel->control);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
if (r3 & CHARxIP)
|
||||
tty = sunzilog_receive_chars(up, channel);
|
||||
port = sunzilog_receive_chars(up, channel);
|
||||
if (r3 & CHAEXT)
|
||||
sunzilog_status_handle(up, channel);
|
||||
if (r3 & CHATxIP)
|
||||
@@ -561,22 +554,22 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
|
||||
}
|
||||
spin_unlock(&up->port.lock);
|
||||
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (port)
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
/* Channel B */
|
||||
up = up->next;
|
||||
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
|
||||
|
||||
spin_lock(&up->port.lock);
|
||||
tty = NULL;
|
||||
port = NULL;
|
||||
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
|
||||
writeb(RES_H_IUS, &channel->control);
|
||||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
if (r3 & CHBRxIP)
|
||||
tty = sunzilog_receive_chars(up, channel);
|
||||
port = sunzilog_receive_chars(up, channel);
|
||||
if (r3 & CHBEXT)
|
||||
sunzilog_status_handle(up, channel);
|
||||
if (r3 & CHBTxIP)
|
||||
@@ -584,8 +577,8 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
|
||||
}
|
||||
spin_unlock(&up->port.lock);
|
||||
|
||||
if (tty)
|
||||
tty_flip_buffer_push(tty);
|
||||
if (port)
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
up = up->next;
|
||||
}
|
||||
|
@@ -91,16 +91,16 @@ static void timbuart_flush_buffer(struct uart_port *port)
|
||||
|
||||
static void timbuart_rx_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
|
||||
while (ioread32(port->membase + TIMBUART_ISR) & RXDP) {
|
||||
u8 ch = ioread8(port->membase + TIMBUART_RXFIFO);
|
||||
port->icount.rx++;
|
||||
tty_insert_flip_char(tty, ch, TTY_NORMAL);
|
||||
tty_insert_flip_char(tport, ch, TTY_NORMAL);
|
||||
}
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
tty_flip_buffer_push(port->state->port.tty);
|
||||
tty_flip_buffer_push(tport);
|
||||
spin_lock(&port->lock);
|
||||
|
||||
dev_dbg(port->dev, "%s - total read %d bytes\n",
|
||||
|
@@ -19,7 +19,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
@@ -34,7 +34,7 @@
|
||||
* Register definitions
|
||||
*
|
||||
* For register details see datasheet:
|
||||
* http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf
|
||||
* http://www.xilinx.com/support/documentation/ip_documentation/opb_uartlite.pdf
|
||||
*/
|
||||
|
||||
#define ULITE_RX 0x00
|
||||
@@ -57,6 +57,54 @@
|
||||
#define ULITE_CONTROL_RST_RX 0x02
|
||||
#define ULITE_CONTROL_IE 0x10
|
||||
|
||||
struct uartlite_reg_ops {
|
||||
u32 (*in)(void __iomem *addr);
|
||||
void (*out)(u32 val, void __iomem *addr);
|
||||
};
|
||||
|
||||
static u32 uartlite_inbe32(void __iomem *addr)
|
||||
{
|
||||
return ioread32be(addr);
|
||||
}
|
||||
|
||||
static void uartlite_outbe32(u32 val, void __iomem *addr)
|
||||
{
|
||||
iowrite32be(val, addr);
|
||||
}
|
||||
|
||||
static struct uartlite_reg_ops uartlite_be = {
|
||||
.in = uartlite_inbe32,
|
||||
.out = uartlite_outbe32,
|
||||
};
|
||||
|
||||
static u32 uartlite_inle32(void __iomem *addr)
|
||||
{
|
||||
return ioread32(addr);
|
||||
}
|
||||
|
||||
static void uartlite_outle32(u32 val, void __iomem *addr)
|
||||
{
|
||||
iowrite32(val, addr);
|
||||
}
|
||||
|
||||
static struct uartlite_reg_ops uartlite_le = {
|
||||
.in = uartlite_inle32,
|
||||
.out = uartlite_outle32,
|
||||
};
|
||||
|
||||
static inline u32 uart_in32(u32 offset, struct uart_port *port)
|
||||
{
|
||||
struct uartlite_reg_ops *reg_ops = port->private_data;
|
||||
|
||||
return reg_ops->in(port->membase + offset);
|
||||
}
|
||||
|
||||
static inline void uart_out32(u32 val, u32 offset, struct uart_port *port)
|
||||
{
|
||||
struct uartlite_reg_ops *reg_ops = port->private_data;
|
||||
|
||||
reg_ops->out(val, port->membase + offset);
|
||||
}
|
||||
|
||||
static struct uart_port ulite_ports[ULITE_NR_UARTS];
|
||||
|
||||
@@ -66,7 +114,7 @@ static struct uart_port ulite_ports[ULITE_NR_UARTS];
|
||||
|
||||
static int ulite_receive(struct uart_port *port, int stat)
|
||||
{
|
||||
struct tty_struct *tty = port->state->port.tty;
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char ch = 0;
|
||||
char flag = TTY_NORMAL;
|
||||
|
||||
@@ -77,7 +125,7 @@ static int ulite_receive(struct uart_port *port, int stat)
|
||||
/* stats */
|
||||
if (stat & ULITE_STATUS_RXVALID) {
|
||||
port->icount.rx++;
|
||||
ch = ioread32be(port->membase + ULITE_RX);
|
||||
ch = uart_in32(ULITE_RX, port);
|
||||
|
||||
if (stat & ULITE_STATUS_PARITY)
|
||||
port->icount.parity++;
|
||||
@@ -103,13 +151,13 @@ static int ulite_receive(struct uart_port *port, int stat)
|
||||
stat &= ~port->ignore_status_mask;
|
||||
|
||||
if (stat & ULITE_STATUS_RXVALID)
|
||||
tty_insert_flip_char(tty, ch, flag);
|
||||
tty_insert_flip_char(tport, ch, flag);
|
||||
|
||||
if (stat & ULITE_STATUS_FRAME)
|
||||
tty_insert_flip_char(tty, 0, TTY_FRAME);
|
||||
tty_insert_flip_char(tport, 0, TTY_FRAME);
|
||||
|
||||
if (stat & ULITE_STATUS_OVERRUN)
|
||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -122,7 +170,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
|
||||
return 0;
|
||||
|
||||
if (port->x_char) {
|
||||
iowrite32be(port->x_char, port->membase + ULITE_TX);
|
||||
uart_out32(port->x_char, ULITE_TX, port);
|
||||
port->x_char = 0;
|
||||
port->icount.tx++;
|
||||
return 1;
|
||||
@@ -131,7 +179,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
return 0;
|
||||
|
||||
iowrite32be(xmit->buf[xmit->tail], port->membase + ULITE_TX);
|
||||
uart_out32(xmit->buf[xmit->tail], ULITE_TX, port);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
|
||||
port->icount.tx++;
|
||||
|
||||
@@ -148,7 +196,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id)
|
||||
int busy, n = 0;
|
||||
|
||||
do {
|
||||
int stat = ioread32be(port->membase + ULITE_STATUS);
|
||||
int stat = uart_in32(ULITE_STATUS, port);
|
||||
busy = ulite_receive(port, stat);
|
||||
busy |= ulite_transmit(port, stat);
|
||||
n++;
|
||||
@@ -156,7 +204,7 @@ static irqreturn_t ulite_isr(int irq, void *dev_id)
|
||||
|
||||
/* work done? */
|
||||
if (n > 1) {
|
||||
tty_flip_buffer_push(port->state->port.tty);
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
return IRQ_HANDLED;
|
||||
} else {
|
||||
return IRQ_NONE;
|
||||
@@ -169,7 +217,7 @@ static unsigned int ulite_tx_empty(struct uart_port *port)
|
||||
unsigned int ret;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
ret = ioread32be(port->membase + ULITE_STATUS);
|
||||
ret = uart_in32(ULITE_STATUS, port);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return ret & ULITE_STATUS_TXEMPTY ? TIOCSER_TEMT : 0;
|
||||
@@ -192,7 +240,7 @@ static void ulite_stop_tx(struct uart_port *port)
|
||||
|
||||
static void ulite_start_tx(struct uart_port *port)
|
||||
{
|
||||
ulite_transmit(port, ioread32be(port->membase + ULITE_STATUS));
|
||||
ulite_transmit(port, uart_in32(ULITE_STATUS, port));
|
||||
}
|
||||
|
||||
static void ulite_stop_rx(struct uart_port *port)
|
||||
@@ -220,17 +268,17 @@ static int ulite_startup(struct uart_port *port)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iowrite32be(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
|
||||
port->membase + ULITE_CONTROL);
|
||||
iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
|
||||
uart_out32(ULITE_CONTROL_RST_RX | ULITE_CONTROL_RST_TX,
|
||||
ULITE_CONTROL, port);
|
||||
uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ulite_shutdown(struct uart_port *port)
|
||||
{
|
||||
iowrite32be(0, port->membase + ULITE_CONTROL);
|
||||
ioread32be(port->membase + ULITE_CONTROL); /* dummy */
|
||||
uart_out32(0, ULITE_CONTROL, port);
|
||||
uart_in32(ULITE_CONTROL, port); /* dummy */
|
||||
free_irq(port->irq, port);
|
||||
}
|
||||
|
||||
@@ -281,6 +329,8 @@ static void ulite_release_port(struct uart_port *port)
|
||||
|
||||
static int ulite_request_port(struct uart_port *port)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_debug("ulite console: port=%p; port->mapbase=%llx\n",
|
||||
port, (unsigned long long) port->mapbase);
|
||||
|
||||
@@ -296,6 +346,14 @@ static int ulite_request_port(struct uart_port *port)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
port->private_data = &uartlite_be;
|
||||
ret = uart_in32(ULITE_CONTROL, port);
|
||||
uart_out32(ULITE_CONTROL_RST_TX, ULITE_CONTROL, port);
|
||||
ret = uart_in32(ULITE_STATUS, port);
|
||||
/* Endianess detection */
|
||||
if ((ret & ULITE_STATUS_TXEMPTY) != ULITE_STATUS_TXEMPTY)
|
||||
port->private_data = &uartlite_le;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -314,20 +372,19 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
static int ulite_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
if (!(ioread32be(port->membase + ULITE_STATUS)
|
||||
& ULITE_STATUS_RXVALID))
|
||||
if (!(uart_in32(ULITE_STATUS, port) & ULITE_STATUS_RXVALID))
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return ioread32be(port->membase + ULITE_RX);
|
||||
return uart_in32(ULITE_RX, port);
|
||||
}
|
||||
|
||||
static void ulite_put_poll_char(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
while (ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL)
|
||||
while (uart_in32(ULITE_STATUS, port) & ULITE_STATUS_TXFULL)
|
||||
cpu_relax();
|
||||
|
||||
/* write char to device */
|
||||
iowrite32be(ch, port->membase + ULITE_TX);
|
||||
uart_out32(ch, ULITE_TX, port);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -366,7 +423,7 @@ static void ulite_console_wait_tx(struct uart_port *port)
|
||||
|
||||
/* Spin waiting for TX fifo to have space available */
|
||||
for (i = 0; i < 100000; i++) {
|
||||
val = ioread32be(port->membase + ULITE_STATUS);
|
||||
val = uart_in32(ULITE_STATUS, port);
|
||||
if ((val & ULITE_STATUS_TXFULL) == 0)
|
||||
break;
|
||||
cpu_relax();
|
||||
@@ -376,7 +433,7 @@ static void ulite_console_wait_tx(struct uart_port *port)
|
||||
static void ulite_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
ulite_console_wait_tx(port);
|
||||
iowrite32be(ch, port->membase + ULITE_TX);
|
||||
uart_out32(ch, ULITE_TX, port);
|
||||
}
|
||||
|
||||
static void ulite_console_write(struct console *co, const char *s,
|
||||
@@ -393,8 +450,8 @@ static void ulite_console_write(struct console *co, const char *s,
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* save and disable interrupt */
|
||||
ier = ioread32be(port->membase + ULITE_STATUS) & ULITE_STATUS_IE;
|
||||
iowrite32be(0, port->membase + ULITE_CONTROL);
|
||||
ier = uart_in32(ULITE_STATUS, port) & ULITE_STATUS_IE;
|
||||
uart_out32(0, ULITE_CONTROL, port);
|
||||
|
||||
uart_console_write(port, s, count, ulite_console_putchar);
|
||||
|
||||
@@ -402,7 +459,7 @@ static void ulite_console_write(struct console *co, const char *s,
|
||||
|
||||
/* restore interrupt state */
|
||||
if (ier)
|
||||
iowrite32be(ULITE_CONTROL_IE, port->membase + ULITE_CONTROL);
|
||||
uart_out32(ULITE_CONTROL_IE, ULITE_CONTROL, port);
|
||||
|
||||
if (locked)
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
@@ -615,7 +672,7 @@ static struct platform_driver ulite_platform_driver = {
|
||||
* Module setup/teardown
|
||||
*/
|
||||
|
||||
int __init ulite_init(void)
|
||||
static int __init ulite_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -634,11 +691,11 @@ int __init ulite_init(void)
|
||||
err_plat:
|
||||
uart_unregister_driver(&ulite_uart_driver);
|
||||
err_uart:
|
||||
printk(KERN_ERR "registering uartlite driver failed: err=%i", ret);
|
||||
pr_err("registering uartlite driver failed: err=%i", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __exit ulite_exit(void)
|
||||
static void __exit ulite_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ulite_platform_driver);
|
||||
uart_unregister_driver(&ulite_uart_driver);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user