mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge branch 'for-next' of git://github.com/rydberg/linux into next
Pull in changes from Henrik: "a trivial MT documentation fix".
This commit is contained in:
commit
31881d74b6
10393 changed files with 590297 additions and 325040 deletions
|
|
@ -1798,19 +1798,7 @@ static struct platform_driver amiga_serial_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init amiga_serial_init(void)
|
||||
{
|
||||
return platform_driver_probe(&amiga_serial_driver, amiga_serial_probe);
|
||||
}
|
||||
|
||||
module_init(amiga_serial_init);
|
||||
|
||||
static void __exit amiga_serial_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&amiga_serial_driver);
|
||||
}
|
||||
|
||||
module_exit(amiga_serial_exit);
|
||||
module_platform_driver_probe(amiga_serial_driver, amiga_serial_probe);
|
||||
|
||||
|
||||
#if defined(CONFIG_SERIAL_CONSOLE) && !defined(MODULE)
|
||||
|
|
|
|||
|
|
@ -1124,14 +1124,8 @@ 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 {
|
||||
struct tty_struct *tty;
|
||||
tty = tty_port_tty_get(&info->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
else
|
||||
tty_port_tty_hangup(&info->port, false);
|
||||
}
|
||||
break;
|
||||
case C_CM_MCTS:
|
||||
|
|
|
|||
|
|
@ -472,13 +472,9 @@ static void ehv_bc_tx_dequeue(struct ehv_bc_data *bc)
|
|||
static irqreturn_t ehv_bc_tty_tx_isr(int irq, void *data)
|
||||
{
|
||||
struct ehv_bc_data *bc = data;
|
||||
struct tty_struct *ttys = tty_port_tty_get(&bc->port);
|
||||
|
||||
ehv_bc_tx_dequeue(bc);
|
||||
if (ttys) {
|
||||
tty_wakeup(ttys);
|
||||
tty_kref_put(ttys);
|
||||
}
|
||||
tty_port_tty_wakeup(&bc->port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
|
@ -863,6 +859,7 @@ error:
|
|||
*/
|
||||
static void __exit ehv_bc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ehv_bc_tty_driver);
|
||||
tty_unregister_driver(ehv_bc_driver);
|
||||
put_tty_driver(ehv_bc_driver);
|
||||
kfree(bcs);
|
||||
|
|
|
|||
|
|
@ -861,7 +861,6 @@ static void hvsi_write_worker(struct work_struct *work)
|
|||
{
|
||||
struct hvsi_struct *hp =
|
||||
container_of(work, struct hvsi_struct, writer.work);
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
#ifdef DEBUG
|
||||
static long start_j = 0;
|
||||
|
|
@ -895,11 +894,7 @@ static void hvsi_write_worker(struct work_struct *work)
|
|||
start_j = 0;
|
||||
#endif /* DEBUG */
|
||||
wake_up_all(&hp->emptyq);
|
||||
tty = tty_port_tty_get(&hp->port);
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_wakeup(&hp->port);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -1732,8 +1732,7 @@ void ipwireless_hardware_free(struct ipw_hardware *hw)
|
|||
flush_work(&hw->work_rx);
|
||||
|
||||
for (i = 0; i < NL_NUM_OF_ADDRESSES; i++)
|
||||
if (hw->packet_assembler[i] != NULL)
|
||||
kfree(hw->packet_assembler[i]);
|
||||
kfree(hw->packet_assembler[i]);
|
||||
|
||||
for (i = 0; i < NL_NUM_OF_PRIORITIES; i++)
|
||||
list_for_each_entry_safe(tp, tq, &hw->tx_queue[i], queue) {
|
||||
|
|
|
|||
|
|
@ -913,16 +913,12 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
|
|||
|
||||
/* pci hot-un-plug support */
|
||||
for (a = 0; a < brd->numPorts; a++)
|
||||
if (brd->ports[a].port.flags & ASYNC_INITIALIZED) {
|
||||
struct tty_struct *tty = tty_port_tty_get(
|
||||
&brd->ports[a].port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
if (brd->ports[a].port.flags & ASYNC_INITIALIZED)
|
||||
tty_port_tty_hangup(&brd->ports[a].port, false);
|
||||
|
||||
for (a = 0; a < MAX_PORTS_PER_BOARD; a++)
|
||||
tty_port_destroy(&brd->ports[a].port);
|
||||
|
||||
while (1) {
|
||||
opened = 0;
|
||||
for (a = 0; a < brd->numPorts; a++)
|
||||
|
|
@ -1365,7 +1361,6 @@ static void moxa_hangup(struct tty_struct *tty)
|
|||
|
||||
static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
dcd = !!dcd;
|
||||
|
||||
|
|
@ -1373,10 +1368,8 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
|
|||
if (dcd != p->DCDState) {
|
||||
p->DCDState = dcd;
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
tty = tty_port_tty_get(&p->port);
|
||||
if (tty && !C_CLOCAL(tty) && !dcd)
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
if (!dcd)
|
||||
tty_port_tty_hangup(&p->port, true);
|
||||
}
|
||||
else
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
|
|
|
|||
|
|
@ -1084,6 +1084,10 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
|
|||
mutex_lock(&port->mutex);
|
||||
mxser_close_port(port);
|
||||
mxser_flush_buffer(tty);
|
||||
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
if (C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(port);
|
||||
}
|
||||
mxser_shutdown_port(port);
|
||||
clear_bit(ASYNCB_INITIALIZED, &port->flags);
|
||||
mutex_unlock(&port->mutex);
|
||||
|
|
@ -1614,8 +1618,12 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
|
|||
if (ip->type == PORT_16550A)
|
||||
me->fifo[p] = 1;
|
||||
|
||||
opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
|
||||
opmode &= OP_MODE_MASK;
|
||||
if (ip->board->chip_flag == MOXA_MUST_MU860_HWID) {
|
||||
opmode = inb(ip->opmode_ioaddr)>>((p % 4) * 2);
|
||||
opmode &= OP_MODE_MASK;
|
||||
} else {
|
||||
opmode = RS232_MODE;
|
||||
}
|
||||
me->iftype[p] = opmode;
|
||||
mutex_unlock(&port->mutex);
|
||||
}
|
||||
|
|
@ -1672,6 +1680,9 @@ static int mxser_ioctl(struct tty_struct *tty,
|
|||
int shiftbit;
|
||||
unsigned char val, mask;
|
||||
|
||||
if (info->board->chip_flag != MOXA_MUST_MU860_HWID)
|
||||
return -EFAULT;
|
||||
|
||||
p = tty->index % 4;
|
||||
if (cmd == MOXA_SET_OP_MODE) {
|
||||
if (get_user(opmode, (int __user *) argp))
|
||||
|
|
@ -2643,9 +2654,9 @@ static int mxser_probe(struct pci_dev *pdev,
|
|||
mxvar_sdriver, brd->idx + i, &pdev->dev);
|
||||
if (IS_ERR(tty_dev)) {
|
||||
retval = PTR_ERR(tty_dev);
|
||||
for (i--; i >= 0; i--)
|
||||
for (; i > 0; i--)
|
||||
tty_unregister_device(mxvar_sdriver,
|
||||
brd->idx + i);
|
||||
brd->idx + i - 1);
|
||||
goto err_relbrd;
|
||||
}
|
||||
}
|
||||
|
|
@ -2751,9 +2762,9 @@ static int __init mxser_module_init(void)
|
|||
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--)
|
||||
for (; i > 0; i--)
|
||||
tty_unregister_device(mxvar_sdriver,
|
||||
brd->idx + i);
|
||||
brd->idx + i - 1);
|
||||
for (i = 0; i < brd->info->nports; i++)
|
||||
tty_port_destroy(&brd->ports[i].port);
|
||||
free_irq(brd->irq, brd);
|
||||
|
|
|
|||
|
|
@ -1418,11 +1418,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
|
|||
pr_debug("DLCI %d goes closed.\n", dlci->addr);
|
||||
dlci->state = DLCI_CLOSED;
|
||||
if (dlci->addr != 0) {
|
||||
struct tty_struct *tty = tty_port_tty_get(&dlci->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_hangup(&dlci->port, false);
|
||||
kfifo_reset(dlci->fifo);
|
||||
} else
|
||||
dlci->gsm->dead = 1;
|
||||
|
|
@ -2968,6 +2964,10 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
|
|||
if (tty_port_close_start(&dlci->port, tty, filp) == 0)
|
||||
goto out;
|
||||
gsm_dlci_begin_close(dlci);
|
||||
if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) {
|
||||
if (C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(&dlci->port);
|
||||
}
|
||||
tty_port_close_end(&dlci->port, tty);
|
||||
tty_port_tty_set(&dlci->port, NULL);
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -153,6 +153,12 @@ static void n_tty_set_room(struct tty_struct *tty)
|
|||
if (left && !old_left) {
|
||||
WARN_RATELIMIT(tty->port->itty == NULL,
|
||||
"scheduling with invalid itty\n");
|
||||
/* see if ldisc has been killed - if so, this means that
|
||||
* even though the ldisc has been halted and ->buf.work
|
||||
* cancelled, ->buf.work is about to be rescheduled
|
||||
*/
|
||||
WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
|
||||
"scheduling buffer work for halted ldisc\n");
|
||||
schedule_work(&tty->port->buf.work);
|
||||
}
|
||||
}
|
||||
|
|
@ -188,35 +194,18 @@ static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
|
|||
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* check_unthrottle - allow new receive data
|
||||
* @tty; tty device
|
||||
*
|
||||
* Check whether to call the driver unthrottle functions
|
||||
*
|
||||
* Can sleep, may be called under the atomic_read_lock mutex but
|
||||
* this is not guaranteed.
|
||||
*/
|
||||
static void check_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
if (tty->count)
|
||||
tty_unthrottle(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset_buffer_flags - reset buffer state
|
||||
* @tty: terminal to reset
|
||||
*
|
||||
* Reset the read buffer counters, clear the flags,
|
||||
* and make sure the driver is unthrottled. Called
|
||||
* from n_tty_open() and n_tty_flush_buffer().
|
||||
* Reset the read buffer counters and clear the flags.
|
||||
* Called from n_tty_open() and n_tty_flush_buffer().
|
||||
*
|
||||
* Locking: tty_read_lock for read fields.
|
||||
*/
|
||||
|
||||
static void reset_buffer_flags(struct tty_struct *tty)
|
||||
static void reset_buffer_flags(struct n_tty_data *ldata)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&ldata->read_lock, flags);
|
||||
|
|
@ -229,29 +218,11 @@ static void reset_buffer_flags(struct tty_struct *tty)
|
|||
|
||||
ldata->canon_head = ldata->canon_data = ldata->erasing = 0;
|
||||
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
|
||||
n_tty_set_room(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* n_tty_flush_buffer - clean input queue
|
||||
* @tty: terminal device
|
||||
*
|
||||
* Flush the input buffer. Called when the line discipline is
|
||||
* being closed, when the tty layer wants the buffer flushed (eg
|
||||
* at hangup) or when the N_TTY line discipline internally has to
|
||||
* clean the pending queue (for example some signals).
|
||||
*
|
||||
* Locking: ctrl_lock, read_lock.
|
||||
*/
|
||||
|
||||
static void n_tty_flush_buffer(struct tty_struct *tty)
|
||||
static void n_tty_packet_mode_flush(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
/* clear everything and unthrottle the driver */
|
||||
reset_buffer_flags(tty);
|
||||
|
||||
if (!tty->link)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
if (tty->link->packet) {
|
||||
|
|
@ -261,6 +232,26 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
|
|||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* n_tty_flush_buffer - clean input queue
|
||||
* @tty: terminal device
|
||||
*
|
||||
* Flush the input buffer. Called when the tty layer wants the
|
||||
* buffer flushed (eg at hangup) or when the N_TTY line discipline
|
||||
* internally has to clean the pending queue (for example some signals).
|
||||
*
|
||||
* Locking: ctrl_lock, read_lock.
|
||||
*/
|
||||
|
||||
static void n_tty_flush_buffer(struct tty_struct *tty)
|
||||
{
|
||||
reset_buffer_flags(tty->disc_data);
|
||||
n_tty_set_room(tty);
|
||||
|
||||
if (tty->link)
|
||||
n_tty_packet_mode_flush(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* n_tty_chars_in_buffer - report available bytes
|
||||
* @tty: tty device
|
||||
|
|
@ -1032,23 +1023,19 @@ static void eraser(unsigned char c, struct tty_struct *tty)
|
|||
* isig - handle the ISIG optio
|
||||
* @sig: signal
|
||||
* @tty: terminal
|
||||
* @flush: force flush
|
||||
*
|
||||
* Called when a signal is being sent due to terminal input. This
|
||||
* may caus terminal flushing to take place according to the termios
|
||||
* settings and character used. Called from the driver receive_buf
|
||||
* path so serialized.
|
||||
* Called when a signal is being sent due to terminal input.
|
||||
* Called from the driver receive_buf path so serialized.
|
||||
*
|
||||
* Locking: ctrl_lock, read_lock (both via flush buffer)
|
||||
* Locking: ctrl_lock
|
||||
*/
|
||||
|
||||
static inline void isig(int sig, struct tty_struct *tty, int flush)
|
||||
static inline void isig(int sig, struct tty_struct *tty)
|
||||
{
|
||||
if (tty->pgrp)
|
||||
kill_pgrp(tty->pgrp, sig, 1);
|
||||
if (flush || !L_NOFLSH(tty)) {
|
||||
n_tty_flush_buffer(tty);
|
||||
tty_driver_flush_buffer(tty);
|
||||
struct pid *tty_pgrp = tty_get_pgrp(tty);
|
||||
if (tty_pgrp) {
|
||||
kill_pgrp(tty_pgrp, sig, 1);
|
||||
put_pid(tty_pgrp);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1069,7 +1056,11 @@ static inline void n_tty_receive_break(struct tty_struct *tty)
|
|||
if (I_IGNBRK(tty))
|
||||
return;
|
||||
if (I_BRKINT(tty)) {
|
||||
isig(SIGINT, tty, 1);
|
||||
isig(SIGINT, tty);
|
||||
if (!L_NOFLSH(tty)) {
|
||||
n_tty_flush_buffer(tty);
|
||||
tty_driver_flush_buffer(tty);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (I_PARMRK(tty)) {
|
||||
|
|
@ -1236,11 +1227,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
|
|||
signal = SIGTSTP;
|
||||
if (c == SUSP_CHAR(tty)) {
|
||||
send_signal:
|
||||
/*
|
||||
* Note that we do not use isig() here because we want
|
||||
* the order to be:
|
||||
* 1) flush, 2) echo, 3) signal
|
||||
*/
|
||||
if (!L_NOFLSH(tty)) {
|
||||
n_tty_flush_buffer(tty);
|
||||
tty_driver_flush_buffer(tty);
|
||||
|
|
@ -1251,8 +1237,7 @@ send_signal:
|
|||
echo_char(c, tty);
|
||||
process_echoes(tty);
|
||||
}
|
||||
if (tty->pgrp)
|
||||
kill_pgrp(tty->pgrp, signal, 1);
|
||||
isig(signal, tty);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1483,14 +1468,14 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
|||
* mode. We don't want to throttle the driver if we're in
|
||||
* canonical mode and don't have a newline yet!
|
||||
*/
|
||||
if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
|
||||
tty_throttle(tty);
|
||||
|
||||
/* FIXME: there is a tiny race here if the receive room check runs
|
||||
before the other work executes and empties the buffer (upping
|
||||
the receiving room and unthrottling. We then throttle and get
|
||||
stuck. This has been observed and traced down by Vincent Pillet/
|
||||
We need to address this when we sort out out the rx path locking */
|
||||
while (1) {
|
||||
tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
|
||||
if (tty->receive_room >= TTY_THRESHOLD_THROTTLE)
|
||||
break;
|
||||
if (!tty_throttle_safe(tty))
|
||||
break;
|
||||
}
|
||||
__tty_set_flow_change(tty, 0);
|
||||
}
|
||||
|
||||
int is_ignored(int sig)
|
||||
|
|
@ -1588,6 +1573,14 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
|
|||
ldata->real_raw = 0;
|
||||
}
|
||||
n_tty_set_room(tty);
|
||||
/*
|
||||
* Fix tty hang when I_IXON(tty) is cleared, but the tty
|
||||
* been stopped by STOP_CHAR(tty) before it.
|
||||
*/
|
||||
if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {
|
||||
start_tty(tty);
|
||||
}
|
||||
|
||||
/* The termios change make the tty ready for I/O */
|
||||
wake_up_interruptible(&tty->write_wait);
|
||||
wake_up_interruptible(&tty->read_wait);
|
||||
|
|
@ -1607,7 +1600,9 @@ static void n_tty_close(struct tty_struct *tty)
|
|||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
|
||||
n_tty_flush_buffer(tty);
|
||||
if (tty->link)
|
||||
n_tty_packet_mode_flush(tty);
|
||||
|
||||
kfree(ldata->read_buf);
|
||||
kfree(ldata->echo_buf);
|
||||
kfree(ldata);
|
||||
|
|
@ -1645,12 +1640,14 @@ static int n_tty_open(struct tty_struct *tty)
|
|||
goto err_free_bufs;
|
||||
|
||||
tty->disc_data = ldata;
|
||||
reset_buffer_flags(tty);
|
||||
tty_unthrottle(tty);
|
||||
reset_buffer_flags(tty->disc_data);
|
||||
ldata->column = 0;
|
||||
n_tty_set_termios(tty, NULL);
|
||||
tty->minimum_to_wake = 1;
|
||||
tty->closing = 0;
|
||||
/* indicate buffer work may resume */
|
||||
clear_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
n_tty_set_termios(tty, NULL);
|
||||
tty_unthrottle(tty);
|
||||
|
||||
return 0;
|
||||
err_free_bufs:
|
||||
|
|
@ -1740,10 +1737,9 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *,
|
|||
* and if appropriate send any needed signals and return a negative
|
||||
* error code if action should be taken.
|
||||
*
|
||||
* FIXME:
|
||||
* Locking: None - redirected write test is safe, testing
|
||||
* current->signal should possibly lock current->sighand
|
||||
* pgrp locking ?
|
||||
* Locking: redirected write test is safe
|
||||
* current->signal->tty check is safe
|
||||
* ctrl_lock to safely reference tty->pgrp
|
||||
*/
|
||||
|
||||
static int job_control(struct tty_struct *tty, struct file *file)
|
||||
|
|
@ -1753,19 +1749,22 @@ static int job_control(struct tty_struct *tty, struct file *file)
|
|||
/* NOTE: not yet done after every sleep pending a thorough
|
||||
check of the logic of this change. -- jlc */
|
||||
/* don't stop on /dev/console */
|
||||
if (file->f_op->write != redirected_tty_write &&
|
||||
current->signal->tty == tty) {
|
||||
if (!tty->pgrp)
|
||||
printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
|
||||
else if (task_pgrp(current) != tty->pgrp) {
|
||||
if (is_ignored(SIGTTIN) ||
|
||||
is_current_pgrp_orphaned())
|
||||
return -EIO;
|
||||
kill_pgrp(task_pgrp(current), SIGTTIN, 1);
|
||||
set_thread_flag(TIF_SIGPENDING);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
if (file->f_op->write == redirected_tty_write ||
|
||||
current->signal->tty != tty)
|
||||
return 0;
|
||||
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
if (!tty->pgrp)
|
||||
printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
|
||||
else if (task_pgrp(current) != tty->pgrp) {
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned())
|
||||
return -EIO;
|
||||
kill_pgrp(task_pgrp(current), SIGTTIN, 1);
|
||||
set_thread_flag(TIF_SIGPENDING);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1959,10 +1958,17 @@ do_it_again:
|
|||
* longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
|
||||
* we won't get any more characters.
|
||||
*/
|
||||
if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
|
||||
while (1) {
|
||||
tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
|
||||
if (n_tty_chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
|
||||
break;
|
||||
if (!tty->count)
|
||||
break;
|
||||
n_tty_set_room(tty);
|
||||
check_unthrottle(tty);
|
||||
if (!tty_unthrottle_safe(tty))
|
||||
break;
|
||||
}
|
||||
__tty_set_flow_change(tty, 0);
|
||||
|
||||
if (b - buf >= minimum)
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -791,7 +791,6 @@ static int send_data(enum port_type index, struct nozomi *dc)
|
|||
const u8 toggle = port->toggle_ul;
|
||||
void __iomem *addr = port->ul_addr[toggle];
|
||||
const u32 ul_size = port->ul_size[toggle];
|
||||
struct tty_struct *tty = tty_port_tty_get(&port->port);
|
||||
|
||||
/* Get data from tty and place in buf for now */
|
||||
size = kfifo_out(&port->fifo_ul, dc->send_buf,
|
||||
|
|
@ -799,7 +798,6 @@ static int send_data(enum port_type index, struct nozomi *dc)
|
|||
|
||||
if (size == 0) {
|
||||
DBG4("No more data to send, disable link:");
|
||||
tty_kref_put(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -809,10 +807,8 @@ static int send_data(enum port_type index, struct nozomi *dc)
|
|||
write_mem32(addr, (u32 *) &size, 4);
|
||||
write_mem32(addr + 4, (u32 *) dc->send_buf, size);
|
||||
|
||||
if (tty)
|
||||
tty_wakeup(tty);
|
||||
tty_port_tty_wakeup(&port->port);
|
||||
|
||||
tty_kref_put(tty);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -1505,12 +1501,9 @@ static void tty_exit(struct nozomi *dc)
|
|||
|
||||
DBG1(" ");
|
||||
|
||||
for (i = 0; i < MAX_PORT; ++i) {
|
||||
struct tty_struct *tty = tty_port_tty_get(&dc->port[i].port);
|
||||
if (tty && list_empty(&tty->hangup_work.entry))
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
for (i = 0; i < MAX_PORT; ++i)
|
||||
tty_port_tty_hangup(&dc->port[i].port, false);
|
||||
|
||||
/* Racy below - surely should wait for scheduled work to be done or
|
||||
complete off a hangup method ? */
|
||||
while (dc->open_ttys)
|
||||
|
|
|
|||
|
|
@ -405,15 +405,8 @@ err:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/* this is called once with whichever end is closed last */
|
||||
static void pty_unix98_shutdown(struct tty_struct *tty)
|
||||
{
|
||||
devpts_kill_index(tty->driver_data, tty->index);
|
||||
}
|
||||
|
||||
static void pty_cleanup(struct tty_struct *tty)
|
||||
{
|
||||
tty->port->itty = NULL;
|
||||
tty_port_put(tty->port);
|
||||
}
|
||||
|
||||
|
|
@ -627,6 +620,12 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
|||
{
|
||||
}
|
||||
|
||||
/* this is called once with whichever end is closed last */
|
||||
static void pty_unix98_shutdown(struct tty_struct *tty)
|
||||
{
|
||||
devpts_kill_index(tty->driver_data, tty->index);
|
||||
}
|
||||
|
||||
static const struct tty_operations ptm_unix98_ops = {
|
||||
.lookup = ptm_unix98_lookup,
|
||||
.install = pty_unix98_install,
|
||||
|
|
@ -682,6 +681,9 @@ static int ptmx_open(struct inode *inode, struct file *filp)
|
|||
|
||||
nonseekable_open(inode, filp);
|
||||
|
||||
/* We refuse fsnotify events on ptmx, since it's a shared resource */
|
||||
filp->f_mode |= FMODE_NONOTIFY;
|
||||
|
||||
retval = tty_alloc_file(filp);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -150,12 +150,14 @@ static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = {
|
|||
AIOP_INTR_BIT_3
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
|
||||
UPCI_AIOP_INTR_BIT_0,
|
||||
UPCI_AIOP_INTR_BIT_1,
|
||||
UPCI_AIOP_INTR_BIT_2,
|
||||
UPCI_AIOP_INTR_BIT_3
|
||||
};
|
||||
#endif
|
||||
|
||||
static Byte_t RData[RDATASIZE] = {
|
||||
0x00, 0x09, 0xf6, 0x82,
|
||||
|
|
@ -227,7 +229,6 @@ static unsigned long nextLineNumber;
|
|||
static int __init init_ISA(int i);
|
||||
static void rp_wait_until_sent(struct tty_struct *tty, int timeout);
|
||||
static void rp_flush_buffer(struct tty_struct *tty);
|
||||
static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model);
|
||||
static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
|
||||
static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
|
||||
static void rp_start(struct tty_struct *tty);
|
||||
|
|
@ -241,11 +242,6 @@ static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
|
|||
static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
|
||||
static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
|
||||
static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
|
||||
static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
|
||||
ByteIO_t * AiopIOList, int AiopIOListSize,
|
||||
WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
|
||||
int PeriodicOnly, int altChanRingIndicator,
|
||||
int UPCIRingInd);
|
||||
static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
|
||||
ByteIO_t * AiopIOList, int AiopIOListSize,
|
||||
int IRQNum, Byte_t Frequency, int PeriodicOnly);
|
||||
|
|
@ -449,7 +445,7 @@ static void rp_do_transmit(struct r_port *info)
|
|||
|
||||
/* Loop sending data to FIFO until done or FIFO full */
|
||||
while (1) {
|
||||
if (tty->stopped || tty->hw_stopped)
|
||||
if (tty->stopped)
|
||||
break;
|
||||
c = min(info->xmit_fifo_room, info->xmit_cnt);
|
||||
c = min(c, XMIT_BUF_SIZE - info->xmit_tail);
|
||||
|
|
@ -521,15 +517,10 @@ 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 = tty_port_tty_get(&info->port);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_hangup(&info->port, false);
|
||||
}
|
||||
info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
|
|
@ -1111,15 +1102,12 @@ static void rp_set_termios(struct tty_struct *tty,
|
|||
|
||||
/* Handle transition away from B0 status */
|
||||
if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
|
||||
if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS))
|
||||
sSetRTS(cp);
|
||||
sSetRTS(cp);
|
||||
sSetDTR(cp);
|
||||
}
|
||||
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) {
|
||||
tty->hw_stopped = 0;
|
||||
if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS))
|
||||
rp_start(tty);
|
||||
}
|
||||
}
|
||||
|
||||
static int rp_break(struct tty_struct *tty, int break_state)
|
||||
|
|
@ -1575,10 +1563,10 @@ static int rp_put_char(struct tty_struct *tty, unsigned char ch)
|
|||
spin_lock_irqsave(&info->slock, flags);
|
||||
cp = &info->channel;
|
||||
|
||||
if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0)
|
||||
if (!tty->stopped && info->xmit_fifo_room == 0)
|
||||
info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
|
||||
|
||||
if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
|
||||
if (tty->stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) {
|
||||
info->xmit_buf[info->xmit_head++] = ch;
|
||||
info->xmit_head &= XMIT_BUF_SIZE - 1;
|
||||
info->xmit_cnt++;
|
||||
|
|
@ -1619,14 +1607,14 @@ static int rp_write(struct tty_struct *tty,
|
|||
#endif
|
||||
cp = &info->channel;
|
||||
|
||||
if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count)
|
||||
if (!tty->stopped && info->xmit_fifo_room < count)
|
||||
info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
|
||||
|
||||
/*
|
||||
* If the write queue for the port is empty, and there is FIFO space, stuff bytes
|
||||
* into FIFO. Use the write queue for temp storage.
|
||||
*/
|
||||
if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
|
||||
if (!tty->stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) {
|
||||
c = min(count, info->xmit_fifo_room);
|
||||
b = buf;
|
||||
|
||||
|
|
@ -1674,7 +1662,7 @@ static int rp_write(struct tty_struct *tty,
|
|||
retval += c;
|
||||
}
|
||||
|
||||
if ((retval > 0) && !tty->stopped && !tty->hw_stopped)
|
||||
if ((retval > 0) && !tty->stopped)
|
||||
set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);
|
||||
|
||||
end:
|
||||
|
|
@ -1783,6 +1771,145 @@ static DEFINE_PCI_DEVICE_TABLE(rocket_pci_ids) = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
|
||||
|
||||
/* Resets the speaker controller on RocketModem II and III devices */
|
||||
static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
|
||||
{
|
||||
ByteIO_t addr;
|
||||
|
||||
/* RocketModem II speaker control is at the 8th port location of offset 0x40 */
|
||||
if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
|
||||
addr = CtlP->AiopIO[0] + 0x4F;
|
||||
sOutB(addr, 0);
|
||||
}
|
||||
|
||||
/* RocketModem III speaker control is at the 1st port location of offset 0x80 */
|
||||
if ((model == MODEL_UPCI_RM3_8PORT)
|
||||
|| (model == MODEL_UPCI_RM3_4PORT)) {
|
||||
addr = CtlP->AiopIO[0] + 0x88;
|
||||
sOutB(addr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Function: sPCIInitController
|
||||
Purpose: Initialization of controller global registers and controller
|
||||
structure.
|
||||
Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
|
||||
IRQNum,Frequency,PeriodicOnly)
|
||||
CONTROLLER_T *CtlP; Ptr to controller structure
|
||||
int CtlNum; Controller number
|
||||
ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
|
||||
This list must be in the order the AIOPs will be found on the
|
||||
controller. Once an AIOP in the list is not found, it is
|
||||
assumed that there are no more AIOPs on the controller.
|
||||
int AiopIOListSize; Number of addresses in AiopIOList
|
||||
int IRQNum; Interrupt Request number. Can be any of the following:
|
||||
0: Disable global interrupts
|
||||
3: IRQ 3
|
||||
4: IRQ 4
|
||||
5: IRQ 5
|
||||
9: IRQ 9
|
||||
10: IRQ 10
|
||||
11: IRQ 11
|
||||
12: IRQ 12
|
||||
15: IRQ 15
|
||||
Byte_t Frequency: A flag identifying the frequency
|
||||
of the periodic interrupt, can be any one of the following:
|
||||
FREQ_DIS - periodic interrupt disabled
|
||||
FREQ_137HZ - 137 Hertz
|
||||
FREQ_69HZ - 69 Hertz
|
||||
FREQ_34HZ - 34 Hertz
|
||||
FREQ_17HZ - 17 Hertz
|
||||
FREQ_9HZ - 9 Hertz
|
||||
FREQ_4HZ - 4 Hertz
|
||||
If IRQNum is set to 0 the Frequency parameter is
|
||||
overidden, it is forced to a value of FREQ_DIS.
|
||||
int PeriodicOnly: 1 if all interrupts except the periodic
|
||||
interrupt are to be blocked.
|
||||
0 is both the periodic interrupt and
|
||||
other channel interrupts are allowed.
|
||||
If IRQNum is set to 0 the PeriodicOnly parameter is
|
||||
overidden, it is forced to a value of 0.
|
||||
Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
|
||||
initialization failed.
|
||||
|
||||
Comments:
|
||||
If periodic interrupts are to be disabled but AIOP interrupts
|
||||
are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
|
||||
|
||||
If interrupts are to be completely disabled set IRQNum to 0.
|
||||
|
||||
Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
|
||||
invalid combination.
|
||||
|
||||
This function performs initialization of global interrupt modes,
|
||||
but it does not actually enable global interrupts. To enable
|
||||
and disable global interrupts use functions sEnGlobalInt() and
|
||||
sDisGlobalInt(). Enabling of global interrupts is normally not
|
||||
done until all other initializations are complete.
|
||||
|
||||
Even if interrupts are globally enabled, they must also be
|
||||
individually enabled for each channel that is to generate
|
||||
interrupts.
|
||||
|
||||
Warnings: No range checking on any of the parameters is done.
|
||||
|
||||
No context switches are allowed while executing this function.
|
||||
|
||||
After this function all AIOPs on the controller are disabled,
|
||||
they can be enabled with sEnAiop().
|
||||
*/
|
||||
static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
|
||||
ByteIO_t * AiopIOList, int AiopIOListSize,
|
||||
WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
|
||||
int PeriodicOnly, int altChanRingIndicator,
|
||||
int UPCIRingInd)
|
||||
{
|
||||
int i;
|
||||
ByteIO_t io;
|
||||
|
||||
CtlP->AltChanRingIndicator = altChanRingIndicator;
|
||||
CtlP->UPCIRingInd = UPCIRingInd;
|
||||
CtlP->CtlNum = CtlNum;
|
||||
CtlP->CtlID = CTLID_0001; /* controller release 1 */
|
||||
CtlP->BusType = isPCI; /* controller release 1 */
|
||||
|
||||
if (ConfigIO) {
|
||||
CtlP->isUPCI = 1;
|
||||
CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
|
||||
CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
|
||||
CtlP->AiopIntrBits = upci_aiop_intr_bits;
|
||||
} else {
|
||||
CtlP->isUPCI = 0;
|
||||
CtlP->PCIIO =
|
||||
(WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
|
||||
CtlP->AiopIntrBits = aiop_intr_bits;
|
||||
}
|
||||
|
||||
sPCIControllerEOI(CtlP); /* clear EOI if warm init */
|
||||
/* Init AIOPs */
|
||||
CtlP->NumAiop = 0;
|
||||
for (i = 0; i < AiopIOListSize; i++) {
|
||||
io = AiopIOList[i];
|
||||
CtlP->AiopIO[i] = (WordIO_t) io;
|
||||
CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
|
||||
|
||||
CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
|
||||
if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
|
||||
break; /* done looking for AIOPs */
|
||||
|
||||
CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
|
||||
sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
|
||||
sOutB(io + _INDX_DATA, sClockPrescale);
|
||||
CtlP->NumAiop++; /* bump count of AIOPs */
|
||||
}
|
||||
|
||||
if (CtlP->NumAiop == 0)
|
||||
return (-1);
|
||||
else
|
||||
return (CtlP->NumAiop);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when a PCI card is found. Retrieves and stores model information,
|
||||
* init's aiopic and serial port hardware.
|
||||
|
|
@ -2527,126 +2654,6 @@ static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
|
|||
return (CtlP->NumAiop);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Function: sPCIInitController
|
||||
Purpose: Initialization of controller global registers and controller
|
||||
structure.
|
||||
Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
|
||||
IRQNum,Frequency,PeriodicOnly)
|
||||
CONTROLLER_T *CtlP; Ptr to controller structure
|
||||
int CtlNum; Controller number
|
||||
ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
|
||||
This list must be in the order the AIOPs will be found on the
|
||||
controller. Once an AIOP in the list is not found, it is
|
||||
assumed that there are no more AIOPs on the controller.
|
||||
int AiopIOListSize; Number of addresses in AiopIOList
|
||||
int IRQNum; Interrupt Request number. Can be any of the following:
|
||||
0: Disable global interrupts
|
||||
3: IRQ 3
|
||||
4: IRQ 4
|
||||
5: IRQ 5
|
||||
9: IRQ 9
|
||||
10: IRQ 10
|
||||
11: IRQ 11
|
||||
12: IRQ 12
|
||||
15: IRQ 15
|
||||
Byte_t Frequency: A flag identifying the frequency
|
||||
of the periodic interrupt, can be any one of the following:
|
||||
FREQ_DIS - periodic interrupt disabled
|
||||
FREQ_137HZ - 137 Hertz
|
||||
FREQ_69HZ - 69 Hertz
|
||||
FREQ_34HZ - 34 Hertz
|
||||
FREQ_17HZ - 17 Hertz
|
||||
FREQ_9HZ - 9 Hertz
|
||||
FREQ_4HZ - 4 Hertz
|
||||
If IRQNum is set to 0 the Frequency parameter is
|
||||
overidden, it is forced to a value of FREQ_DIS.
|
||||
int PeriodicOnly: 1 if all interrupts except the periodic
|
||||
interrupt are to be blocked.
|
||||
0 is both the periodic interrupt and
|
||||
other channel interrupts are allowed.
|
||||
If IRQNum is set to 0 the PeriodicOnly parameter is
|
||||
overidden, it is forced to a value of 0.
|
||||
Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
|
||||
initialization failed.
|
||||
|
||||
Comments:
|
||||
If periodic interrupts are to be disabled but AIOP interrupts
|
||||
are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
|
||||
|
||||
If interrupts are to be completely disabled set IRQNum to 0.
|
||||
|
||||
Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
|
||||
invalid combination.
|
||||
|
||||
This function performs initialization of global interrupt modes,
|
||||
but it does not actually enable global interrupts. To enable
|
||||
and disable global interrupts use functions sEnGlobalInt() and
|
||||
sDisGlobalInt(). Enabling of global interrupts is normally not
|
||||
done until all other initializations are complete.
|
||||
|
||||
Even if interrupts are globally enabled, they must also be
|
||||
individually enabled for each channel that is to generate
|
||||
interrupts.
|
||||
|
||||
Warnings: No range checking on any of the parameters is done.
|
||||
|
||||
No context switches are allowed while executing this function.
|
||||
|
||||
After this function all AIOPs on the controller are disabled,
|
||||
they can be enabled with sEnAiop().
|
||||
*/
|
||||
static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
|
||||
ByteIO_t * AiopIOList, int AiopIOListSize,
|
||||
WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
|
||||
int PeriodicOnly, int altChanRingIndicator,
|
||||
int UPCIRingInd)
|
||||
{
|
||||
int i;
|
||||
ByteIO_t io;
|
||||
|
||||
CtlP->AltChanRingIndicator = altChanRingIndicator;
|
||||
CtlP->UPCIRingInd = UPCIRingInd;
|
||||
CtlP->CtlNum = CtlNum;
|
||||
CtlP->CtlID = CTLID_0001; /* controller release 1 */
|
||||
CtlP->BusType = isPCI; /* controller release 1 */
|
||||
|
||||
if (ConfigIO) {
|
||||
CtlP->isUPCI = 1;
|
||||
CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL;
|
||||
CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL;
|
||||
CtlP->AiopIntrBits = upci_aiop_intr_bits;
|
||||
} else {
|
||||
CtlP->isUPCI = 0;
|
||||
CtlP->PCIIO =
|
||||
(WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC);
|
||||
CtlP->AiopIntrBits = aiop_intr_bits;
|
||||
}
|
||||
|
||||
sPCIControllerEOI(CtlP); /* clear EOI if warm init */
|
||||
/* Init AIOPs */
|
||||
CtlP->NumAiop = 0;
|
||||
for (i = 0; i < AiopIOListSize; i++) {
|
||||
io = AiopIOList[i];
|
||||
CtlP->AiopIO[i] = (WordIO_t) io;
|
||||
CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
|
||||
|
||||
CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
|
||||
if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
|
||||
break; /* done looking for AIOPs */
|
||||
|
||||
CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */
|
||||
sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */
|
||||
sOutB(io + _INDX_DATA, sClockPrescale);
|
||||
CtlP->NumAiop++; /* bump count of AIOPs */
|
||||
}
|
||||
|
||||
if (CtlP->NumAiop == 0)
|
||||
return (-1);
|
||||
else
|
||||
return (CtlP->NumAiop);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Function: sReadAiopID
|
||||
Purpose: Read the AIOP idenfication number directly from an AIOP.
|
||||
|
|
@ -3136,25 +3143,6 @@ static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
|
|||
sOutB(addr + chan, 0); /* apply or remove reset */
|
||||
}
|
||||
|
||||
/* Resets the speaker controller on RocketModem II and III devices */
|
||||
static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model)
|
||||
{
|
||||
ByteIO_t addr;
|
||||
|
||||
/* RocketModem II speaker control is at the 8th port location of offset 0x40 */
|
||||
if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) {
|
||||
addr = CtlP->AiopIO[0] + 0x4F;
|
||||
sOutB(addr, 0);
|
||||
}
|
||||
|
||||
/* RocketModem III speaker control is at the 1st port location of offset 0x80 */
|
||||
if ((model == MODEL_UPCI_RM3_8PORT)
|
||||
|| (model == MODEL_UPCI_RM3_4PORT)) {
|
||||
addr = CtlP->AiopIO[0] + 0x88;
|
||||
sOutB(addr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the line number given the controller (board), aiop and channel number */
|
||||
static unsigned char GetLineNumber(int ctrl, int aiop, int ch)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
* 2.4/2.5 port David McCullough
|
||||
*/
|
||||
|
||||
#include <asm/dbg.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/serial.h>
|
||||
|
|
@ -630,8 +629,7 @@ static void rs_flush_chars(struct tty_struct *tty)
|
|||
/* Enable transmitter */
|
||||
local_irq_save(flags);
|
||||
|
||||
if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
|
||||
!info->xmit_buf) {
|
||||
if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) {
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
|
|
@ -697,7 +695,7 @@ static int rs_write(struct tty_struct * tty,
|
|||
total += c;
|
||||
}
|
||||
|
||||
if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
|
||||
if (info->xmit_cnt && !tty->stopped) {
|
||||
/* Enable transmitter */
|
||||
local_irq_disable();
|
||||
#ifndef USE_INTS
|
||||
|
|
@ -978,10 +976,8 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
|||
change_speed(info, tty);
|
||||
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS)) {
|
||||
tty->hw_stopped = 0;
|
||||
!(tty->termios.c_cflag & CRTSCTS))
|
||||
rs_start(tty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,13 +117,6 @@ static inline void serial_dl_write(struct uart_8250_port *up, int value)
|
|||
* is cleared, the machine locks up with endless interrupts.
|
||||
*/
|
||||
#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1)
|
||||
#elif defined(CONFIG_SBC8560)
|
||||
/*
|
||||
* WindRiver did something similarly broken on their SBC8560 board. The
|
||||
* UART tristates its IRQ output while OUT2 is clear, but they pulled
|
||||
* the interrupt line _up_ instead of down, so if we register the IRQ
|
||||
* while the UART is in that state, we die in an IRQ storm. */
|
||||
#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2)
|
||||
#else
|
||||
#define ALPHA_KLUDGE_MCR 0
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3247,6 +3247,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
|
|||
uart->tx_loadsz = up->tx_loadsz;
|
||||
uart->capabilities = up->capabilities;
|
||||
|
||||
/* Take tx_loadsz from fifosize if it wasn't set separately */
|
||||
if (uart->port.fifosize && !uart->tx_loadsz)
|
||||
uart->tx_loadsz = uart->port.fifosize;
|
||||
|
||||
if (up->port.dev)
|
||||
uart->port.dev = up->port.dev;
|
||||
|
||||
|
|
@ -3418,6 +3422,7 @@ MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
|
|||
#endif
|
||||
MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
|
||||
#ifndef MODULE
|
||||
/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name
|
||||
* working as well for the module options so we don't break people. We
|
||||
|
|
@ -3432,7 +3437,7 @@ MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
|
|||
static void __used s8250_options(void)
|
||||
{
|
||||
#undef MODULE_PARAM_PREFIX
|
||||
#define MODULE_PARAM_PREFIX "8250."
|
||||
#define MODULE_PARAM_PREFIX "8250_core."
|
||||
|
||||
module_param_cb(share_irqs, ¶m_ops_uint, &share_irqs, 0644);
|
||||
module_param_cb(nr_uarts, ¶m_ops_uint, &nr_uarts, 0644);
|
||||
|
|
@ -3444,5 +3449,6 @@ static void __used s8250_options(void)
|
|||
#endif
|
||||
}
|
||||
#else
|
||||
MODULE_ALIAS("8250");
|
||||
MODULE_ALIAS("8250_core");
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -33,10 +33,8 @@ static void __dma_tx_complete(void *param)
|
|||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&p->port);
|
||||
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&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)
|
||||
|
|
@ -67,12 +65,11 @@ int serial8250_tx_dma(struct uart_8250_port *p)
|
|||
struct circ_buf *xmit = &p->port.state->xmit;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
|
||||
if (dma->tx_running)
|
||||
return -EBUSY;
|
||||
if (uart_tx_stopped(&p->port) || dma->tx_running ||
|
||||
uart_circ_empty(xmit))
|
||||
return 0;
|
||||
|
||||
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,
|
||||
|
|
@ -104,20 +101,29 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
|
|||
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);
|
||||
dma_status = dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
|
||||
|
||||
switch (iir & 0x3f) {
|
||||
case UART_IIR_RLSI:
|
||||
/* 8250_core handles errors and break interrupts */
|
||||
return -EIO;
|
||||
case UART_IIR_RX_TIMEOUT:
|
||||
/*
|
||||
* If RCVR FIFO trigger level was not reached, complete the
|
||||
* transfer and let 8250_core copy the remaining data.
|
||||
*/
|
||||
if (dma_status == DMA_IN_PROGRESS) {
|
||||
dmaengine_pause(dma->rxchan);
|
||||
__dma_rx_complete(p);
|
||||
}
|
||||
return -ETIMEDOUT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dma_status)
|
||||
return 0;
|
||||
|
||||
desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr,
|
||||
dma->rx_size, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
|
|
@ -143,21 +149,31 @@ 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;
|
||||
/* Default slave configuration parameters */
|
||||
dma->rxconf.direction = DMA_DEV_TO_MEM;
|
||||
dma->rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
dma->rxconf.src_addr = p->port.mapbase + UART_RX;
|
||||
|
||||
dma->txconf.direction = DMA_MEM_TO_DEV;
|
||||
dma->txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
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);
|
||||
dma->rxchan = dma_request_slave_channel_compat(mask,
|
||||
dma->fn, dma->rx_param,
|
||||
p->port.dev, "rx");
|
||||
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);
|
||||
dma->txchan = dma_request_slave_channel_compat(mask,
|
||||
dma->fn, dma->tx_param,
|
||||
p->port.dev, "tx");
|
||||
if (!dma->txchan) {
|
||||
dma_release_channel(dma->rxchan);
|
||||
return -ENODEV;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
|
|
@ -34,9 +36,6 @@
|
|||
#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)
|
||||
|
|
@ -55,8 +54,9 @@
|
|||
|
||||
|
||||
struct dw8250_data {
|
||||
int last_lcr;
|
||||
int line;
|
||||
int last_lcr;
|
||||
int line;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
|
||||
|
|
@ -113,6 +113,18 @@ static int dw8250_handle_irq(struct uart_port *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dw8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old)
|
||||
{
|
||||
if (!state)
|
||||
pm_runtime_get_sync(port->dev);
|
||||
|
||||
serial8250_do_pm(port, state, old);
|
||||
|
||||
if (state)
|
||||
pm_runtime_put_sync_suspend(port->dev);
|
||||
}
|
||||
|
||||
static int dw8250_probe_of(struct uart_port *p)
|
||||
{
|
||||
struct device_node *np = p->dev->of_node;
|
||||
|
|
@ -136,8 +148,13 @@ static int dw8250_probe_of(struct uart_port *p)
|
|||
if (!of_property_read_u32(np, "reg-shift", &val))
|
||||
p->regshift = val;
|
||||
|
||||
/* clock got configured through clk api, all done */
|
||||
if (p->uartclk)
|
||||
return 0;
|
||||
|
||||
/* try to find out clock frequency from DT as fallback */
|
||||
if (of_property_read_u32(np, "clock-frequency", &val)) {
|
||||
dev_err(p->dev, "no clock-frequency property set\n");
|
||||
dev_err(p->dev, "clk or clock-frequency not defined\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
p->uartclk = val;
|
||||
|
|
@ -146,67 +163,10 @@ static int dw8250_probe_of(struct uart_port *p)
|
|||
}
|
||||
|
||||
#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)
|
||||
static int dw8250_probe_acpi(struct uart_8250_port *up)
|
||||
{
|
||||
const struct acpi_device_id *id;
|
||||
acpi_status status;
|
||||
u32 reg;
|
||||
struct uart_port *p = &up->port;
|
||||
|
||||
id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
|
||||
if (!id)
|
||||
|
|
@ -216,26 +176,21 @@ static int dw8250_probe_acpi(struct uart_port *p)
|
|||
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;
|
||||
}
|
||||
if (!p->uartclk)
|
||||
p->uartclk = (unsigned int)id->driver_data;
|
||||
|
||||
/* 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);
|
||||
}
|
||||
up->dma = devm_kzalloc(p->dev, sizeof(*up->dma), GFP_KERNEL);
|
||||
if (!up->dma)
|
||||
return -ENOMEM;
|
||||
|
||||
up->dma->rxconf.src_maxburst = p->fifosize / 4;
|
||||
up->dma->txconf.dst_maxburst = p->fifosize / 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int dw8250_probe_acpi(struct uart_port *p)
|
||||
static inline int dw8250_probe_acpi(struct uart_8250_port *up)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
@ -266,7 +221,11 @@ static void dw8250_setup_port(struct uart_8250_port *up)
|
|||
p->flags |= UPF_FIXED_TYPE;
|
||||
p->fifosize = DW_UART_CPR_FIFO_SIZE(reg);
|
||||
up->tx_loadsz = p->fifosize;
|
||||
up->capabilities = UART_CAP_FIFO;
|
||||
}
|
||||
|
||||
if (reg & DW_UART_CPR_AFCE_MODE)
|
||||
up->capabilities |= UART_CAP_AFE;
|
||||
}
|
||||
|
||||
static int dw8250_probe(struct platform_device *pdev)
|
||||
|
|
@ -286,17 +245,30 @@ static int dw8250_probe(struct platform_device *pdev)
|
|||
uart.port.mapbase = regs->start;
|
||||
uart.port.irq = irq->start;
|
||||
uart.port.handle_irq = dw8250_handle_irq;
|
||||
uart.port.pm = dw8250_do_pm;
|
||||
uart.port.type = PORT_8250;
|
||||
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));
|
||||
uart.port.membase = devm_ioremap(&pdev->dev, regs->start,
|
||||
resource_size(regs));
|
||||
if (!uart.port.membase)
|
||||
return -ENOMEM;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (!IS_ERR(data->clk)) {
|
||||
clk_prepare_enable(data->clk);
|
||||
uart.port.uartclk = clk_get_rate(data->clk);
|
||||
}
|
||||
|
||||
uart.port.iotype = UPIO_MEM;
|
||||
uart.port.serial_in = dw8250_serial_in;
|
||||
uart.port.serial_out = dw8250_serial_out;
|
||||
uart.port.private_data = data;
|
||||
|
||||
dw8250_setup_port(&uart);
|
||||
|
||||
|
|
@ -305,25 +277,22 @@ static int dw8250_probe(struct platform_device *pdev)
|
|||
if (err)
|
||||
return err;
|
||||
} else if (ACPI_HANDLE(&pdev->dev)) {
|
||||
err = dw8250_probe_acpi(&uart.port);
|
||||
err = dw8250_probe_acpi(&uart);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
uart.port.private_data = data;
|
||||
|
||||
data->line = serial8250_register_8250_port(&uart);
|
||||
if (data->line < 0)
|
||||
return data->line;
|
||||
|
||||
platform_set_drvdata(pdev, data);
|
||||
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -331,34 +300,66 @@ static int dw8250_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct dw8250_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
|
||||
serial8250_unregister_port(data->line);
|
||||
|
||||
if (!IS_ERR(data->clk))
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int dw8250_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
static int dw8250_suspend(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = platform_get_drvdata(pdev);
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
serial8250_suspend_port(data->line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw8250_resume(struct platform_device *pdev)
|
||||
static int dw8250_resume(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = platform_get_drvdata(pdev);
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
serial8250_resume_port(data->line);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define dw8250_suspend NULL
|
||||
#define dw8250_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int dw8250_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (!IS_ERR(data->clk))
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw8250_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (!IS_ERR(data->clk))
|
||||
clk_prepare_enable(data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops dw8250_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
|
||||
SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct of_device_id dw8250_of_match[] = {
|
||||
{ .compatible = "snps,dw-apb-uart" },
|
||||
{ /* Sentinel */ }
|
||||
|
|
@ -366,8 +367,9 @@ static const struct of_device_id dw8250_of_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, dw8250_of_match);
|
||||
|
||||
static const struct acpi_device_id dw8250_acpi_match[] = {
|
||||
{ "INT33C4", 100000000 },
|
||||
{ "INT33C5", 100000000 },
|
||||
{ "INT33C4", 0 },
|
||||
{ "INT33C5", 0 },
|
||||
{ "80860F0A", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
|
||||
|
|
@ -376,13 +378,12 @@ static struct platform_driver dw8250_platform_driver = {
|
|||
.driver = {
|
||||
.name = "dw-apb-uart",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &dw8250_pm_ops,
|
||||
.of_match_table = dw8250_of_match,
|
||||
.acpi_match_table = ACPI_PTR(dw8250_acpi_match),
|
||||
},
|
||||
.probe = dw8250_probe,
|
||||
.remove = dw8250_remove,
|
||||
.suspend = dw8250_suspend,
|
||||
.resume = dw8250_resume,
|
||||
};
|
||||
|
||||
module_platform_driver(dw8250_platform_driver);
|
||||
|
|
|
|||
|
|
@ -1554,6 +1554,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
|
|||
#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
|
||||
#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
|
||||
#define PCI_VENDOR_ID_WCH 0x4348
|
||||
#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253
|
||||
#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
|
||||
#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
|
||||
#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
|
||||
|
|
@ -2172,6 +2173,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
|||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_wch_ch353_setup,
|
||||
},
|
||||
/* WCH CH352 2S card (16550 clone) */
|
||||
{
|
||||
.vendor = PCI_VENDOR_ID_WCH,
|
||||
.device = PCI_DEVICE_ID_WCH_CH352_2S,
|
||||
.subvendor = PCI_ANY_ID,
|
||||
.subdevice = PCI_ANY_ID,
|
||||
.setup = pci_wch_ch353_setup,
|
||||
},
|
||||
/*
|
||||
* ASIX devices with FIFO bug
|
||||
*/
|
||||
|
|
@ -4870,6 +4879,10 @@ static struct pci_device_id serial_pci_tbl[] = {
|
|||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0, pbn_b0_bt_2_115200 },
|
||||
|
||||
{ PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH352_2S,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0, pbn_b0_bt_2_115200 },
|
||||
|
||||
/*
|
||||
* Commtech, Inc. Fastcom adapters
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -429,7 +429,6 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
|
|||
{
|
||||
struct uart_8250_port uart;
|
||||
int ret, line, flags = dev_id->driver_data;
|
||||
struct resource *res = NULL;
|
||||
|
||||
if (flags & UNKNOWN_DEV) {
|
||||
ret = serial_pnp_guess_board(dev);
|
||||
|
|
@ -440,12 +439,11 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
|
|||
memset(&uart, 0, sizeof(uart));
|
||||
if (pnp_irq_valid(dev, 0))
|
||||
uart.port.irq = pnp_irq(dev, 0);
|
||||
if ((flags & CIR_PORT) && pnp_port_valid(dev, 2))
|
||||
res = pnp_get_resource(dev, IORESOURCE_IO, 2);
|
||||
else if (pnp_port_valid(dev, 0))
|
||||
res = pnp_get_resource(dev, IORESOURCE_IO, 0);
|
||||
if (pnp_resource_enabled(res)) {
|
||||
uart.port.iobase = res->start;
|
||||
if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
|
||||
uart.port.iobase = pnp_port_start(dev, 2);
|
||||
uart.port.iotype = UPIO_PORT;
|
||||
} else if (pnp_port_valid(dev, 0)) {
|
||||
uart.port.iobase = pnp_port_start(dev, 0);
|
||||
uart.port.iotype = UPIO_PORT;
|
||||
} else if (pnp_mem_valid(dev, 0)) {
|
||||
uart.port.mapbase = pnp_mem_start(dev, 0);
|
||||
|
|
|
|||
|
|
@ -33,6 +33,23 @@ config SERIAL_8250
|
|||
Most people will say Y or M here, so that they can use serial mice,
|
||||
modems and similar devices connecting to the standard serial ports.
|
||||
|
||||
config SERIAL_8250_DEPRECATED_OPTIONS
|
||||
bool "Support 8250_core.* kernel options (DEPRECATED)"
|
||||
depends on SERIAL_8250
|
||||
default y
|
||||
---help---
|
||||
In 3.7 we renamed 8250 to 8250_core by mistake, so now we have to
|
||||
accept kernel parameters in both forms like 8250_core.nr_uarts=4 and
|
||||
8250.nr_uarts=4. We now renamed the module back to 8250, but if
|
||||
anybody noticed in 3.7 and changed their userspace we still have to
|
||||
keep the 8350_core.* options around until they revert the changes
|
||||
they already did.
|
||||
|
||||
If 8250 is built as a module, this adds 8250_core alias instead.
|
||||
|
||||
If you did not notice yet and/or you have userspace from pre-3.7, it
|
||||
is safe (and recommended) to say N here.
|
||||
|
||||
config SERIAL_8250_PNP
|
||||
bool "8250/16550 PNP device support" if EXPERT
|
||||
depends on SERIAL_8250 && PNP
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
# Makefile for the 8250 serial device drivers.
|
||||
#
|
||||
|
||||
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) += 8250.o
|
||||
8250-y := 8250_core.o
|
||||
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
|
||||
8250-$(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
|
||||
|
|
|
|||
|
|
@ -852,18 +852,6 @@ static struct pcmcia_driver serial_cs_driver = {
|
|||
.suspend = serial_suspend,
|
||||
.resume = serial_resume,
|
||||
};
|
||||
|
||||
static int __init init_serial_cs(void)
|
||||
{
|
||||
return pcmcia_register_driver(&serial_cs_driver);
|
||||
}
|
||||
|
||||
static void __exit exit_serial_cs(void)
|
||||
{
|
||||
pcmcia_unregister_driver(&serial_cs_driver);
|
||||
}
|
||||
|
||||
module_init(init_serial_cs);
|
||||
module_exit(exit_serial_cs);
|
||||
module_pcmcia_driver(serial_cs_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
* and hooked into this driver.
|
||||
*/
|
||||
|
||||
|
||||
#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
|
@ -72,32 +73,44 @@
|
|||
/* There is by now at least one vendor with differing details, so handle it */
|
||||
struct vendor_data {
|
||||
unsigned int ifls;
|
||||
unsigned int fifosize;
|
||||
unsigned int lcrh_tx;
|
||||
unsigned int lcrh_rx;
|
||||
bool oversampling;
|
||||
bool dma_threshold;
|
||||
bool cts_event_workaround;
|
||||
|
||||
unsigned int (*get_fifosize)(unsigned int periphid);
|
||||
};
|
||||
|
||||
static unsigned int get_fifosize_arm(unsigned int periphid)
|
||||
{
|
||||
unsigned int rev = (periphid >> 20) & 0xf;
|
||||
return rev < 3 ? 16 : 32;
|
||||
}
|
||||
|
||||
static struct vendor_data vendor_arm = {
|
||||
.ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8,
|
||||
.fifosize = 16,
|
||||
.lcrh_tx = UART011_LCRH,
|
||||
.lcrh_rx = UART011_LCRH,
|
||||
.oversampling = false,
|
||||
.dma_threshold = false,
|
||||
.cts_event_workaround = false,
|
||||
.get_fifosize = get_fifosize_arm,
|
||||
};
|
||||
|
||||
static unsigned int get_fifosize_st(unsigned int periphid)
|
||||
{
|
||||
return 64;
|
||||
}
|
||||
|
||||
static struct vendor_data vendor_st = {
|
||||
.ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF,
|
||||
.fifosize = 64,
|
||||
.lcrh_tx = ST_UART011_LCRH_TX,
|
||||
.lcrh_rx = ST_UART011_LCRH_RX,
|
||||
.oversampling = true,
|
||||
.dma_threshold = true,
|
||||
.cts_event_workaround = true,
|
||||
.get_fifosize = get_fifosize_st,
|
||||
};
|
||||
|
||||
static struct uart_amba_port *amba_ports[UART_NR];
|
||||
|
|
@ -117,6 +130,12 @@ struct pl011_dmarx_data {
|
|||
struct pl011_sgbuf sgbuf_b;
|
||||
dma_cookie_t cookie;
|
||||
bool running;
|
||||
struct timer_list timer;
|
||||
unsigned int last_residue;
|
||||
unsigned long last_jiffies;
|
||||
bool auto_poll_rate;
|
||||
unsigned int poll_rate;
|
||||
unsigned int poll_timeout;
|
||||
};
|
||||
|
||||
struct pl011_dmatx_data {
|
||||
|
|
@ -223,16 +242,18 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
|
|||
static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
sg->buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL);
|
||||
dma_addr_t dma_addr;
|
||||
|
||||
sg->buf = dma_alloc_coherent(chan->device->dev,
|
||||
PL011_DMA_BUFFER_SIZE, &dma_addr, GFP_KERNEL);
|
||||
if (!sg->buf)
|
||||
return -ENOMEM;
|
||||
|
||||
sg_init_one(&sg->sg, sg->buf, PL011_DMA_BUFFER_SIZE);
|
||||
sg_init_table(&sg->sg, 1);
|
||||
sg_set_page(&sg->sg, phys_to_page(dma_addr),
|
||||
PL011_DMA_BUFFER_SIZE, offset_in_page(dma_addr));
|
||||
sg_dma_address(&sg->sg) = dma_addr;
|
||||
|
||||
if (dma_map_sg(chan->device->dev, &sg->sg, 1, dir) != 1) {
|
||||
kfree(sg->buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -240,12 +261,13 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
|
|||
enum dma_data_direction dir)
|
||||
{
|
||||
if (sg->buf) {
|
||||
dma_unmap_sg(chan->device->dev, &sg->sg, 1, dir);
|
||||
kfree(sg->buf);
|
||||
dma_free_coherent(chan->device->dev,
|
||||
PL011_DMA_BUFFER_SIZE, sg->buf,
|
||||
sg_dma_address(&sg->sg));
|
||||
}
|
||||
}
|
||||
|
||||
static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
|
||||
static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port *uap)
|
||||
{
|
||||
/* DMA is the sole user of the platform data right now */
|
||||
struct amba_pl011_data *plat = uap->port.dev->platform_data;
|
||||
|
|
@ -259,20 +281,25 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
|
|||
struct dma_chan *chan;
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
/* We need platform data */
|
||||
if (!plat || !plat->dma_filter) {
|
||||
dev_info(uap->port.dev, "no DMA platform data\n");
|
||||
return;
|
||||
}
|
||||
chan = dma_request_slave_channel(dev, "tx");
|
||||
|
||||
/* Try to acquire a generic DMA engine slave TX channel */
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_tx_param);
|
||||
if (!chan) {
|
||||
dev_err(uap->port.dev, "no TX DMA channel!\n");
|
||||
return;
|
||||
/* We need platform data */
|
||||
if (!plat || !plat->dma_filter) {
|
||||
dev_info(uap->port.dev, "no DMA platform data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to acquire a generic DMA engine slave TX channel */
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
chan = dma_request_channel(mask, plat->dma_filter,
|
||||
plat->dma_tx_param);
|
||||
if (!chan) {
|
||||
dev_err(uap->port.dev, "no TX DMA channel!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dmaengine_slave_config(chan, &tx_conf);
|
||||
|
|
@ -282,7 +309,18 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
|
|||
dma_chan_name(uap->dmatx.chan));
|
||||
|
||||
/* Optionally make use of an RX channel as well */
|
||||
if (plat->dma_rx_param) {
|
||||
chan = dma_request_slave_channel(dev, "rx");
|
||||
|
||||
if (!chan && plat->dma_rx_param) {
|
||||
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
|
||||
|
||||
if (!chan) {
|
||||
dev_err(uap->port.dev, "no RX DMA channel!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan) {
|
||||
struct dma_slave_config rx_conf = {
|
||||
.src_addr = uap->port.mapbase + UART01x_DR,
|
||||
.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
|
||||
|
|
@ -291,15 +329,32 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
|
|||
.device_fc = false,
|
||||
};
|
||||
|
||||
chan = dma_request_channel(mask, plat->dma_filter, plat->dma_rx_param);
|
||||
if (!chan) {
|
||||
dev_err(uap->port.dev, "no RX DMA channel!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dmaengine_slave_config(chan, &rx_conf);
|
||||
uap->dmarx.chan = chan;
|
||||
|
||||
if (plat && plat->dma_rx_poll_enable) {
|
||||
/* Set poll rate if specified. */
|
||||
if (plat->dma_rx_poll_rate) {
|
||||
uap->dmarx.auto_poll_rate = false;
|
||||
uap->dmarx.poll_rate = plat->dma_rx_poll_rate;
|
||||
} else {
|
||||
/*
|
||||
* 100 ms defaults to poll rate if not
|
||||
* specified. This will be adjusted with
|
||||
* the baud rate at set_termios.
|
||||
*/
|
||||
uap->dmarx.auto_poll_rate = true;
|
||||
uap->dmarx.poll_rate = 100;
|
||||
}
|
||||
/* 3 secs defaults poll_timeout if not specified. */
|
||||
if (plat->dma_rx_poll_timeout)
|
||||
uap->dmarx.poll_timeout =
|
||||
plat->dma_rx_poll_timeout;
|
||||
else
|
||||
uap->dmarx.poll_timeout = 3000;
|
||||
} else
|
||||
uap->dmarx.auto_poll_rate = false;
|
||||
|
||||
dev_info(uap->port.dev, "DMA channel RX %s\n",
|
||||
dma_chan_name(uap->dmarx.chan));
|
||||
}
|
||||
|
|
@ -315,6 +370,7 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
|
|||
struct dma_uap {
|
||||
struct list_head node;
|
||||
struct uart_amba_port *uap;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static LIST_HEAD(pl011_dma_uarts);
|
||||
|
|
@ -325,7 +381,7 @@ static int __init pl011_dma_initcall(void)
|
|||
|
||||
list_for_each_safe(node, tmp, &pl011_dma_uarts) {
|
||||
struct dma_uap *dmau = list_entry(node, struct dma_uap, node);
|
||||
pl011_dma_probe_initcall(dmau->uap);
|
||||
pl011_dma_probe_initcall(dmau->dev, dmau->uap);
|
||||
list_del(node);
|
||||
kfree(dmau);
|
||||
}
|
||||
|
|
@ -334,18 +390,19 @@ static int __init pl011_dma_initcall(void)
|
|||
|
||||
device_initcall(pl011_dma_initcall);
|
||||
|
||||
static void pl011_dma_probe(struct uart_amba_port *uap)
|
||||
static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
|
||||
{
|
||||
struct dma_uap *dmau = kzalloc(sizeof(struct dma_uap), GFP_KERNEL);
|
||||
if (dmau) {
|
||||
dmau->uap = uap;
|
||||
dmau->dev = dev;
|
||||
list_add_tail(&dmau->node, &pl011_dma_uarts);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void pl011_dma_probe(struct uart_amba_port *uap)
|
||||
static void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
|
||||
{
|
||||
pl011_dma_probe_initcall(uap);
|
||||
pl011_dma_probe_initcall(dev, uap);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -701,24 +758,30 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
|
|||
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;
|
||||
int dma_count = 0;
|
||||
u32 fifotaken = 0; /* only used for vdbg() */
|
||||
|
||||
/* Pick everything from the DMA first */
|
||||
struct pl011_dmarx_data *dmarx = &uap->dmarx;
|
||||
int dmataken = 0;
|
||||
|
||||
if (uap->dmarx.poll_rate) {
|
||||
/* The data can be taken by polling */
|
||||
dmataken = sgbuf->sg.length - dmarx->last_residue;
|
||||
/* Recalculate the pending size */
|
||||
if (pending >= dmataken)
|
||||
pending -= dmataken;
|
||||
}
|
||||
|
||||
/* Pick the remain data from the DMA */
|
||||
if (pending) {
|
||||
/* Sync in buffer */
|
||||
dma_sync_sg_for_cpu(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
|
||||
|
||||
/*
|
||||
* First take all chars in the DMA pipe, then look in the FIFO.
|
||||
* Note that tty_insert_flip_buf() tries to take as many chars
|
||||
* as it can.
|
||||
*/
|
||||
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);
|
||||
dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken,
|
||||
pending);
|
||||
|
||||
uap->port.icount.rx += dma_count;
|
||||
if (dma_count < pending)
|
||||
|
|
@ -726,6 +789,10 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
|
|||
"couldn't insert all characters (TTY is full?)\n");
|
||||
}
|
||||
|
||||
/* Reset the last_residue for Rx DMA poll */
|
||||
if (uap->dmarx.poll_rate)
|
||||
dmarx->last_residue = sgbuf->sg.length;
|
||||
|
||||
/*
|
||||
* Only continue with trying to read the FIFO if all DMA chars have
|
||||
* been taken first.
|
||||
|
|
@ -865,6 +932,57 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
|
|||
writew(uap->dmacr, uap->port.membase + UART011_DMACR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Timer handler for Rx DMA polling.
|
||||
* Every polling, It checks the residue in the dma buffer and transfer
|
||||
* data to the tty. Also, last_residue is updated for the next polling.
|
||||
*/
|
||||
static void pl011_dma_rx_poll(unsigned long args)
|
||||
{
|
||||
struct uart_amba_port *uap = (struct uart_amba_port *)args;
|
||||
struct tty_port *port = &uap->port.state->port;
|
||||
struct pl011_dmarx_data *dmarx = &uap->dmarx;
|
||||
struct dma_chan *rxchan = uap->dmarx.chan;
|
||||
unsigned long flags = 0;
|
||||
unsigned int dmataken = 0;
|
||||
unsigned int size = 0;
|
||||
struct pl011_sgbuf *sgbuf;
|
||||
int dma_count;
|
||||
struct dma_tx_state state;
|
||||
|
||||
sgbuf = dmarx->use_buf_b ? &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
|
||||
rxchan->device->device_tx_status(rxchan, dmarx->cookie, &state);
|
||||
if (likely(state.residue < dmarx->last_residue)) {
|
||||
dmataken = sgbuf->sg.length - dmarx->last_residue;
|
||||
size = dmarx->last_residue - state.residue;
|
||||
dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken,
|
||||
size);
|
||||
if (dma_count == size)
|
||||
dmarx->last_residue = state.residue;
|
||||
dmarx->last_jiffies = jiffies;
|
||||
}
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
/*
|
||||
* If no data is received in poll_timeout, the driver will fall back
|
||||
* to interrupt mode. We will retrigger DMA at the first interrupt.
|
||||
*/
|
||||
if (jiffies_to_msecs(jiffies - dmarx->last_jiffies)
|
||||
> uap->dmarx.poll_timeout) {
|
||||
|
||||
spin_lock_irqsave(&uap->port.lock, flags);
|
||||
pl011_dma_rx_stop(uap);
|
||||
spin_unlock_irqrestore(&uap->port.lock, flags);
|
||||
|
||||
uap->dmarx.running = false;
|
||||
dmaengine_terminate_all(rxchan);
|
||||
del_timer(&uap->dmarx.timer);
|
||||
} else {
|
||||
mod_timer(&uap->dmarx.timer,
|
||||
jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
|
||||
}
|
||||
}
|
||||
|
||||
static void pl011_dma_startup(struct uart_amba_port *uap)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -927,6 +1045,16 @@ skip_rx:
|
|||
if (pl011_dma_rx_trigger_dma(uap))
|
||||
dev_dbg(uap->port.dev, "could not trigger initial "
|
||||
"RX DMA job, fall back to interrupt mode\n");
|
||||
if (uap->dmarx.poll_rate) {
|
||||
init_timer(&(uap->dmarx.timer));
|
||||
uap->dmarx.timer.function = pl011_dma_rx_poll;
|
||||
uap->dmarx.timer.data = (unsigned long)uap;
|
||||
mod_timer(&uap->dmarx.timer,
|
||||
jiffies +
|
||||
msecs_to_jiffies(uap->dmarx.poll_rate));
|
||||
uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
|
||||
uap->dmarx.last_jiffies = jiffies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -962,6 +1090,8 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
|
|||
/* Clean up the RX DMA */
|
||||
pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_a, DMA_FROM_DEVICE);
|
||||
pl011_sgbuf_free(uap->dmarx.chan, &uap->dmarx.sgbuf_b, DMA_FROM_DEVICE);
|
||||
if (uap->dmarx.poll_rate)
|
||||
del_timer_sync(&uap->dmarx.timer);
|
||||
uap->using_rx_dma = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -976,10 +1106,9 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
|
|||
return uap->using_rx_dma && uap->dmarx.running;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
/* Blank functions if the DMA engine is not available */
|
||||
static inline void pl011_dma_probe(struct uart_amba_port *uap)
|
||||
static inline void pl011_dma_probe(struct device *dev, struct uart_amba_port *uap)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -1088,8 +1217,20 @@ static void pl011_rx_chars(struct uart_amba_port *uap)
|
|||
dev_dbg(uap->port.dev, "could not trigger RX DMA job "
|
||||
"fall back to interrupt mode again\n");
|
||||
uap->im |= UART011_RXIM;
|
||||
} else
|
||||
} else {
|
||||
uap->im &= ~UART011_RXIM;
|
||||
#ifdef CONFIG_DMA_ENGINE
|
||||
/* Start Rx DMA poll */
|
||||
if (uap->dmarx.poll_rate) {
|
||||
uap->dmarx.last_jiffies = jiffies;
|
||||
uap->dmarx.last_residue = PL011_DMA_BUFFER_SIZE;
|
||||
mod_timer(&uap->dmarx.timer,
|
||||
jiffies +
|
||||
msecs_to_jiffies(uap->dmarx.poll_rate));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
writew(uap->im, uap->port.membase + UART011_IMSC);
|
||||
}
|
||||
spin_lock(&uap->port.lock);
|
||||
|
|
@ -1164,7 +1305,6 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
|
|||
unsigned int dummy_read;
|
||||
|
||||
spin_lock_irqsave(&uap->port.lock, flags);
|
||||
|
||||
status = readw(uap->port.membase + UART011_MIS);
|
||||
if (status) {
|
||||
do {
|
||||
|
|
@ -1551,6 +1691,13 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
*/
|
||||
baud = uart_get_baud_rate(port, termios, old, 0,
|
||||
port->uartclk / clkdiv);
|
||||
#ifdef CONFIG_DMA_ENGINE
|
||||
/*
|
||||
* Adjust RX DMA polling rate with baud rate if not specified.
|
||||
*/
|
||||
if (uap->dmarx.auto_poll_rate)
|
||||
uap->dmarx.poll_rate = DIV_ROUND_UP(10000000, baud);
|
||||
#endif
|
||||
|
||||
if (baud > port->uartclk/16)
|
||||
quot = DIV_ROUND_CLOSEST(port->uartclk * 8, baud);
|
||||
|
|
@ -2010,7 +2157,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
uap->lcrh_rx = vendor->lcrh_rx;
|
||||
uap->lcrh_tx = vendor->lcrh_tx;
|
||||
uap->old_cr = 0;
|
||||
uap->fifosize = vendor->fifosize;
|
||||
uap->fifosize = vendor->get_fifosize(dev->periphid);
|
||||
uap->port.dev = &dev->dev;
|
||||
uap->port.mapbase = dev->res.start;
|
||||
uap->port.membase = base;
|
||||
|
|
@ -2020,7 +2167,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
uap->port.ops = &amba_pl011_pops;
|
||||
uap->port.flags = UPF_BOOT_AUTOCONF;
|
||||
uap->port.line = i;
|
||||
pl011_dma_probe(uap);
|
||||
pl011_dma_probe(&dev->dev, uap);
|
||||
|
||||
/* Ensure interrupts from this UART are masked and cleared */
|
||||
writew(0, uap->port.membase + UART011_IMSC);
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port)
|
|||
/*
|
||||
* Driver internal routine, used by both tty(serial core) as well as tx-isr
|
||||
* -Called under spinlock in either cases
|
||||
* -also tty->stopped / tty->hw_stopped has already been checked
|
||||
* -also tty->stopped has already been checked
|
||||
* = by uart_start( ) before calling us
|
||||
* = tx_ist checks that too before calling
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ struct atmel_uart_port {
|
|||
};
|
||||
|
||||
static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
|
||||
static unsigned long atmel_ports_in_use;
|
||||
static DECLARE_BITMAP(atmel_ports_in_use, ATMEL_MAX_UART);
|
||||
|
||||
#ifdef SUPPORT_SYSRQ
|
||||
static struct console atmel_console;
|
||||
|
|
@ -1769,15 +1769,14 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
/* port id not found in platform data nor device-tree aliases:
|
||||
* auto-enumerate it */
|
||||
ret = find_first_zero_bit(&atmel_ports_in_use,
|
||||
sizeof(atmel_ports_in_use));
|
||||
ret = find_first_zero_bit(atmel_ports_in_use, ATMEL_MAX_UART);
|
||||
|
||||
if (ret > ATMEL_MAX_UART) {
|
||||
if (ret >= ATMEL_MAX_UART) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (test_and_set_bit(ret, &atmel_ports_in_use)) {
|
||||
if (test_and_set_bit(ret, atmel_ports_in_use)) {
|
||||
/* port already in use */
|
||||
ret = -EBUSY;
|
||||
goto err;
|
||||
|
|
@ -1857,7 +1856,7 @@ static int atmel_serial_remove(struct platform_device *pdev)
|
|||
|
||||
/* "port" is allocated statically, so we shouldn't free it */
|
||||
|
||||
clear_bit(port->line, &atmel_ports_in_use);
|
||||
clear_bit(port->line, atmel_ports_in_use);
|
||||
|
||||
clk_put(atmel_port->clk);
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#include <bcm63xx_clk.h>
|
||||
#include <bcm63xx_irq.h>
|
||||
#include <bcm63xx_regs.h>
|
||||
#include <bcm63xx_io.h>
|
||||
|
|
|
|||
|
|
@ -1011,24 +1011,6 @@ static int bfin_serial_poll_get_char(struct uart_port *port)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
|
||||
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
|
||||
static void bfin_kgdboc_port_shutdown(struct uart_port *port)
|
||||
{
|
||||
if (kgdboc_break_enabled) {
|
||||
kgdboc_break_enabled = 0;
|
||||
bfin_serial_shutdown(port);
|
||||
}
|
||||
}
|
||||
|
||||
static int bfin_kgdboc_port_startup(struct uart_port *port)
|
||||
{
|
||||
kgdboc_port_line = port->line;
|
||||
kgdboc_break_enabled = !bfin_serial_startup(port);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct uart_ops bfin_serial_pops = {
|
||||
.tx_empty = bfin_serial_tx_empty,
|
||||
.set_mctrl = bfin_serial_set_mctrl,
|
||||
|
|
@ -1047,11 +1029,6 @@ static struct uart_ops bfin_serial_pops = {
|
|||
.request_port = bfin_serial_request_port,
|
||||
.config_port = bfin_serial_config_port,
|
||||
.verify_port = bfin_serial_verify_port,
|
||||
#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
|
||||
defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
|
||||
.kgdboc_port_startup = bfin_kgdboc_port_startup,
|
||||
.kgdboc_port_shutdown = bfin_kgdboc_port_shutdown,
|
||||
#endif
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_put_char = bfin_serial_poll_put_char,
|
||||
.poll_get_char = bfin_serial_poll_get_char,
|
||||
|
|
|
|||
|
|
@ -169,7 +169,6 @@ static int get_lsr_info(struct e100_serial *info, unsigned int *value);
|
|||
|
||||
|
||||
#define DEF_BAUD 115200 /* 115.2 kbit/s */
|
||||
#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
|
||||
#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */
|
||||
/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
|
||||
#define DEF_TX 0x80 /* or SERIAL_CTRL_B */
|
||||
|
|
@ -246,7 +245,6 @@ static struct e100_serial rs_table[] = {
|
|||
.ifirstadr = R_DMA_CH7_FIRST,
|
||||
.icmdadr = R_DMA_CH7_CMD,
|
||||
.idescradr = R_DMA_CH7_DESCR,
|
||||
.flags = STD_FLAGS,
|
||||
.rx_ctrl = DEF_RX,
|
||||
.tx_ctrl = DEF_TX,
|
||||
.iseteop = 2,
|
||||
|
|
@ -300,7 +298,6 @@ static struct e100_serial rs_table[] = {
|
|||
.ifirstadr = R_DMA_CH9_FIRST,
|
||||
.icmdadr = R_DMA_CH9_CMD,
|
||||
.idescradr = R_DMA_CH9_DESCR,
|
||||
.flags = STD_FLAGS,
|
||||
.rx_ctrl = DEF_RX,
|
||||
.tx_ctrl = DEF_TX,
|
||||
.iseteop = 3,
|
||||
|
|
@ -356,7 +353,6 @@ static struct e100_serial rs_table[] = {
|
|||
.ifirstadr = R_DMA_CH3_FIRST,
|
||||
.icmdadr = R_DMA_CH3_CMD,
|
||||
.idescradr = R_DMA_CH3_DESCR,
|
||||
.flags = STD_FLAGS,
|
||||
.rx_ctrl = DEF_RX,
|
||||
.tx_ctrl = DEF_TX,
|
||||
.iseteop = 0,
|
||||
|
|
@ -410,7 +406,6 @@ static struct e100_serial rs_table[] = {
|
|||
.ifirstadr = R_DMA_CH5_FIRST,
|
||||
.icmdadr = R_DMA_CH5_CMD,
|
||||
.idescradr = R_DMA_CH5_DESCR,
|
||||
.flags = STD_FLAGS,
|
||||
.rx_ctrl = DEF_RX,
|
||||
.tx_ctrl = DEF_TX,
|
||||
.iseteop = 1,
|
||||
|
|
@ -2263,8 +2258,7 @@ TODO: The break will be delayed until an F or V character is received.
|
|||
|
||||
*/
|
||||
|
||||
static
|
||||
struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
|
||||
static void handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
|
||||
{
|
||||
unsigned long data_read;
|
||||
|
||||
|
|
@ -2370,10 +2364,9 @@ more_data:
|
|||
}
|
||||
|
||||
tty_flip_buffer_push(&info->port);
|
||||
return info;
|
||||
}
|
||||
|
||||
static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
|
||||
static void handle_ser_rx_interrupt(struct e100_serial *info)
|
||||
{
|
||||
unsigned char rstat;
|
||||
|
||||
|
|
@ -2382,7 +2375,8 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
|
|||
#endif
|
||||
/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
|
||||
if (!info->uses_dma_in) {
|
||||
return handle_ser_rx_interrupt_no_dma(info);
|
||||
handle_ser_rx_interrupt_no_dma(info);
|
||||
return;
|
||||
}
|
||||
/* DMA is used */
|
||||
rstat = info->ioport[REG_STATUS];
|
||||
|
|
@ -2489,7 +2483,6 @@ static struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
|
|||
/* Restarting the DMA never hurts */
|
||||
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
|
||||
START_FLUSH_FAST_TIMER(info, "ser_int");
|
||||
return info;
|
||||
} /* handle_ser_rx_interrupt */
|
||||
|
||||
static void handle_ser_tx_interrupt(struct e100_serial *info)
|
||||
|
|
@ -2534,8 +2527,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)
|
|||
}
|
||||
/* Normal char-by-char interrupt */
|
||||
if (info->xmit.head == info->xmit.tail
|
||||
|| info->port.tty->stopped
|
||||
|| info->port.tty->hw_stopped) {
|
||||
|| info->port.tty->stopped) {
|
||||
DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n",
|
||||
info->port.tty->stopped));
|
||||
e100_disable_serial_tx_ready_irq(info);
|
||||
|
|
@ -2722,7 +2714,7 @@ startup(struct e100_serial * info)
|
|||
|
||||
/* if it was already initialized, skip this */
|
||||
|
||||
if (info->flags & ASYNC_INITIALIZED) {
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
local_irq_restore(flags);
|
||||
free_page(xmit_page);
|
||||
return 0;
|
||||
|
|
@ -2847,7 +2839,7 @@ startup(struct e100_serial * info)
|
|||
|
||||
#endif /* CONFIG_SVINTO_SIM */
|
||||
|
||||
info->flags |= ASYNC_INITIALIZED;
|
||||
info->port.flags |= ASYNC_INITIALIZED;
|
||||
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
|
|
@ -2892,7 +2884,7 @@ shutdown(struct e100_serial * info)
|
|||
|
||||
#endif /* CONFIG_SVINTO_SIM */
|
||||
|
||||
if (!(info->flags & ASYNC_INITIALIZED))
|
||||
if (!(info->port.flags & ASYNC_INITIALIZED))
|
||||
return;
|
||||
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
|
|
@ -2923,7 +2915,7 @@ shutdown(struct e100_serial * info)
|
|||
if (info->port.tty)
|
||||
set_bit(TTY_IO_ERROR, &info->port.tty->flags);
|
||||
|
||||
info->flags &= ~ASYNC_INITIALIZED;
|
||||
info->port.flags &= ~ASYNC_INITIALIZED;
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
|
|
@ -2948,7 +2940,7 @@ change_speed(struct e100_serial *info)
|
|||
/* possibly, the tx/rx should be disabled first to do this safely */
|
||||
|
||||
/* change baud-rate and write it to the hardware */
|
||||
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
|
||||
if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
|
||||
/* Special baudrate */
|
||||
u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
|
||||
unsigned long alt_source =
|
||||
|
|
@ -3098,7 +3090,6 @@ rs_flush_chars(struct tty_struct *tty)
|
|||
if (info->tr_running ||
|
||||
info->xmit.head == info->xmit.tail ||
|
||||
tty->stopped ||
|
||||
tty->hw_stopped ||
|
||||
!info->xmit.buf)
|
||||
return;
|
||||
|
||||
|
|
@ -3176,7 +3167,6 @@ static int rs_raw_write(struct tty_struct *tty,
|
|||
|
||||
if (info->xmit.head != info->xmit.tail &&
|
||||
!tty->stopped &&
|
||||
!tty->hw_stopped &&
|
||||
!info->tr_running) {
|
||||
start_transmit(info);
|
||||
}
|
||||
|
|
@ -3400,10 +3390,10 @@ get_serial_info(struct e100_serial * info,
|
|||
tmp.line = info->line;
|
||||
tmp.port = (int)info->ioport;
|
||||
tmp.irq = info->irq;
|
||||
tmp.flags = info->flags;
|
||||
tmp.flags = info->port.flags;
|
||||
tmp.baud_base = info->baud_base;
|
||||
tmp.close_delay = info->close_delay;
|
||||
tmp.closing_wait = info->closing_wait;
|
||||
tmp.close_delay = info->port.close_delay;
|
||||
tmp.closing_wait = info->port.closing_wait;
|
||||
tmp.custom_divisor = info->custom_divisor;
|
||||
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
|
||||
return -EFAULT;
|
||||
|
|
@ -3425,16 +3415,16 @@ set_serial_info(struct e100_serial *info,
|
|||
|
||||
if (!capable(CAP_SYS_ADMIN)) {
|
||||
if ((new_serial.type != info->type) ||
|
||||
(new_serial.close_delay != info->close_delay) ||
|
||||
(new_serial.close_delay != info->port.close_delay) ||
|
||||
((new_serial.flags & ~ASYNC_USR_MASK) !=
|
||||
(info->flags & ~ASYNC_USR_MASK)))
|
||||
(info->port.flags & ~ASYNC_USR_MASK)))
|
||||
return -EPERM;
|
||||
info->flags = ((info->flags & ~ASYNC_USR_MASK) |
|
||||
info->port.flags = ((info->port.flags & ~ASYNC_USR_MASK) |
|
||||
(new_serial.flags & ASYNC_USR_MASK));
|
||||
goto check_and_exit;
|
||||
}
|
||||
|
||||
if (info->count > 1)
|
||||
if (info->port.count > 1)
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
|
|
@ -3443,16 +3433,16 @@ set_serial_info(struct e100_serial *info,
|
|||
*/
|
||||
|
||||
info->baud_base = new_serial.baud_base;
|
||||
info->flags = ((info->flags & ~ASYNC_FLAGS) |
|
||||
info->port.flags = ((info->port.flags & ~ASYNC_FLAGS) |
|
||||
(new_serial.flags & ASYNC_FLAGS));
|
||||
info->custom_divisor = new_serial.custom_divisor;
|
||||
info->type = new_serial.type;
|
||||
info->close_delay = new_serial.close_delay;
|
||||
info->closing_wait = new_serial.closing_wait;
|
||||
info->port.low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
info->port.close_delay = new_serial.close_delay;
|
||||
info->port.closing_wait = new_serial.closing_wait;
|
||||
info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
|
||||
|
||||
check_and_exit:
|
||||
if (info->flags & ASYNC_INITIALIZED) {
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
change_speed(info);
|
||||
} else
|
||||
retval = startup(info);
|
||||
|
|
@ -3733,10 +3723,8 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
|||
|
||||
/* Handle turning off CRTSCTS */
|
||||
if ((old_termios->c_cflag & CRTSCTS) &&
|
||||
!(tty->termios.c_cflag & CRTSCTS)) {
|
||||
tty->hw_stopped = 0;
|
||||
!(tty->termios.c_cflag & CRTSCTS))
|
||||
rs_start(tty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -3772,7 +3760,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
|||
printk("[%d] rs_close ttyS%d, count = %d\n", current->pid,
|
||||
info->line, info->count);
|
||||
#endif
|
||||
if ((tty->count == 1) && (info->count != 1)) {
|
||||
if ((tty->count == 1) && (info->port.count != 1)) {
|
||||
/*
|
||||
* Uh, oh. tty->count is 1, which means that the tty
|
||||
* structure will be freed. Info->count should always
|
||||
|
|
@ -3782,32 +3770,32 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
|||
*/
|
||||
printk(KERN_ERR
|
||||
"rs_close: bad serial port count; tty->count is 1, "
|
||||
"info->count is %d\n", info->count);
|
||||
info->count = 1;
|
||||
"info->count is %d\n", info->port.count);
|
||||
info->port.count = 1;
|
||||
}
|
||||
if (--info->count < 0) {
|
||||
if (--info->port.count < 0) {
|
||||
printk(KERN_ERR "rs_close: bad serial port count for ttyS%d: %d\n",
|
||||
info->line, info->count);
|
||||
info->count = 0;
|
||||
info->line, info->port.count);
|
||||
info->port.count = 0;
|
||||
}
|
||||
if (info->count) {
|
||||
if (info->port.count) {
|
||||
local_irq_restore(flags);
|
||||
return;
|
||||
}
|
||||
info->flags |= ASYNC_CLOSING;
|
||||
info->port.flags |= ASYNC_CLOSING;
|
||||
/*
|
||||
* Save the termios structure, since this port may have
|
||||
* separate termios for callout and dialin.
|
||||
*/
|
||||
if (info->flags & ASYNC_NORMAL_ACTIVE)
|
||||
if (info->port.flags & ASYNC_NORMAL_ACTIVE)
|
||||
info->normal_termios = tty->termios;
|
||||
/*
|
||||
* Now we wait for the transmit buffer to clear; and we notify
|
||||
* the line discipline to only process XON/XOFF characters.
|
||||
*/
|
||||
tty->closing = 1;
|
||||
if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent(tty, info->closing_wait);
|
||||
if (info->port.closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent(tty, info->port.closing_wait);
|
||||
/*
|
||||
* At this point we stop accepting input. To do this, we
|
||||
* disable the serial receiver and the DMA receive interrupt.
|
||||
|
|
@ -3820,7 +3808,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
|||
e100_disable_rx(info);
|
||||
e100_disable_rx_irq(info);
|
||||
|
||||
if (info->flags & ASYNC_INITIALIZED) {
|
||||
if (info->port.flags & ASYNC_INITIALIZED) {
|
||||
/*
|
||||
* Before we drop DTR, make sure the UART transmitter
|
||||
* has completely drained; this is especially
|
||||
|
|
@ -3836,13 +3824,13 @@ rs_close(struct tty_struct *tty, struct file * filp)
|
|||
tty->closing = 0;
|
||||
info->event = 0;
|
||||
info->port.tty = NULL;
|
||||
if (info->blocked_open) {
|
||||
if (info->close_delay)
|
||||
schedule_timeout_interruptible(info->close_delay);
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
if (info->port.blocked_open) {
|
||||
if (info->port.close_delay)
|
||||
schedule_timeout_interruptible(info->port.close_delay);
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
}
|
||||
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||
wake_up_interruptible(&info->close_wait);
|
||||
info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
|
||||
wake_up_interruptible(&info->port.close_wait);
|
||||
local_irq_restore(flags);
|
||||
|
||||
/* port closed */
|
||||
|
|
@ -3935,10 +3923,10 @@ rs_hangup(struct tty_struct *tty)
|
|||
rs_flush_buffer(tty);
|
||||
shutdown(info);
|
||||
info->event = 0;
|
||||
info->count = 0;
|
||||
info->flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
info->port.count = 0;
|
||||
info->port.flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
info->port.tty = NULL;
|
||||
wake_up_interruptible(&info->open_wait);
|
||||
wake_up_interruptible(&info->port.open_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3960,11 +3948,11 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
* until it's done, and then try again.
|
||||
*/
|
||||
if (tty_hung_up_p(filp) ||
|
||||
(info->flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(tty, info->close_wait,
|
||||
!(info->flags & ASYNC_CLOSING));
|
||||
(info->port.flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
if (info->flags & ASYNC_HUP_NOTIFY)
|
||||
if (info->port.flags & ASYNC_HUP_NOTIFY)
|
||||
return -EAGAIN;
|
||||
else
|
||||
return -ERESTARTSYS;
|
||||
|
|
@ -3979,7 +3967,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
*/
|
||||
if ((filp->f_flags & O_NONBLOCK) ||
|
||||
(tty->flags & (1 << TTY_IO_ERROR))) {
|
||||
info->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
info->port.flags |= ASYNC_NORMAL_ACTIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3990,23 +3978,23 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
/*
|
||||
* Block waiting for the carrier detect and the line to become
|
||||
* free (i.e., not in use by the callout). While we are in
|
||||
* this loop, info->count is dropped by one, so that
|
||||
* this loop, info->port.count is dropped by one, so that
|
||||
* rs_close() knows when to free things. We restore it upon
|
||||
* exit, either normal or abnormal.
|
||||
*/
|
||||
retval = 0;
|
||||
add_wait_queue(&info->open_wait, &wait);
|
||||
add_wait_queue(&info->port.open_wait, &wait);
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
printk("block_til_ready before block: ttyS%d, count = %d\n",
|
||||
info->line, info->count);
|
||||
info->line, info->port.count);
|
||||
#endif
|
||||
local_irq_save(flags);
|
||||
if (!tty_hung_up_p(filp)) {
|
||||
extra_count++;
|
||||
info->count--;
|
||||
info->port.count--;
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
info->blocked_open++;
|
||||
info->port.blocked_open++;
|
||||
while (1) {
|
||||
local_irq_save(flags);
|
||||
/* assert RTS and DTR */
|
||||
|
|
@ -4015,9 +4003,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
local_irq_restore(flags);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (tty_hung_up_p(filp) ||
|
||||
!(info->flags & ASYNC_INITIALIZED)) {
|
||||
!(info->port.flags & ASYNC_INITIALIZED)) {
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
if (info->flags & ASYNC_HUP_NOTIFY)
|
||||
if (info->port.flags & ASYNC_HUP_NOTIFY)
|
||||
retval = -EAGAIN;
|
||||
else
|
||||
retval = -ERESTARTSYS;
|
||||
|
|
@ -4026,7 +4014,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
#endif
|
||||
break;
|
||||
}
|
||||
if (!(info->flags & ASYNC_CLOSING) && do_clocal)
|
||||
if (!(info->port.flags & ASYNC_CLOSING) && do_clocal)
|
||||
/* && (do_clocal || DCD_IS_ASSERTED) */
|
||||
break;
|
||||
if (signal_pending(current)) {
|
||||
|
|
@ -4035,24 +4023,24 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
}
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
printk("block_til_ready blocking: ttyS%d, count = %d\n",
|
||||
info->line, info->count);
|
||||
info->line, info->port.count);
|
||||
#endif
|
||||
tty_unlock(tty);
|
||||
schedule();
|
||||
tty_lock(tty);
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&info->open_wait, &wait);
|
||||
remove_wait_queue(&info->port.open_wait, &wait);
|
||||
if (extra_count)
|
||||
info->count++;
|
||||
info->blocked_open--;
|
||||
info->port.count++;
|
||||
info->port.blocked_open--;
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
printk("block_til_ready after blocking: ttyS%d, count = %d\n",
|
||||
info->line, info->count);
|
||||
info->line, info->port.count);
|
||||
#endif
|
||||
if (retval)
|
||||
return retval;
|
||||
info->flags |= ASYNC_NORMAL_ACTIVE;
|
||||
info->port.flags |= ASYNC_NORMAL_ACTIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -4086,24 +4074,24 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
|||
|
||||
#ifdef SERIAL_DEBUG_OPEN
|
||||
printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name,
|
||||
info->count);
|
||||
info->port.count);
|
||||
#endif
|
||||
|
||||
info->count++;
|
||||
info->port.count++;
|
||||
tty->driver_data = info;
|
||||
info->port.tty = tty;
|
||||
|
||||
info->port.low_latency = !!(info->flags & ASYNC_LOW_LATENCY);
|
||||
info->port.low_latency = !!(info->port.flags & ASYNC_LOW_LATENCY);
|
||||
|
||||
/*
|
||||
* If the port is in the middle of closing, bail out now
|
||||
*/
|
||||
if (tty_hung_up_p(filp) ||
|
||||
(info->flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(tty, info->close_wait,
|
||||
!(info->flags & ASYNC_CLOSING));
|
||||
(info->port.flags & ASYNC_CLOSING)) {
|
||||
wait_event_interruptible_tty(tty, info->port.close_wait,
|
||||
!(info->port.flags & ASYNC_CLOSING));
|
||||
#ifdef SERIAL_DO_RESTART
|
||||
return ((info->flags & ASYNC_HUP_NOTIFY) ?
|
||||
return ((info->port.flags & ASYNC_HUP_NOTIFY) ?
|
||||
-EAGAIN : -ERESTARTSYS);
|
||||
#else
|
||||
return -EAGAIN;
|
||||
|
|
@ -4113,7 +4101,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
|||
/*
|
||||
* If DMA is enabled try to allocate the irq's.
|
||||
*/
|
||||
if (info->count == 1) {
|
||||
if (info->port.count == 1) {
|
||||
allocated_resources = 1;
|
||||
if (info->dma_in_enabled) {
|
||||
if (request_irq(info->dma_in_irq_nbr,
|
||||
|
|
@ -4186,7 +4174,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
|||
if (allocated_resources)
|
||||
deinit_port(info);
|
||||
|
||||
/* FIXME Decrease count info->count here too? */
|
||||
/* FIXME Decrease count info->port.count here too? */
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -4203,7 +4191,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
|
|||
return retval;
|
||||
}
|
||||
|
||||
if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
|
||||
if ((info->port.count == 1) && (info->port.flags & ASYNC_SPLIT_TERMIOS)) {
|
||||
tty->termios = info->normal_termios;
|
||||
change_speed(info);
|
||||
}
|
||||
|
|
@ -4256,9 +4244,6 @@ static void seq_line_info(struct seq_file *m, struct e100_serial *info)
|
|||
if (info->port.tty->stopped)
|
||||
seq_printf(m, " stopped:%i",
|
||||
(int)info->port.tty->stopped);
|
||||
if (info->port.tty->hw_stopped)
|
||||
seq_printf(m, " hw_stopped:%i",
|
||||
(int)info->port.tty->hw_stopped);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
@ -4455,16 +4440,9 @@ static int __init rs_init(void)
|
|||
info->forced_eop = 0;
|
||||
info->baud_base = DEF_BAUD_BASE;
|
||||
info->custom_divisor = 0;
|
||||
info->flags = 0;
|
||||
info->close_delay = 5*HZ/10;
|
||||
info->closing_wait = 30*HZ;
|
||||
info->x_char = 0;
|
||||
info->event = 0;
|
||||
info->count = 0;
|
||||
info->blocked_open = 0;
|
||||
info->normal_termios = driver->init_termios;
|
||||
init_waitqueue_head(&info->open_wait);
|
||||
init_waitqueue_head(&info->close_wait);
|
||||
info->xmit.buf = NULL;
|
||||
info->xmit.tail = info->xmit.head = 0;
|
||||
info->first_recv_buffer = info->last_recv_buffer = NULL;
|
||||
|
|
|
|||
|
|
@ -53,8 +53,6 @@ struct e100_serial {
|
|||
volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */
|
||||
volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */
|
||||
|
||||
int flags; /* defined in tty.h */
|
||||
|
||||
u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
|
||||
u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
|
||||
u8 iseteop; /* bit number for R_SET_EOP for the input dma */
|
||||
|
|
@ -88,19 +86,10 @@ struct e100_serial {
|
|||
|
||||
volatile int tr_running; /* 1 if output is running */
|
||||
|
||||
struct tty_struct *tty;
|
||||
int read_status_mask;
|
||||
int ignore_status_mask;
|
||||
int x_char; /* xon/xoff character */
|
||||
int close_delay;
|
||||
unsigned short closing_wait;
|
||||
unsigned short closing_wait2;
|
||||
unsigned long event;
|
||||
unsigned long last_active;
|
||||
int line;
|
||||
int type; /* PORT_ETRAX */
|
||||
int count; /* # of fd on device */
|
||||
int blocked_open; /* # of blocked opens */
|
||||
struct circ_buf xmit;
|
||||
struct etrax_recv_buffer *first_recv_buffer;
|
||||
struct etrax_recv_buffer *last_recv_buffer;
|
||||
|
|
@ -110,9 +99,6 @@ struct e100_serial {
|
|||
struct work_struct work;
|
||||
struct async_icount icount; /* error-statistics etc.*/
|
||||
struct ktermios normal_termios;
|
||||
struct ktermios callout_termios;
|
||||
wait_queue_head_t open_wait;
|
||||
wait_queue_head_t close_wait;
|
||||
|
||||
unsigned long char_time_usec; /* The time for 1 char, in usecs */
|
||||
unsigned long flush_time_usec; /* How often we should flush */
|
||||
|
|
|
|||
|
|
@ -1415,8 +1415,7 @@ static int icom_alloc_adapter(struct icom_adapter
|
|||
struct icom_adapter *cur_adapter_entry;
|
||||
struct list_head *tmp;
|
||||
|
||||
icom_adapter = (struct icom_adapter *)
|
||||
kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
|
||||
icom_adapter = kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
|
||||
|
||||
if (!icom_adapter) {
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -269,23 +269,6 @@ static void mrdy_assert(struct ifx_spi_device *ifx_dev)
|
|||
mrdy_set_high(ifx_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_hangup - hang up an IFX device
|
||||
* @ifx_dev: our SPI device
|
||||
*
|
||||
* Hang up the tty attached to the IFX device if one is currently
|
||||
* open. If not take no action
|
||||
*/
|
||||
static void ifx_spi_ttyhangup(struct ifx_spi_device *ifx_dev)
|
||||
{
|
||||
struct tty_port *pport = &ifx_dev->tty_port;
|
||||
struct tty_struct *tty = tty_port_tty_get(pport);
|
||||
if (tty) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_timeout - SPI timeout
|
||||
* @arg: our SPI device
|
||||
|
|
@ -298,7 +281,7 @@ static void ifx_spi_timeout(unsigned long arg)
|
|||
struct ifx_spi_device *ifx_dev = (struct ifx_spi_device *)arg;
|
||||
|
||||
dev_warn(&ifx_dev->spi_dev->dev, "*** SPI Timeout ***");
|
||||
ifx_spi_ttyhangup(ifx_dev);
|
||||
tty_port_tty_hangup(&ifx_dev->tty_port, false);
|
||||
mrdy_set_low(ifx_dev);
|
||||
clear_bit(IFX_SPI_STATE_TIMER_PENDING, &ifx_dev->flags);
|
||||
}
|
||||
|
|
@ -442,25 +425,6 @@ static void ifx_spi_setup_spi_header(unsigned char *txbuffer, int tx_count,
|
|||
txbuffer[1] |= (more << IFX_SPI_MORE_BIT) & IFX_SPI_MORE_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_wakeup_serial - SPI space made
|
||||
* @port_data: our SPI device
|
||||
*
|
||||
* We have emptied the FIFO enough that we want to get more data
|
||||
* queued into it. Poke the line discipline via tty_wakeup so that
|
||||
* it will feed us more bits
|
||||
*/
|
||||
static void ifx_spi_wakeup_serial(struct ifx_spi_device *ifx_dev)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
|
||||
tty = tty_port_tty_get(&ifx_dev->tty_port);
|
||||
if (!tty)
|
||||
return;
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_prepare_tx_buffer - prepare transmit frame
|
||||
* @ifx_dev: our SPI device
|
||||
|
|
@ -506,7 +470,7 @@ static int ifx_spi_prepare_tx_buffer(struct ifx_spi_device *ifx_dev)
|
|||
tx_count += temp_count;
|
||||
if (temp_count == queue_length)
|
||||
/* poke port to get more data */
|
||||
ifx_spi_wakeup_serial(ifx_dev);
|
||||
tty_port_tty_wakeup(&ifx_dev->tty_port);
|
||||
else /* more data in port, use next SPI message */
|
||||
ifx_dev->spi_more = 1;
|
||||
}
|
||||
|
|
@ -683,8 +647,6 @@ static void ifx_spi_insert_flip_string(struct ifx_spi_device *ifx_dev,
|
|||
static void ifx_spi_complete(void *ctx)
|
||||
{
|
||||
struct ifx_spi_device *ifx_dev = ctx;
|
||||
struct tty_struct *tty;
|
||||
struct tty_ldisc *ldisc = NULL;
|
||||
int length;
|
||||
int actual_length;
|
||||
unsigned char more;
|
||||
|
|
@ -762,15 +724,7 @@ complete_exit:
|
|||
*/
|
||||
ifx_spi_power_state_clear(ifx_dev,
|
||||
IFX_SPI_POWER_DATA_PENDING);
|
||||
tty = tty_port_tty_get(&ifx_dev->tty_port);
|
||||
if (tty) {
|
||||
ldisc = tty_ldisc_ref(tty);
|
||||
if (ldisc) {
|
||||
ldisc->ops->write_wakeup(tty);
|
||||
tty_ldisc_deref(ldisc);
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
tty_port_tty_wakeup(&ifx_dev->tty_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -962,7 +916,7 @@ static irqreturn_t ifx_spi_reset_interrupt(int irq, void *dev)
|
|||
set_bit(MR_INPROGRESS, &ifx_dev->mdm_reset_state);
|
||||
if (!solreset) {
|
||||
/* unsolicited reset */
|
||||
ifx_spi_ttyhangup(ifx_dev);
|
||||
tty_port_tty_hangup(&ifx_dev->tty_port, false);
|
||||
}
|
||||
} else {
|
||||
/* exited reset */
|
||||
|
|
@ -1324,30 +1278,6 @@ static void ifx_spi_spi_shutdown(struct spi_device *spi)
|
|||
* no hardware to save state for
|
||||
*/
|
||||
|
||||
/**
|
||||
* ifx_spi_spi_suspend - suspend SPI on system suspend
|
||||
* @dev: device being suspended
|
||||
*
|
||||
* Suspend the SPI side. No action needed on Intel MID platforms, may
|
||||
* need extending for other systems.
|
||||
*/
|
||||
static int ifx_spi_spi_suspend(struct spi_device *spi, pm_message_t msg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_spi_resume - resume SPI side on system resume
|
||||
* @dev: device being suspended
|
||||
*
|
||||
* Suspend the SPI side. No action needed on Intel MID platforms, may
|
||||
* need extending for other systems.
|
||||
*/
|
||||
static int ifx_spi_spi_resume(struct spi_device *spi)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ifx_spi_pm_suspend - suspend modem on system suspend
|
||||
* @dev: device being suspended
|
||||
|
|
@ -1437,8 +1367,6 @@ static struct spi_driver ifx_spi_driver = {
|
|||
.probe = ifx_spi_spi_probe,
|
||||
.shutdown = ifx_spi_spi_shutdown,
|
||||
.remove = ifx_spi_spi_remove,
|
||||
.suspend = ifx_spi_spi_suspend,
|
||||
.resume = ifx_spi_spi_resume,
|
||||
.id_table = ifx_id_table
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -761,6 +761,8 @@ static int imx_startup(struct uart_port *port)
|
|||
|
||||
temp = readl(sport->port.membase + UCR2);
|
||||
temp |= (UCR2_RXEN | UCR2_TXEN);
|
||||
if (!sport->have_rtscts)
|
||||
temp |= UCR2_IRTS;
|
||||
writel(temp, sport->port.membase + UCR2);
|
||||
|
||||
if (USE_IRDA(sport)) {
|
||||
|
|
|
|||
|
|
@ -596,12 +596,6 @@ void jsm_input(struct jsm_channel *ch)
|
|||
|
||||
jsm_dbg(READ, &ch->ch_bd->pci_dev, "start 2\n");
|
||||
|
||||
if (data_len <= 0) {
|
||||
spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
|
||||
jsm_dbg(READ, &ch->ch_bd->pci_dev, "jsm_input 1\n");
|
||||
return;
|
||||
}
|
||||
|
||||
len = tty_buffer_request_room(port, data_len);
|
||||
n = len;
|
||||
|
||||
|
|
|
|||
|
|
@ -778,7 +778,7 @@ static int max3100_probe(struct spi_device *spi)
|
|||
max3100s[i]->spi = spi;
|
||||
max3100s[i]->irq = spi->irq;
|
||||
spin_lock_init(&max3100s[i]->conf_lock);
|
||||
dev_set_drvdata(&spi->dev, max3100s[i]);
|
||||
spi_set_drvdata(spi, max3100s[i]);
|
||||
pdata = spi->dev.platform_data;
|
||||
max3100s[i]->crystal = pdata->crystal;
|
||||
max3100s[i]->loopback = pdata->loopback;
|
||||
|
|
@ -819,7 +819,7 @@ static int max3100_probe(struct spi_device *spi)
|
|||
|
||||
static int max3100_remove(struct spi_device *spi)
|
||||
{
|
||||
struct max3100_port *s = dev_get_drvdata(&spi->dev);
|
||||
struct max3100_port *s = spi_get_drvdata(spi);
|
||||
int i;
|
||||
|
||||
mutex_lock(&max3100s_lock);
|
||||
|
|
@ -849,11 +849,11 @@ static int max3100_remove(struct spi_device *spi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int max3100_suspend(struct spi_device *spi, pm_message_t state)
|
||||
static int max3100_suspend(struct device *dev)
|
||||
{
|
||||
struct max3100_port *s = dev_get_drvdata(&spi->dev);
|
||||
struct max3100_port *s = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
|
|
@ -874,9 +874,9 @@ static int max3100_suspend(struct spi_device *spi, pm_message_t state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int max3100_resume(struct spi_device *spi)
|
||||
static int max3100_resume(struct device *dev)
|
||||
{
|
||||
struct max3100_port *s = dev_get_drvdata(&spi->dev);
|
||||
struct max3100_port *s = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(&s->spi->dev, "%s\n", __func__);
|
||||
|
||||
|
|
@ -894,21 +894,21 @@ static int max3100_resume(struct spi_device *spi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume);
|
||||
#define MAX3100_PM_OPS (&max3100_pm_ops)
|
||||
|
||||
#else
|
||||
#define max3100_suspend NULL
|
||||
#define max3100_resume NULL
|
||||
#define MAX3100_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct spi_driver max3100_driver = {
|
||||
.driver = {
|
||||
.name = "max3100",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = MAX3100_PM_OPS,
|
||||
},
|
||||
|
||||
.probe = max3100_probe,
|
||||
.remove = max3100_remove,
|
||||
.suspend = max3100_suspend,
|
||||
.resume = max3100_resume,
|
||||
};
|
||||
|
||||
module_spi_driver(max3100_driver);
|
||||
|
|
|
|||
|
|
@ -881,12 +881,14 @@ static struct uart_ops max310x_ops = {
|
|||
.verify_port = max310x_verify_port,
|
||||
};
|
||||
|
||||
static int max310x_suspend(struct spi_device *spi, pm_message_t state)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static int max310x_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct max310x_port *s = dev_get_drvdata(&spi->dev);
|
||||
struct max310x_port *s = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(&spi->dev, "Suspend\n");
|
||||
dev_dbg(dev, "Suspend\n");
|
||||
|
||||
ret = uart_suspend_port(&s->uart, &s->port);
|
||||
|
||||
|
|
@ -905,11 +907,11 @@ static int max310x_suspend(struct spi_device *spi, pm_message_t state)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int max310x_resume(struct spi_device *spi)
|
||||
static int max310x_resume(struct device *dev)
|
||||
{
|
||||
struct max310x_port *s = dev_get_drvdata(&spi->dev);
|
||||
struct max310x_port *s = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(&spi->dev, "Resume\n");
|
||||
dev_dbg(dev, "Resume\n");
|
||||
|
||||
if (s->pdata->suspend)
|
||||
s->pdata->suspend(0);
|
||||
|
|
@ -928,6 +930,13 @@ static int max310x_resume(struct spi_device *spi)
|
|||
return uart_resume_port(&s->uart, &s->port);
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
|
||||
#define MAX310X_PM_OPS (&max310x_pm_ops)
|
||||
|
||||
#else
|
||||
#define MAX310X_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
|
|
@ -1242,11 +1251,10 @@ static struct spi_driver max310x_driver = {
|
|||
.driver = {
|
||||
.name = "max310x",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = MAX310X_PM_OPS,
|
||||
},
|
||||
.probe = max310x_probe,
|
||||
.remove = max310x_remove,
|
||||
.suspend = max310x_suspend,
|
||||
.resume = max310x_resume,
|
||||
.id_table = max310x_id_table,
|
||||
};
|
||||
module_spi_driver(max310x_driver);
|
||||
|
|
|
|||
|
|
@ -707,8 +707,10 @@ static int __init mcf_init(void)
|
|||
if (rc)
|
||||
return rc;
|
||||
rc = platform_driver_register(&mcf_platform_driver);
|
||||
if (rc)
|
||||
if (rc) {
|
||||
uart_unregister_driver(&mcf_driver);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1497,18 +1497,23 @@ mpc52xx_uart_init(void)
|
|||
if (psc_ops && psc_ops->fifoc_init) {
|
||||
ret = psc_ops->fifoc_init();
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
ret = platform_driver_register(&mpc52xx_uart_of_driver);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
|
||||
__FILE__, ret);
|
||||
uart_unregister_driver(&mpc52xx_uart_driver);
|
||||
return ret;
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_reg:
|
||||
if (psc_ops && psc_ops->fifoc_uninit)
|
||||
psc_ops->fifoc_uninit();
|
||||
err_init:
|
||||
uart_unregister_driver(&mpc52xx_uart_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
|
|
|
|||
|
|
@ -743,9 +743,10 @@ static struct uart_driver serial_m3110_reg = {
|
|||
.cons = &serial_m3110_console,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int serial_m3110_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
struct uart_max3110 *max = spi_get_drvdata(spi);
|
||||
|
||||
disable_irq(max->irq);
|
||||
|
|
@ -754,8 +755,9 @@ static int serial_m3110_suspend(struct spi_device *spi, pm_message_t state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int serial_m3110_resume(struct spi_device *spi)
|
||||
static int serial_m3110_resume(struct device *dev)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
struct uart_max3110 *max = spi_get_drvdata(spi);
|
||||
|
||||
max3110_out(max, max->cur_conf);
|
||||
|
|
@ -763,9 +765,13 @@ static int serial_m3110_resume(struct spi_device *spi)
|
|||
enable_irq(max->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(serial_m3110_pm_ops, serial_m3110_suspend,
|
||||
serial_m3110_resume);
|
||||
#define SERIAL_M3110_PM_OPS (&serial_m3110_pm_ops)
|
||||
|
||||
#else
|
||||
#define serial_m3110_suspend NULL
|
||||
#define serial_m3110_resume NULL
|
||||
#define SERIAL_M3110_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static int serial_m3110_probe(struct spi_device *spi)
|
||||
|
|
@ -872,11 +878,10 @@ static struct spi_driver uart_max3110_driver = {
|
|||
.driver = {
|
||||
.name = "spi_max3111",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = SERIAL_M3110_PM_OPS,
|
||||
},
|
||||
.probe = serial_m3110_probe,
|
||||
.remove = serial_m3110_remove,
|
||||
.suspend = serial_m3110_suspend,
|
||||
.resume = serial_m3110_resume,
|
||||
};
|
||||
|
||||
static int __init serial_m3110_init(void)
|
||||
|
|
|
|||
|
|
@ -907,7 +907,6 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
|
|||
unsigned int error_f = 0;
|
||||
unsigned long flags;
|
||||
unsigned int flush;
|
||||
struct tty_struct *tty;
|
||||
struct tty_port *port;
|
||||
struct uart_port *uport;
|
||||
struct msm_hs_port *msm_uport;
|
||||
|
|
@ -919,7 +918,6 @@ static void msm_hs_dmov_rx_callback(struct msm_dmov_cmd *cmd_ptr,
|
|||
clk_enable(msm_uport->clk);
|
||||
|
||||
port = &uport->state->port;
|
||||
tty = port->tty;
|
||||
|
||||
msm_hs_write(uport, UARTDM_CR_ADDR, STALE_EVENT_DISABLE);
|
||||
|
||||
|
|
|
|||
|
|
@ -90,13 +90,13 @@ static void smd_tty_notify(void *priv, unsigned event)
|
|||
|
||||
static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)
|
||||
{
|
||||
struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
|
||||
port);
|
||||
int i, res = 0;
|
||||
int n = tty->index;
|
||||
const char *name = NULL;
|
||||
struct smd_tty_info *info = smd_tty + n;
|
||||
|
||||
for (i = 0; i < smd_tty_channels_len; i++) {
|
||||
if (smd_tty_channels[i].id == n) {
|
||||
if (smd_tty_channels[i].id == tty->index) {
|
||||
name = smd_tty_channels[i].name;
|
||||
break;
|
||||
}
|
||||
|
|
@ -117,17 +117,13 @@ static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty)
|
|||
|
||||
static void smd_tty_port_shutdown(struct tty_port *tport)
|
||||
{
|
||||
struct smd_tty_info *info;
|
||||
struct tty_struct *tty = tty_port_tty_get(tport);
|
||||
struct smd_tty_info *info = container_of(tport, struct smd_tty_info,
|
||||
port);
|
||||
|
||||
info = tty->driver_data;
|
||||
if (info->ch) {
|
||||
smd_close(info->ch);
|
||||
info->ch = 0;
|
||||
}
|
||||
|
||||
tty->driver_data = 0;
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
static int smd_tty_open(struct tty_struct *tty, struct file *f)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/fsl/mxs-dma.h>
|
||||
#include <linux/dmaengine.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
|
|
@ -148,11 +148,6 @@ struct mxs_auart_port {
|
|||
struct device *dev;
|
||||
|
||||
/* for DMA */
|
||||
struct mxs_dma_data dma_data;
|
||||
int dma_channel_rx, dma_channel_tx;
|
||||
int dma_irq_rx, dma_irq_tx;
|
||||
int dma_channel;
|
||||
|
||||
struct scatterlist tx_sgl;
|
||||
struct dma_chan *tx_dma_chan;
|
||||
void *tx_dma_buf;
|
||||
|
|
@ -440,20 +435,6 @@ static u32 mxs_auart_get_mctrl(struct uart_port *u)
|
|||
return mctrl;
|
||||
}
|
||||
|
||||
static bool mxs_auart_dma_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct mxs_auart_port *s = param;
|
||||
|
||||
if (!mxs_dma_is_apbx(chan))
|
||||
return false;
|
||||
|
||||
if (s->dma_channel == chan->chan_id) {
|
||||
chan->private = &s->dma_data;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int mxs_auart_dma_prep_rx(struct mxs_auart_port *s);
|
||||
static void dma_rx_callback(void *arg)
|
||||
{
|
||||
|
|
@ -545,21 +526,11 @@ static void mxs_auart_dma_exit(struct mxs_auart_port *s)
|
|||
|
||||
static int mxs_auart_dma_init(struct mxs_auart_port *s)
|
||||
{
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
if (auart_dma_enabled(s))
|
||||
return 0;
|
||||
|
||||
/* We do not get the right DMA channels. */
|
||||
if (s->dma_channel_rx == -1 || s->dma_channel_tx == -1)
|
||||
return -EINVAL;
|
||||
|
||||
/* init for RX */
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
s->dma_channel = s->dma_channel_rx;
|
||||
s->dma_data.chan_irq = s->dma_irq_rx;
|
||||
s->rx_dma_chan = dma_request_channel(mask, mxs_auart_dma_filter, s);
|
||||
s->rx_dma_chan = dma_request_slave_channel(s->dev, "rx");
|
||||
if (!s->rx_dma_chan)
|
||||
goto err_out;
|
||||
s->rx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
|
|
@ -567,9 +538,7 @@ static int mxs_auart_dma_init(struct mxs_auart_port *s)
|
|||
goto err_out;
|
||||
|
||||
/* init for TX */
|
||||
s->dma_channel = s->dma_channel_tx;
|
||||
s->dma_data.chan_irq = s->dma_irq_tx;
|
||||
s->tx_dma_chan = dma_request_channel(mask, mxs_auart_dma_filter, s);
|
||||
s->tx_dma_chan = dma_request_slave_channel(s->dev, "tx");
|
||||
if (!s->tx_dma_chan)
|
||||
goto err_out;
|
||||
s->tx_dma_buf = kzalloc(UART_XMIT_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
|
|
@ -883,7 +852,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
|
|||
unsigned int old_ctrl0, old_ctrl2;
|
||||
unsigned int to = 1000;
|
||||
|
||||
if (co->index > MXS_AUART_PORTS || co->index < 0)
|
||||
if (co->index >= MXS_AUART_PORTS || co->index < 0)
|
||||
return;
|
||||
|
||||
s = auart_port[co->index];
|
||||
|
|
@ -1020,7 +989,6 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
|
|||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 dma_channel[2];
|
||||
int ret;
|
||||
|
||||
if (!np)
|
||||
|
|
@ -1034,20 +1002,8 @@ static int serial_mxs_probe_dt(struct mxs_auart_port *s,
|
|||
}
|
||||
s->port.line = ret;
|
||||
|
||||
s->dma_irq_rx = platform_get_irq(pdev, 1);
|
||||
s->dma_irq_tx = platform_get_irq(pdev, 2);
|
||||
s->flags |= MXS_AUART_DMA_CONFIG;
|
||||
|
||||
ret = of_property_read_u32_array(np, "fsl,auart-dma-channel",
|
||||
dma_channel, 2);
|
||||
if (ret == 0) {
|
||||
s->dma_channel_rx = dma_channel[0];
|
||||
s->dma_channel_tx = dma_channel[1];
|
||||
|
||||
s->flags |= MXS_AUART_DMA_CONFIG;
|
||||
} else {
|
||||
s->dma_channel_rx = -1;
|
||||
s->dma_channel_tx = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1103,7 +1059,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
|
|||
s->port.fifosize = 16;
|
||||
s->port.uartclk = clk_get_rate(s->clk);
|
||||
s->port.type = PORT_IMX;
|
||||
s->port.dev = s->dev = get_device(&pdev->dev);
|
||||
s->port.dev = s->dev = &pdev->dev;
|
||||
|
||||
s->ctrl = 0;
|
||||
|
||||
|
|
@ -1134,7 +1090,6 @@ out_free_irq:
|
|||
auart_port[pdev->id] = NULL;
|
||||
free_irq(s->irq, s);
|
||||
out_free_clk:
|
||||
put_device(s->dev);
|
||||
clk_put(s->clk);
|
||||
out_free:
|
||||
kfree(s);
|
||||
|
|
@ -1150,7 +1105,6 @@ static int mxs_auart_remove(struct platform_device *pdev)
|
|||
|
||||
auart_port[pdev->id] = NULL;
|
||||
|
||||
put_device(s->dev);
|
||||
clk_put(s->clk);
|
||||
free_irq(s->irq, s);
|
||||
kfree(s);
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ static void nwpserial_shutdown(struct uart_port *port)
|
|||
dcr_write(up->dcr_host, UART_IER, up->ier);
|
||||
|
||||
/* free irq */
|
||||
free_irq(up->port.irq, port);
|
||||
free_irq(up->port.irq, up);
|
||||
}
|
||||
|
||||
static int nwpserial_verify_port(struct uart_port *port,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
|
|
@ -22,6 +21,8 @@
|
|||
#include <linux/nwpserial.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include "8250/8250.h"
|
||||
|
||||
struct of_serial_info {
|
||||
struct clk *clk;
|
||||
int type;
|
||||
|
|
@ -97,6 +98,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
|||
if (of_property_read_u32(np, "reg-shift", &prop) == 0)
|
||||
port->regshift = prop;
|
||||
|
||||
/* Check for fifo size */
|
||||
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
|
||||
port->fifosize = prop;
|
||||
|
||||
port->irq = irq_of_parse_and_map(np, 0);
|
||||
port->iotype = UPIO_MEM;
|
||||
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
|
||||
|
|
@ -167,11 +172,17 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
|
|||
#ifdef CONFIG_SERIAL_8250
|
||||
case PORT_8250 ... PORT_MAX_8250:
|
||||
{
|
||||
/* For now the of bindings don't support the extra
|
||||
8250 specific bits */
|
||||
struct uart_8250_port port8250;
|
||||
memset(&port8250, 0, sizeof(port8250));
|
||||
port8250.port = port;
|
||||
|
||||
if (port.fifosize)
|
||||
port8250.capabilities = UART_CAP_FIFO;
|
||||
|
||||
if (of_property_read_bool(ofdev->dev.of_node,
|
||||
"auto-flow-control"))
|
||||
port8250.capabilities |= UART_CAP_AFE;
|
||||
|
||||
ret = serial8250_register_8250_port(&port8250);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,26 +202,6 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up)
|
|||
return pdata->get_context_loss_count(up->dev);
|
||||
}
|
||||
|
||||
static void serial_omap_set_forceidle(struct uart_omap_port *up)
|
||||
{
|
||||
struct omap_uart_port_info *pdata = up->dev->platform_data;
|
||||
|
||||
if (!pdata || !pdata->set_forceidle)
|
||||
return;
|
||||
|
||||
pdata->set_forceidle(up->dev);
|
||||
}
|
||||
|
||||
static void serial_omap_set_noidle(struct uart_omap_port *up)
|
||||
{
|
||||
struct omap_uart_port_info *pdata = up->dev->platform_data;
|
||||
|
||||
if (!pdata || !pdata->set_noidle)
|
||||
return;
|
||||
|
||||
pdata->set_noidle(up->dev);
|
||||
}
|
||||
|
||||
static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable)
|
||||
{
|
||||
struct omap_uart_port_info *pdata = up->dev->platform_data;
|
||||
|
|
@ -298,8 +278,6 @@ static void serial_omap_stop_tx(struct uart_port *port)
|
|||
serial_out(up, UART_IER, up->ier);
|
||||
}
|
||||
|
||||
serial_omap_set_forceidle(up);
|
||||
|
||||
pm_runtime_mark_last_busy(up->dev);
|
||||
pm_runtime_put_autosuspend(up->dev);
|
||||
}
|
||||
|
|
@ -364,7 +342,6 @@ static void serial_omap_start_tx(struct uart_port *port)
|
|||
|
||||
pm_runtime_get_sync(up->dev);
|
||||
serial_omap_enable_ier_thri(up);
|
||||
serial_omap_set_noidle(up);
|
||||
pm_runtime_mark_last_busy(up->dev);
|
||||
pm_runtime_put_autosuspend(up->dev);
|
||||
}
|
||||
|
|
@ -886,6 +863,17 @@ 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;
|
||||
/*
|
||||
* NOTE: Setting OMAP_UART_SCR_RX_TRIG_GRANU1_MASK
|
||||
* sets Enables the granularity of 1 for TRIGGER RX
|
||||
* level. Along with setting RX FIFO trigger level
|
||||
* to 1 (as noted below, 16 characters) and TLR[3:0]
|
||||
* to zero this will result RX FIFO threshold level
|
||||
* to 1 character, instead of 16 as noted in comment
|
||||
* below.
|
||||
*/
|
||||
|
||||
/* Set receive FIFO threshold to 16 characters and
|
||||
* transmit FIFO threshold to 16 spaces
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1493,29 +1493,6 @@ static int pch_uart_verify_port(struct uart_port *port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct uart_ops pch_uart_ops = {
|
||||
.tx_empty = pch_uart_tx_empty,
|
||||
.set_mctrl = pch_uart_set_mctrl,
|
||||
.get_mctrl = pch_uart_get_mctrl,
|
||||
.stop_tx = pch_uart_stop_tx,
|
||||
.start_tx = pch_uart_start_tx,
|
||||
.stop_rx = pch_uart_stop_rx,
|
||||
.enable_ms = pch_uart_enable_ms,
|
||||
.break_ctl = pch_uart_break_ctl,
|
||||
.startup = pch_uart_startup,
|
||||
.shutdown = pch_uart_shutdown,
|
||||
.set_termios = pch_uart_set_termios,
|
||||
/* .pm = pch_uart_pm, Not supported yet */
|
||||
/* .set_wake = pch_uart_set_wake, Not supported yet */
|
||||
.type = pch_uart_type,
|
||||
.release_port = pch_uart_release_port,
|
||||
.request_port = pch_uart_request_port,
|
||||
.config_port = pch_uart_config_port,
|
||||
.verify_port = pch_uart_verify_port
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
|
||||
|
||||
/*
|
||||
* Wait for transmitter & holding register to empty
|
||||
*/
|
||||
|
|
@ -1547,6 +1524,84 @@ static void wait_for_xmitr(struct eg20t_port *up, int bits)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
/*
|
||||
* Console polling routines for communicate via uart while
|
||||
* in an interrupt or debug context.
|
||||
*/
|
||||
static int pch_uart_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
struct eg20t_port *priv =
|
||||
container_of(port, struct eg20t_port, port);
|
||||
u8 lsr = ioread8(priv->membase + UART_LSR);
|
||||
|
||||
if (!(lsr & UART_LSR_DR))
|
||||
return NO_POLL_CHAR;
|
||||
|
||||
return ioread8(priv->membase + PCH_UART_RBR);
|
||||
}
|
||||
|
||||
|
||||
static void pch_uart_put_poll_char(struct uart_port *port,
|
||||
unsigned char c)
|
||||
{
|
||||
unsigned int ier;
|
||||
struct eg20t_port *priv =
|
||||
container_of(port, struct eg20t_port, port);
|
||||
|
||||
/*
|
||||
* First save the IER then disable the interrupts
|
||||
*/
|
||||
ier = ioread8(priv->membase + UART_IER);
|
||||
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_ALL_INT);
|
||||
|
||||
wait_for_xmitr(priv, UART_LSR_THRE);
|
||||
/*
|
||||
* Send the character out.
|
||||
* If a LF, also do CR...
|
||||
*/
|
||||
iowrite8(c, priv->membase + PCH_UART_THR);
|
||||
if (c == 10) {
|
||||
wait_for_xmitr(priv, UART_LSR_THRE);
|
||||
iowrite8(13, priv->membase + PCH_UART_THR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finally, wait for transmitter to become empty
|
||||
* and restore the IER
|
||||
*/
|
||||
wait_for_xmitr(priv, BOTH_EMPTY);
|
||||
iowrite8(ier, priv->membase + UART_IER);
|
||||
}
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
|
||||
static struct uart_ops pch_uart_ops = {
|
||||
.tx_empty = pch_uart_tx_empty,
|
||||
.set_mctrl = pch_uart_set_mctrl,
|
||||
.get_mctrl = pch_uart_get_mctrl,
|
||||
.stop_tx = pch_uart_stop_tx,
|
||||
.start_tx = pch_uart_start_tx,
|
||||
.stop_rx = pch_uart_stop_rx,
|
||||
.enable_ms = pch_uart_enable_ms,
|
||||
.break_ctl = pch_uart_break_ctl,
|
||||
.startup = pch_uart_startup,
|
||||
.shutdown = pch_uart_shutdown,
|
||||
.set_termios = pch_uart_set_termios,
|
||||
/* .pm = pch_uart_pm, Not supported yet */
|
||||
/* .set_wake = pch_uart_set_wake, Not supported yet */
|
||||
.type = pch_uart_type,
|
||||
.release_port = pch_uart_release_port,
|
||||
.request_port = pch_uart_request_port,
|
||||
.config_port = pch_uart_config_port,
|
||||
.verify_port = pch_uart_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
.poll_get_char = pch_uart_get_poll_char,
|
||||
.poll_put_char = pch_uart_put_poll_char,
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
|
||||
|
||||
static void pch_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
struct eg20t_port *priv =
|
||||
|
|
@ -1655,7 +1710,7 @@ static struct console pch_console = {
|
|||
#define PCH_CONSOLE (&pch_console)
|
||||
#else
|
||||
#define PCH_CONSOLE NULL
|
||||
#endif
|
||||
#endif /* CONFIG_SERIAL_PCH_UART_CONSOLE */
|
||||
|
||||
static struct uart_driver pch_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@
|
|||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_s3c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/cpufreq.h>
|
||||
|
|
@ -46,10 +47,9 @@
|
|||
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
|
||||
#include <plat/regs-serial.h>
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
#include <plat/clock.h>
|
||||
#endif
|
||||
|
||||
#include "samsung.h"
|
||||
|
||||
|
|
@ -446,6 +446,8 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
|
|||
|
||||
/* Clear pending interrupts and mask all interrupts */
|
||||
if (s3c24xx_serial_has_interrupt_mask(port)) {
|
||||
free_irq(port->irq, ourport);
|
||||
|
||||
wr_regl(port, S3C64XX_UINTP, 0xf);
|
||||
wr_regl(port, S3C64XX_UINTM, 0xf);
|
||||
}
|
||||
|
|
@ -505,6 +507,8 @@ static int s3c64xx_serial_startup(struct uart_port *port)
|
|||
dbg("s3c64xx_serial_startup: port=%p (%08lx,%p)\n",
|
||||
port->mapbase, port->membase);
|
||||
|
||||
wr_regl(port, S3C64XX_UINTM, 0xf);
|
||||
|
||||
ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
|
||||
s3c24xx_serial_portname(port), ourport);
|
||||
if (ret) {
|
||||
|
|
@ -894,7 +898,7 @@ console_initcall(s3c24xx_serial_console_init);
|
|||
#define S3C24XX_SERIAL_CONSOLE NULL
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
|
||||
static int s3c24xx_serial_get_poll_char(struct uart_port *port);
|
||||
static void s3c24xx_serial_put_poll_char(struct uart_port *port,
|
||||
unsigned char c);
|
||||
|
|
@ -918,7 +922,7 @@ static struct uart_ops s3c24xx_serial_ops = {
|
|||
.request_port = s3c24xx_serial_request_port,
|
||||
.config_port = s3c24xx_serial_config_port,
|
||||
.verify_port = s3c24xx_serial_verify_port,
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
#if defined(CONFIG_SERIAL_SAMSUNG_CONSOLE) && defined(CONFIG_CONSOLE_POLL)
|
||||
.poll_get_char = s3c24xx_serial_get_poll_char,
|
||||
.poll_put_char = s3c24xx_serial_put_poll_char,
|
||||
#endif
|
||||
|
|
@ -1162,6 +1166,18 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
|||
ourport->tx_irq = ret;
|
||||
|
||||
ourport->clk = clk_get(&platdev->dev, "uart");
|
||||
if (IS_ERR(ourport->clk)) {
|
||||
pr_err("%s: Controller clock not found\n",
|
||||
dev_name(&platdev->dev));
|
||||
return PTR_ERR(ourport->clk);
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ourport->clk);
|
||||
if (ret) {
|
||||
pr_err("uart: clock failed to prepare+enable: %d\n", ret);
|
||||
clk_put(ourport->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Keep all interrupts masked and cleared */
|
||||
if (s3c24xx_serial_has_interrupt_mask(port)) {
|
||||
|
|
@ -1176,9 +1192,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
|
|||
|
||||
/* reset the fifos (and setup the uart) */
|
||||
s3c24xx_serial_resetport(port, cfg);
|
||||
clk_disable_unprepare(ourport->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
|
|
@ -1194,7 +1212,7 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
|
|||
}
|
||||
|
||||
static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
|
||||
|
||||
#endif
|
||||
|
||||
/* Device driver serial port probe */
|
||||
|
||||
|
|
@ -1252,9 +1270,11 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
|||
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
|
||||
platform_set_drvdata(pdev, &ourport->port);
|
||||
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
ret = device_create_file(&pdev->dev, &dev_attr_clock_source);
|
||||
if (ret < 0)
|
||||
dev_err(&pdev->dev, "failed to add clock source attr.\n");
|
||||
#endif
|
||||
|
||||
ret = s3c24xx_serial_cpufreq_register(ourport);
|
||||
if (ret < 0)
|
||||
|
|
@ -1272,7 +1292,9 @@ static int s3c24xx_serial_remove(struct platform_device *dev)
|
|||
|
||||
if (port) {
|
||||
s3c24xx_serial_cpufreq_deregister(to_ourport(port));
|
||||
#ifdef CONFIG_SAMSUNG_CLOCK
|
||||
device_remove_file(&dev->dev, &dev_attr_clock_source);
|
||||
#endif
|
||||
uart_remove_one_port(&s3c24xx_uart_drv, port);
|
||||
}
|
||||
|
||||
|
|
@ -1307,9 +1329,29 @@ static int s3c24xx_serial_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int s3c24xx_serial_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct uart_port *port = s3c24xx_dev_to_port(dev);
|
||||
|
||||
if (port) {
|
||||
/* restore IRQ mask */
|
||||
if (s3c24xx_serial_has_interrupt_mask(port)) {
|
||||
unsigned int uintm = 0xf;
|
||||
if (tx_enabled(port))
|
||||
uintm &= ~S3C64XX_UINTM_TXD_MSK;
|
||||
if (rx_enabled(port))
|
||||
uintm &= ~S3C64XX_UINTM_RXD_MSK;
|
||||
wr_regl(port, S3C64XX_UINTM, uintm);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops s3c24xx_serial_pm_ops = {
|
||||
.suspend = s3c24xx_serial_suspend,
|
||||
.resume = s3c24xx_serial_resume,
|
||||
.resume_noirq = s3c24xx_serial_resume_noirq,
|
||||
};
|
||||
#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
|
||||
|
||||
|
|
@ -1343,6 +1385,13 @@ s3c24xx_serial_console_txrdy(struct uart_port *port, unsigned int ufcon)
|
|||
return (utrstat & S3C2410_UTRSTAT_TXE) ? 1 : 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
s3c24xx_port_configured(unsigned int ucon)
|
||||
{
|
||||
/* consider the serial port configured if the tx/rx mode set */
|
||||
return (ucon & 0xf) != 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CONSOLE_POLL
|
||||
/*
|
||||
* Console polling routines for writing and reading from the uart while
|
||||
|
|
@ -1365,6 +1414,11 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port,
|
|||
unsigned char c)
|
||||
{
|
||||
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
|
||||
unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
|
||||
|
||||
/* not possible to xmit on unconfigured port */
|
||||
if (!s3c24xx_port_configured(ucon))
|
||||
return;
|
||||
|
||||
while (!s3c24xx_serial_console_txrdy(port, ufcon))
|
||||
cpu_relax();
|
||||
|
|
@ -1377,6 +1431,12 @@ static void
|
|||
s3c24xx_serial_console_putchar(struct uart_port *port, int ch)
|
||||
{
|
||||
unsigned int ufcon = rd_regl(cons_uart, S3C2410_UFCON);
|
||||
unsigned int ucon = rd_regl(cons_uart, S3C2410_UCON);
|
||||
|
||||
/* not possible to xmit on unconfigured port */
|
||||
if (!s3c24xx_port_configured(ucon))
|
||||
return;
|
||||
|
||||
while (!s3c24xx_serial_console_txrdy(port, ufcon))
|
||||
barrier();
|
||||
wr_regb(cons_uart, S3C2410_UTXH, ch);
|
||||
|
|
@ -1409,9 +1469,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
|
|||
"registers: ulcon=%08x, ucon=%08x, ubdriv=%08x\n",
|
||||
port, ulcon, ucon, ubrdiv);
|
||||
|
||||
if ((ucon & 0xf) != 0) {
|
||||
/* consider the serial port configured if the tx/rx mode set */
|
||||
|
||||
if (s3c24xx_port_configured(ucon)) {
|
||||
switch (ulcon & S3C2410_LCON_CSMASK) {
|
||||
case S3C2410_LCON_CS5:
|
||||
*bits = 5;
|
||||
|
|
@ -1758,6 +1816,7 @@ static int __init s3c24xx_serial_modinit(void)
|
|||
|
||||
static void __exit s3c24xx_serial_modexit(void)
|
||||
{
|
||||
platform_driver_unregister(&samsung_serial_driver);
|
||||
uart_unregister_driver(&s3c24xx_uart_drv);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,9 @@ struct s3c24xx_uart_port {
|
|||
#define wr_regb(port, reg, val) __raw_writeb(val, portaddr(port, reg))
|
||||
#define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg))
|
||||
|
||||
#ifdef CONFIG_SERIAL_SAMSUNG_DEBUG
|
||||
#if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \
|
||||
defined(CONFIG_DEBUG_LL) && \
|
||||
!defined(MODULE)
|
||||
|
||||
extern void printascii(const char *);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/platform_data/serial-sccnxp.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#define SCCNXP_NAME "uart-sccnxp"
|
||||
#define SCCNXP_MAJOR 204
|
||||
|
|
@ -131,6 +132,8 @@ struct sccnxp_port {
|
|||
struct timer_list timer;
|
||||
|
||||
struct sccnxp_pdata pdata;
|
||||
|
||||
struct regulator *regulator;
|
||||
};
|
||||
|
||||
static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift)
|
||||
|
|
@ -789,8 +792,6 @@ static int sccnxp_probe(struct platform_device *pdev)
|
|||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
dev_set_name(&pdev->dev, SCCNXP_NAME);
|
||||
|
||||
s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL);
|
||||
if (!s) {
|
||||
dev_err(&pdev->dev, "Error allocating port structure\n");
|
||||
|
|
@ -918,6 +919,16 @@ static int sccnxp_probe(struct platform_device *pdev)
|
|||
goto err_out;
|
||||
}
|
||||
|
||||
s->regulator = devm_regulator_get(&pdev->dev, "VCC");
|
||||
if (!IS_ERR(s->regulator)) {
|
||||
ret = regulator_enable(s->regulator);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to enable regulator: %i\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
membase = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(membase)) {
|
||||
ret = PTR_ERR(membase);
|
||||
|
|
@ -967,10 +978,6 @@ static int sccnxp_probe(struct platform_device *pdev)
|
|||
s->imr = 0;
|
||||
sccnxp_write(&s->port[0], SCCNXP_IMR_REG, 0);
|
||||
|
||||
/* Board specific configure */
|
||||
if (s->pdata.init)
|
||||
s->pdata.init();
|
||||
|
||||
if (!s->poll) {
|
||||
ret = devm_request_threaded_irq(&pdev->dev, s->irq, NULL,
|
||||
sccnxp_ist,
|
||||
|
|
@ -1011,8 +1018,8 @@ static int sccnxp_remove(struct platform_device *pdev)
|
|||
uart_unregister_driver(&s->uart);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
if (s->pdata.exit)
|
||||
s->pdata.exit();
|
||||
if (!IS_ERR(s->regulator))
|
||||
return regulator_disable(s->regulator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dmapool.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -1301,11 +1302,9 @@ static int tegra_uart_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
u->mapbase = resource->start;
|
||||
u->membase = devm_request_and_ioremap(&pdev->dev, resource);
|
||||
if (!u->membase) {
|
||||
dev_err(&pdev->dev, "memregion/iomap address req failed\n");
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
u->membase = devm_ioremap_resource(&pdev->dev, resource);
|
||||
if (IS_ERR(u->membase))
|
||||
return PTR_ERR(u->membase);
|
||||
|
||||
tup->uart_clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(tup->uart_clk)) {
|
||||
|
|
|
|||
|
|
@ -1711,7 +1711,7 @@ static int uart_proc_show(struct seq_file *m, void *v)
|
|||
|
||||
static int uart_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, uart_proc_show, PDE(inode)->data);
|
||||
return single_open(file, uart_proc_show, PDE_DATA(inode));
|
||||
}
|
||||
|
||||
static const struct file_operations uart_proc_fops = {
|
||||
|
|
@ -1941,6 +1941,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
|
|||
mutex_unlock(&port->mutex);
|
||||
return 0;
|
||||
}
|
||||
put_device(tty_dev);
|
||||
|
||||
if (console_suspend_enabled || !uart_console(uport))
|
||||
uport->suspended = 1;
|
||||
|
||||
|
|
@ -2006,9 +2008,11 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
|
|||
disable_irq_wake(uport->irq);
|
||||
uport->irq_wake = 0;
|
||||
}
|
||||
put_device(tty_dev);
|
||||
mutex_unlock(&port->mutex);
|
||||
return 0;
|
||||
}
|
||||
put_device(tty_dev);
|
||||
uport->suspended = 0;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
|
||||
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
|
||||
defined(CONFIG_ARCH_SH73A0) || \
|
||||
defined(CONFIG_ARCH_SH7367) || \
|
||||
defined(CONFIG_ARCH_SH7377) || \
|
||||
defined(CONFIG_ARCH_SH7372) || \
|
||||
defined(CONFIG_ARCH_R8A7740)
|
||||
|
||||
|
|
|
|||
|
|
@ -758,7 +758,7 @@ static struct of_device_id sirfsoc_uart_ids[] = {
|
|||
{ .compatible = "sirf,marco-uart", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sirfsoc_serial_of_match);
|
||||
MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids);
|
||||
|
||||
static struct platform_driver sirfsoc_uart_driver = {
|
||||
.probe = sirfsoc_uart_probe,
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ receive_chars(struct uart_sunsab_port *up,
|
|||
flag = TTY_FRAME;
|
||||
}
|
||||
|
||||
if (uart_handle_sysrq_char(&up->port, ch))
|
||||
if (uart_handle_sysrq_char(&up->port, ch) || !port)
|
||||
continue;
|
||||
|
||||
if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&
|
||||
|
|
|
|||
|
|
@ -968,6 +968,7 @@ static struct uart_ops sunsu_pops = {
|
|||
#define UART_NR 4
|
||||
|
||||
static struct uart_sunsu_port sunsu_ports[UART_NR];
|
||||
static int nr_inst; /* Number of already registered ports */
|
||||
|
||||
#ifdef CONFIG_SERIO
|
||||
|
||||
|
|
@ -1337,13 +1338,8 @@ static int __init sunsu_console_setup(struct console *co, char *options)
|
|||
printk("Console: ttyS%d (SU)\n",
|
||||
(sunsu_reg.minor - 64) + co->index);
|
||||
|
||||
/*
|
||||
* Check whether an invalid uart number has been specified, and
|
||||
* if so, search for the first available port that does have
|
||||
* console support.
|
||||
*/
|
||||
if (co->index >= UART_NR)
|
||||
co->index = 0;
|
||||
if (co->index > nr_inst)
|
||||
return -ENODEV;
|
||||
port = &sunsu_ports[co->index].port;
|
||||
|
||||
/*
|
||||
|
|
@ -1408,7 +1404,6 @@ static enum su_type su_get_type(struct device_node *dp)
|
|||
|
||||
static int su_probe(struct platform_device *op)
|
||||
{
|
||||
static int inst;
|
||||
struct device_node *dp = op->dev.of_node;
|
||||
struct uart_sunsu_port *up;
|
||||
struct resource *rp;
|
||||
|
|
@ -1418,16 +1413,16 @@ static int su_probe(struct platform_device *op)
|
|||
|
||||
type = su_get_type(dp);
|
||||
if (type == SU_PORT_PORT) {
|
||||
if (inst >= UART_NR)
|
||||
if (nr_inst >= UART_NR)
|
||||
return -EINVAL;
|
||||
up = &sunsu_ports[inst];
|
||||
up = &sunsu_ports[nr_inst];
|
||||
} else {
|
||||
up = kzalloc(sizeof(*up), GFP_KERNEL);
|
||||
if (!up)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
up->port.line = inst;
|
||||
up->port.line = nr_inst;
|
||||
|
||||
spin_lock_init(&up->port.lock);
|
||||
|
||||
|
|
@ -1461,6 +1456,8 @@ static int su_probe(struct platform_device *op)
|
|||
}
|
||||
dev_set_drvdata(&op->dev, up);
|
||||
|
||||
nr_inst++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1488,7 +1485,7 @@ static int su_probe(struct platform_device *op)
|
|||
|
||||
dev_set_drvdata(&op->dev, up);
|
||||
|
||||
inst++;
|
||||
nr_inst++;
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -1595,6 +1592,7 @@ static int __init sunsu_init(void)
|
|||
|
||||
static void __exit sunsu_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&su_driver);
|
||||
if (sunsu_reg.nr)
|
||||
sunserial_unregister_minors(&sunsu_reg, sunsu_reg.nr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
|
|||
else if (r1 & CRC_ERR)
|
||||
flag = TTY_FRAME;
|
||||
}
|
||||
if (uart_handle_sysrq_char(&up->port, ch))
|
||||
if (uart_handle_sysrq_char(&up->port, ch) || !port)
|
||||
continue;
|
||||
|
||||
if (up->port.ignore_status_mask == 0xff ||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
/*
|
||||
* UART Register offsets
|
||||
|
|
@ -585,9 +586,9 @@ static int vt8500_serial_probe(struct platform_device *pdev)
|
|||
if (!vt8500_port)
|
||||
return -ENOMEM;
|
||||
|
||||
vt8500_port->uart.membase = devm_request_and_ioremap(&pdev->dev, mmres);
|
||||
if (!vt8500_port->uart.membase)
|
||||
return -EADDRNOTAVAIL;
|
||||
vt8500_port->uart.membase = devm_ioremap_resource(&pdev->dev, mmres);
|
||||
if (IS_ERR(vt8500_port->uart.membase))
|
||||
return PTR_ERR(vt8500_port->uart.membase);
|
||||
|
||||
vt8500_port->clk = of_clk_get(pdev->dev.of_node, 0);
|
||||
if (IS_ERR(vt8500_port->clk)) {
|
||||
|
|
|
|||
|
|
@ -578,14 +578,13 @@ static int xuartps_startup(struct uart_port *port)
|
|||
/* Receive Timeout register is enabled with value of 10 */
|
||||
xuartps_writel(10, XUARTPS_RXTOUT_OFFSET);
|
||||
|
||||
/* Clear out any pending interrupts before enabling them */
|
||||
xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET);
|
||||
|
||||
/* Set the Interrupt Registers with desired interrupts */
|
||||
xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
|
||||
XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
|
||||
XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT, XUARTPS_IER_OFFSET);
|
||||
xuartps_writel(~(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
|
||||
XUARTPS_IXR_FRAMING | XUARTPS_IXR_OVERRUN |
|
||||
XUARTPS_IXR_RXTRIG | XUARTPS_IXR_TOUT), XUARTPS_IDR_OFFSET);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1058,9 +1058,6 @@ static void mgsl_bh_handler(struct work_struct *work)
|
|||
container_of(work, struct mgsl_struct, task);
|
||||
int action;
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if ( debug_level >= DEBUG_LEVEL_BH )
|
||||
printk( "%s(%d):mgsl_bh_handler(%s) entry\n",
|
||||
__FILE__,__LINE__,info->device_name);
|
||||
|
|
@ -3311,7 +3308,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
|
|||
port->blocked_open++;
|
||||
|
||||
while (1) {
|
||||
if (tty->termios.c_cflag & CBAUD)
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
|
|
|||
|
|
@ -3308,7 +3308,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
|||
port->blocked_open++;
|
||||
|
||||
while (1) {
|
||||
if ((tty->termios.c_cflag & CBAUD))
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
|
|
|||
|
|
@ -3329,7 +3329,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
|
|||
port->blocked_open++;
|
||||
|
||||
while (1) {
|
||||
if (tty->termios.c_cflag & CBAUD)
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ static void sysrq_handle_SAK(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_SAK_op = {
|
||||
.handler = sysrq_handle_SAK,
|
||||
.help_msg = "saK",
|
||||
.help_msg = "sak(k)",
|
||||
.action_msg = "SAK",
|
||||
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
|
||||
};
|
||||
|
|
@ -122,7 +122,7 @@ static void sysrq_handle_unraw(int key)
|
|||
|
||||
static struct sysrq_key_op sysrq_unraw_op = {
|
||||
.handler = sysrq_handle_unraw,
|
||||
.help_msg = "unRaw",
|
||||
.help_msg = "unraw(r)",
|
||||
.action_msg = "Keyboard mode set to system default",
|
||||
.enable_mask = SYSRQ_ENABLE_KEYBOARD,
|
||||
};
|
||||
|
|
@ -140,7 +140,7 @@ static void sysrq_handle_crash(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_crash_op = {
|
||||
.handler = sysrq_handle_crash,
|
||||
.help_msg = "Crash",
|
||||
.help_msg = "crash(c)",
|
||||
.action_msg = "Trigger a crash",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
|
|
@ -153,7 +153,7 @@ static void sysrq_handle_reboot(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_reboot_op = {
|
||||
.handler = sysrq_handle_reboot,
|
||||
.help_msg = "reBoot",
|
||||
.help_msg = "reboot(b)",
|
||||
.action_msg = "Resetting",
|
||||
.enable_mask = SYSRQ_ENABLE_BOOT,
|
||||
};
|
||||
|
|
@ -164,7 +164,7 @@ static void sysrq_handle_sync(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_sync_op = {
|
||||
.handler = sysrq_handle_sync,
|
||||
.help_msg = "Sync",
|
||||
.help_msg = "sync(s)",
|
||||
.action_msg = "Emergency Sync",
|
||||
.enable_mask = SYSRQ_ENABLE_SYNC,
|
||||
};
|
||||
|
|
@ -176,7 +176,7 @@ static void sysrq_handle_show_timers(int key)
|
|||
|
||||
static struct sysrq_key_op sysrq_show_timers_op = {
|
||||
.handler = sysrq_handle_show_timers,
|
||||
.help_msg = "show-all-timers(Q)",
|
||||
.help_msg = "show-all-timers(q)",
|
||||
.action_msg = "Show clockevent devices & pending hrtimers (no others)",
|
||||
};
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ static void sysrq_handle_mountro(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_mountro_op = {
|
||||
.handler = sysrq_handle_mountro,
|
||||
.help_msg = "Unmount",
|
||||
.help_msg = "unmount(u)",
|
||||
.action_msg = "Emergency Remount R/O",
|
||||
.enable_mask = SYSRQ_ENABLE_REMOUNT,
|
||||
};
|
||||
|
|
@ -199,7 +199,7 @@ static void sysrq_handle_showlocks(int key)
|
|||
|
||||
static struct sysrq_key_op sysrq_showlocks_op = {
|
||||
.handler = sysrq_handle_showlocks,
|
||||
.help_msg = "show-all-locks(D)",
|
||||
.help_msg = "show-all-locks(d)",
|
||||
.action_msg = "Show Locks Held",
|
||||
};
|
||||
#else
|
||||
|
|
@ -250,7 +250,7 @@ static void sysrq_handle_showallcpus(int key)
|
|||
|
||||
static struct sysrq_key_op sysrq_showallcpus_op = {
|
||||
.handler = sysrq_handle_showallcpus,
|
||||
.help_msg = "show-backtrace-all-active-cpus(L)",
|
||||
.help_msg = "show-backtrace-all-active-cpus(l)",
|
||||
.action_msg = "Show backtrace of all active CPUs",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
|
|
@ -265,7 +265,7 @@ static void sysrq_handle_showregs(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_showregs_op = {
|
||||
.handler = sysrq_handle_showregs,
|
||||
.help_msg = "show-registers(P)",
|
||||
.help_msg = "show-registers(p)",
|
||||
.action_msg = "Show Regs",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
|
|
@ -276,7 +276,7 @@ static void sysrq_handle_showstate(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_showstate_op = {
|
||||
.handler = sysrq_handle_showstate,
|
||||
.help_msg = "show-task-states(T)",
|
||||
.help_msg = "show-task-states(t)",
|
||||
.action_msg = "Show State",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
|
|
@ -287,7 +287,7 @@ static void sysrq_handle_showstate_blocked(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_showstate_blocked_op = {
|
||||
.handler = sysrq_handle_showstate_blocked,
|
||||
.help_msg = "show-blocked-tasks(W)",
|
||||
.help_msg = "show-blocked-tasks(w)",
|
||||
.action_msg = "Show Blocked State",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
|
|
@ -301,7 +301,7 @@ static void sysrq_ftrace_dump(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_ftrace_dump_op = {
|
||||
.handler = sysrq_ftrace_dump,
|
||||
.help_msg = "dump-ftrace-buffer(Z)",
|
||||
.help_msg = "dump-ftrace-buffer(z)",
|
||||
.action_msg = "Dump ftrace buffer",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
|
|
@ -315,7 +315,7 @@ static void sysrq_handle_showmem(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_showmem_op = {
|
||||
.handler = sysrq_handle_showmem,
|
||||
.help_msg = "show-memory-usage(M)",
|
||||
.help_msg = "show-memory-usage(m)",
|
||||
.action_msg = "Show Memory",
|
||||
.enable_mask = SYSRQ_ENABLE_DUMP,
|
||||
};
|
||||
|
|
@ -346,7 +346,7 @@ static void sysrq_handle_term(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_term_op = {
|
||||
.handler = sysrq_handle_term,
|
||||
.help_msg = "terminate-all-tasks(E)",
|
||||
.help_msg = "terminate-all-tasks(e)",
|
||||
.action_msg = "Terminate All Tasks",
|
||||
.enable_mask = SYSRQ_ENABLE_SIGNAL,
|
||||
};
|
||||
|
|
@ -365,7 +365,7 @@ static void sysrq_handle_moom(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_moom_op = {
|
||||
.handler = sysrq_handle_moom,
|
||||
.help_msg = "memory-full-oom-kill(F)",
|
||||
.help_msg = "memory-full-oom-kill(f)",
|
||||
.action_msg = "Manual OOM execution",
|
||||
.enable_mask = SYSRQ_ENABLE_SIGNAL,
|
||||
};
|
||||
|
|
@ -377,7 +377,7 @@ static void sysrq_handle_thaw(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_thaw_op = {
|
||||
.handler = sysrq_handle_thaw,
|
||||
.help_msg = "thaw-filesystems(J)",
|
||||
.help_msg = "thaw-filesystems(j)",
|
||||
.action_msg = "Emergency Thaw of all frozen filesystems",
|
||||
.enable_mask = SYSRQ_ENABLE_SIGNAL,
|
||||
};
|
||||
|
|
@ -390,7 +390,7 @@ static void sysrq_handle_kill(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_kill_op = {
|
||||
.handler = sysrq_handle_kill,
|
||||
.help_msg = "kill-all-tasks(I)",
|
||||
.help_msg = "kill-all-tasks(i)",
|
||||
.action_msg = "Kill All Tasks",
|
||||
.enable_mask = SYSRQ_ENABLE_SIGNAL,
|
||||
};
|
||||
|
|
@ -401,7 +401,7 @@ static void sysrq_handle_unrt(int key)
|
|||
}
|
||||
static struct sysrq_key_op sysrq_unrt_op = {
|
||||
.handler = sysrq_handle_unrt,
|
||||
.help_msg = "nice-all-RT-tasks(N)",
|
||||
.help_msg = "nice-all-RT-tasks(n)",
|
||||
.action_msg = "Nice All RT Tasks",
|
||||
.enable_mask = SYSRQ_ENABLE_RTNICE,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -60,24 +60,22 @@ static void tty_audit_buf_put(struct tty_audit_buf *buf)
|
|||
tty_audit_buf_free(buf);
|
||||
}
|
||||
|
||||
static void tty_audit_log(const char *description, struct task_struct *tsk,
|
||||
kuid_t loginuid, unsigned sessionid, int major,
|
||||
int minor, unsigned char *data, size_t size)
|
||||
static void tty_audit_log(const char *description, int major, int minor,
|
||||
unsigned char *data, size_t size)
|
||||
{
|
||||
struct audit_buffer *ab;
|
||||
struct task_struct *tsk = current;
|
||||
uid_t uid = from_kuid(&init_user_ns, task_uid(tsk));
|
||||
uid_t loginuid = from_kuid(&init_user_ns, audit_get_loginuid(tsk));
|
||||
u32 sessionid = audit_get_sessionid(tsk);
|
||||
|
||||
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
|
||||
if (ab) {
|
||||
char name[sizeof(tsk->comm)];
|
||||
kuid_t uid = task_uid(tsk);
|
||||
|
||||
audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u "
|
||||
"major=%d minor=%d comm=", description,
|
||||
tsk->pid,
|
||||
from_kuid(&init_user_ns, uid),
|
||||
from_kuid(&init_user_ns, loginuid),
|
||||
sessionid,
|
||||
major, minor);
|
||||
audit_log_format(ab, "%s pid=%u uid=%u auid=%u ses=%u major=%d"
|
||||
" minor=%d comm=", description, tsk->pid, uid,
|
||||
loginuid, sessionid, major, minor);
|
||||
get_task_comm(name, tsk);
|
||||
audit_log_untrustedstring(ab, name);
|
||||
audit_log_format(ab, " data=");
|
||||
|
|
@ -90,11 +88,9 @@ static void tty_audit_log(const char *description, struct task_struct *tsk,
|
|||
* tty_audit_buf_push - Push buffered data out
|
||||
*
|
||||
* Generate an audit message from the contents of @buf, which is owned by
|
||||
* @tsk with @loginuid. @buf->mutex must be locked.
|
||||
* the current task. @buf->mutex must be locked.
|
||||
*/
|
||||
static void tty_audit_buf_push(struct task_struct *tsk, kuid_t loginuid,
|
||||
unsigned int sessionid,
|
||||
struct tty_audit_buf *buf)
|
||||
static void tty_audit_buf_push(struct tty_audit_buf *buf)
|
||||
{
|
||||
if (buf->valid == 0)
|
||||
return;
|
||||
|
|
@ -102,24 +98,10 @@ static void tty_audit_buf_push(struct task_struct *tsk, kuid_t loginuid,
|
|||
buf->valid = 0;
|
||||
return;
|
||||
}
|
||||
tty_audit_log("tty", tsk, loginuid, sessionid, buf->major, buf->minor,
|
||||
buf->data, buf->valid);
|
||||
tty_audit_log("tty", buf->major, buf->minor, buf->data, buf->valid);
|
||||
buf->valid = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_audit_buf_push_current - Push buffered data out
|
||||
*
|
||||
* Generate an audit message from the contents of @buf, which is owned by
|
||||
* the current task. @buf->mutex must be locked.
|
||||
*/
|
||||
static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
|
||||
{
|
||||
kuid_t auid = audit_get_loginuid(current);
|
||||
unsigned int sessionid = audit_get_sessionid(current);
|
||||
tty_audit_buf_push(current, auid, sessionid, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_audit_exit - Handle a task exit
|
||||
*
|
||||
|
|
@ -130,15 +112,13 @@ void tty_audit_exit(void)
|
|||
{
|
||||
struct tty_audit_buf *buf;
|
||||
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
buf = current->signal->tty_audit_buf;
|
||||
current->signal->tty_audit_buf = NULL;
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
mutex_lock(&buf->mutex);
|
||||
tty_audit_buf_push_current(buf);
|
||||
tty_audit_buf_push(buf);
|
||||
mutex_unlock(&buf->mutex);
|
||||
|
||||
tty_audit_buf_put(buf);
|
||||
|
|
@ -151,9 +131,8 @@ void tty_audit_exit(void)
|
|||
*/
|
||||
void tty_audit_fork(struct signal_struct *sig)
|
||||
{
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
sig->audit_tty = current->signal->audit_tty;
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
sig->audit_tty_log_passwd = current->signal->audit_tty_log_passwd;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -163,20 +142,21 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch)
|
|||
{
|
||||
struct tty_audit_buf *buf;
|
||||
int major, minor, should_audit;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
should_audit = current->signal->audit_tty;
|
||||
buf = current->signal->tty_audit_buf;
|
||||
if (buf)
|
||||
atomic_inc(&buf->count);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
|
||||
major = tty->driver->major;
|
||||
minor = tty->driver->minor_start + tty->index;
|
||||
if (buf) {
|
||||
mutex_lock(&buf->mutex);
|
||||
if (buf->major == major && buf->minor == minor)
|
||||
tty_audit_buf_push_current(buf);
|
||||
tty_audit_buf_push(buf);
|
||||
mutex_unlock(&buf->mutex);
|
||||
tty_audit_buf_put(buf);
|
||||
}
|
||||
|
|
@ -187,24 +167,20 @@ void tty_audit_tiocsti(struct tty_struct *tty, char ch)
|
|||
|
||||
auid = audit_get_loginuid(current);
|
||||
sessionid = audit_get_sessionid(current);
|
||||
tty_audit_log("ioctl=TIOCSTI", current, auid, sessionid, major,
|
||||
minor, &ch, 1);
|
||||
tty_audit_log("ioctl=TIOCSTI", major, minor, &ch, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_audit_push_task - Flush task's pending audit data
|
||||
* @tsk: task pointer
|
||||
* @loginuid: sender login uid
|
||||
* @sessionid: sender session id
|
||||
* tty_audit_push_current - Flush current's pending audit data
|
||||
*
|
||||
* Called with a ref on @tsk held. Try to lock sighand and get a
|
||||
* reference to the tty audit buffer if available.
|
||||
* Try to lock sighand and get a reference to the tty audit buffer if available.
|
||||
* Flush the buffer or return an appropriate error code.
|
||||
*/
|
||||
int tty_audit_push_task(struct task_struct *tsk, kuid_t loginuid, u32 sessionid)
|
||||
int tty_audit_push_current(void)
|
||||
{
|
||||
struct tty_audit_buf *buf = ERR_PTR(-EPERM);
|
||||
struct task_struct *tsk = current;
|
||||
unsigned long flags;
|
||||
|
||||
if (!lock_task_sighand(tsk, &flags))
|
||||
|
|
@ -225,7 +201,7 @@ int tty_audit_push_task(struct task_struct *tsk, kuid_t loginuid, u32 sessionid)
|
|||
return PTR_ERR(buf);
|
||||
|
||||
mutex_lock(&buf->mutex);
|
||||
tty_audit_buf_push(tsk, loginuid, sessionid, buf);
|
||||
tty_audit_buf_push(buf);
|
||||
mutex_unlock(&buf->mutex);
|
||||
|
||||
tty_audit_buf_put(buf);
|
||||
|
|
@ -243,10 +219,11 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
|
|||
unsigned icanon)
|
||||
{
|
||||
struct tty_audit_buf *buf, *buf2;
|
||||
unsigned long flags;
|
||||
|
||||
buf = NULL;
|
||||
buf2 = NULL;
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
if (likely(!current->signal->audit_tty))
|
||||
goto out;
|
||||
buf = current->signal->tty_audit_buf;
|
||||
|
|
@ -254,7 +231,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
|
|||
atomic_inc(&buf->count);
|
||||
goto out;
|
||||
}
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
|
||||
buf2 = tty_audit_buf_alloc(tty->driver->major,
|
||||
tty->driver->minor_start + tty->index,
|
||||
|
|
@ -264,7 +241,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
if (!current->signal->audit_tty)
|
||||
goto out;
|
||||
buf = current->signal->tty_audit_buf;
|
||||
|
|
@ -276,7 +253,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
|
|||
atomic_inc(&buf->count);
|
||||
/* Fall through */
|
||||
out:
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
if (buf2)
|
||||
tty_audit_buf_free(buf2);
|
||||
return buf;
|
||||
|
|
@ -292,10 +269,18 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
|
|||
{
|
||||
struct tty_audit_buf *buf;
|
||||
int major, minor;
|
||||
int audit_log_tty_passwd;
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(size == 0))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
audit_log_tty_passwd = current->signal->audit_tty_log_passwd;
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
if (!audit_log_tty_passwd && icanon && !L_ECHO(tty))
|
||||
return;
|
||||
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY
|
||||
&& tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
return;
|
||||
|
|
@ -309,7 +294,7 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
|
|||
minor = tty->driver->minor_start + tty->index;
|
||||
if (buf->major != major || buf->minor != minor
|
||||
|| buf->icanon != icanon) {
|
||||
tty_audit_buf_push_current(buf);
|
||||
tty_audit_buf_push(buf);
|
||||
buf->major = major;
|
||||
buf->minor = minor;
|
||||
buf->icanon = icanon;
|
||||
|
|
@ -325,7 +310,7 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
|
|||
data += run;
|
||||
size -= run;
|
||||
if (buf->valid == N_TTY_BUF_SIZE)
|
||||
tty_audit_buf_push_current(buf);
|
||||
tty_audit_buf_push(buf);
|
||||
} while (size != 0);
|
||||
mutex_unlock(&buf->mutex);
|
||||
tty_audit_buf_put(buf);
|
||||
|
|
@ -339,16 +324,17 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
|
|||
void tty_audit_push(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_audit_buf *buf;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
spin_lock_irqsave(¤t->sighand->siglock, flags);
|
||||
if (likely(!current->signal->audit_tty)) {
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
return;
|
||||
}
|
||||
buf = current->signal->tty_audit_buf;
|
||||
if (buf)
|
||||
atomic_inc(&buf->count);
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
spin_unlock_irqrestore(¤t->sighand->siglock, flags);
|
||||
|
||||
if (buf) {
|
||||
int major, minor;
|
||||
|
|
@ -357,7 +343,7 @@ void tty_audit_push(struct tty_struct *tty)
|
|||
minor = tty->driver->minor_start + tty->index;
|
||||
mutex_lock(&buf->mutex);
|
||||
if (buf->major == major && buf->minor == minor)
|
||||
tty_audit_buf_push_current(buf);
|
||||
tty_audit_buf_push(buf);
|
||||
mutex_unlock(&buf->mutex);
|
||||
tty_audit_buf_put(buf);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -449,11 +449,6 @@ static void flush_to_ldisc(struct work_struct *work)
|
|||
tty_buffer_free(port, head);
|
||||
continue;
|
||||
}
|
||||
/* Ldisc or user is trying to flush the buffers
|
||||
we are feeding to the ldisc, stop feeding the
|
||||
line discipline as we want to empty the queue */
|
||||
if (test_bit(TTYP_FLUSHPENDING, &port->iflags))
|
||||
break;
|
||||
if (!tty->receive_room)
|
||||
break;
|
||||
if (count > tty->receive_room)
|
||||
|
|
@ -465,17 +460,20 @@ static void flush_to_ldisc(struct work_struct *work)
|
|||
disc->ops->receive_buf(tty, char_buf,
|
||||
flag_buf, count);
|
||||
spin_lock_irqsave(&buf->lock, flags);
|
||||
/* Ldisc or user is trying to flush the buffers.
|
||||
We may have a deferred request to flush the
|
||||
input buffer, if so pull the chain under the lock
|
||||
and empty the queue */
|
||||
if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
|
||||
__tty_buffer_flush(port);
|
||||
clear_bit(TTYP_FLUSHPENDING, &port->iflags);
|
||||
wake_up(&tty->read_wait);
|
||||
break;
|
||||
}
|
||||
}
|
||||
clear_bit(TTYP_FLUSHING, &port->iflags);
|
||||
}
|
||||
|
||||
/* We may have a deferred request to flush the input buffer,
|
||||
if so pull the chain under the lock and empty the queue */
|
||||
if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) {
|
||||
__tty_buffer_flush(port);
|
||||
clear_bit(TTYP_FLUSHPENDING, &port->iflags);
|
||||
wake_up(&tty->read_wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&buf->lock, flags);
|
||||
|
||||
tty_ldisc_deref(disc);
|
||||
|
|
|
|||
|
|
@ -532,6 +532,60 @@ void tty_wakeup(struct tty_struct *tty)
|
|||
|
||||
EXPORT_SYMBOL_GPL(tty_wakeup);
|
||||
|
||||
/**
|
||||
* tty_signal_session_leader - sends SIGHUP to session leader
|
||||
* @tty controlling tty
|
||||
* @exit_session if non-zero, signal all foreground group processes
|
||||
*
|
||||
* Send SIGHUP and SIGCONT to the session leader and its process group.
|
||||
* Optionally, signal all processes in the foreground process group.
|
||||
*
|
||||
* Returns the number of processes in the session with this tty
|
||||
* as their controlling terminal. This value is used to drop
|
||||
* tty references for those processes.
|
||||
*/
|
||||
static int tty_signal_session_leader(struct tty_struct *tty, int exit_session)
|
||||
{
|
||||
struct task_struct *p;
|
||||
int refs = 0;
|
||||
struct pid *tty_pgrp = NULL;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
if (tty->session) {
|
||||
do_each_pid_task(tty->session, PIDTYPE_SID, p) {
|
||||
spin_lock_irq(&p->sighand->siglock);
|
||||
if (p->signal->tty == tty) {
|
||||
p->signal->tty = NULL;
|
||||
/* We defer the dereferences outside fo
|
||||
the tasklist lock */
|
||||
refs++;
|
||||
}
|
||||
if (!p->signal->leader) {
|
||||
spin_unlock_irq(&p->sighand->siglock);
|
||||
continue;
|
||||
}
|
||||
__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
|
||||
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
|
||||
put_pid(p->signal->tty_old_pgrp); /* A noop */
|
||||
spin_lock(&tty->ctrl_lock);
|
||||
tty_pgrp = get_pid(tty->pgrp);
|
||||
if (tty->pgrp)
|
||||
p->signal->tty_old_pgrp = get_pid(tty->pgrp);
|
||||
spin_unlock(&tty->ctrl_lock);
|
||||
spin_unlock_irq(&p->sighand->siglock);
|
||||
} while_each_pid_task(tty->session, PIDTYPE_SID, p);
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
if (tty_pgrp) {
|
||||
if (exit_session)
|
||||
kill_pgrp(tty_pgrp, SIGHUP, exit_session);
|
||||
put_pid(tty_pgrp);
|
||||
}
|
||||
|
||||
return refs;
|
||||
}
|
||||
|
||||
/**
|
||||
* __tty_hangup - actual handler for hangup events
|
||||
* @work: tty device
|
||||
|
|
@ -554,15 +608,13 @@ EXPORT_SYMBOL_GPL(tty_wakeup);
|
|||
* tasklist_lock to walk task list for hangup event
|
||||
* ->siglock to protect ->signal/->sighand
|
||||
*/
|
||||
static void __tty_hangup(struct tty_struct *tty)
|
||||
static void __tty_hangup(struct tty_struct *tty, int exit_session)
|
||||
{
|
||||
struct file *cons_filp = NULL;
|
||||
struct file *filp, *f = NULL;
|
||||
struct task_struct *p;
|
||||
struct tty_file_private *priv;
|
||||
int closecount = 0, n;
|
||||
unsigned long flags;
|
||||
int refs = 0;
|
||||
int refs;
|
||||
|
||||
if (!tty)
|
||||
return;
|
||||
|
|
@ -599,39 +651,18 @@ static void __tty_hangup(struct tty_struct *tty)
|
|||
}
|
||||
spin_unlock(&tty_files_lock);
|
||||
|
||||
refs = tty_signal_session_leader(tty, exit_session);
|
||||
/* Account for the p->signal references we killed */
|
||||
while (refs--)
|
||||
tty_kref_put(tty);
|
||||
|
||||
/*
|
||||
* it drops BTM and thus races with reopen
|
||||
* we protect the race by TTY_HUPPING
|
||||
*/
|
||||
tty_ldisc_hangup(tty);
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
if (tty->session) {
|
||||
do_each_pid_task(tty->session, PIDTYPE_SID, p) {
|
||||
spin_lock_irq(&p->sighand->siglock);
|
||||
if (p->signal->tty == tty) {
|
||||
p->signal->tty = NULL;
|
||||
/* We defer the dereferences outside fo
|
||||
the tasklist lock */
|
||||
refs++;
|
||||
}
|
||||
if (!p->signal->leader) {
|
||||
spin_unlock_irq(&p->sighand->siglock);
|
||||
continue;
|
||||
}
|
||||
__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
|
||||
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
|
||||
put_pid(p->signal->tty_old_pgrp); /* A noop */
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
if (tty->pgrp)
|
||||
p->signal->tty_old_pgrp = get_pid(tty->pgrp);
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
spin_unlock_irq(&p->sighand->siglock);
|
||||
} while_each_pid_task(tty->session, PIDTYPE_SID, p);
|
||||
}
|
||||
read_unlock(&tasklist_lock);
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
spin_lock_irq(&tty->ctrl_lock);
|
||||
clear_bit(TTY_THROTTLED, &tty->flags);
|
||||
clear_bit(TTY_PUSH, &tty->flags);
|
||||
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||||
|
|
@ -640,11 +671,7 @@ static void __tty_hangup(struct tty_struct *tty)
|
|||
tty->session = NULL;
|
||||
tty->pgrp = NULL;
|
||||
tty->ctrl_status = 0;
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
|
||||
/* Account for the p->signal references we killed */
|
||||
while (refs--)
|
||||
tty_kref_put(tty);
|
||||
spin_unlock_irq(&tty->ctrl_lock);
|
||||
|
||||
/*
|
||||
* If one of the devices matches a console pointer, we
|
||||
|
|
@ -666,7 +693,6 @@ static void __tty_hangup(struct tty_struct *tty)
|
|||
*/
|
||||
set_bit(TTY_HUPPED, &tty->flags);
|
||||
clear_bit(TTY_HUPPING, &tty->flags);
|
||||
tty_ldisc_enable(tty);
|
||||
|
||||
tty_unlock(tty);
|
||||
|
||||
|
|
@ -679,7 +705,7 @@ static void do_tty_hangup(struct work_struct *work)
|
|||
struct tty_struct *tty =
|
||||
container_of(work, struct tty_struct, hangup_work);
|
||||
|
||||
__tty_hangup(tty);
|
||||
__tty_hangup(tty, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -717,7 +743,7 @@ void tty_vhangup(struct tty_struct *tty)
|
|||
|
||||
printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
|
||||
#endif
|
||||
__tty_hangup(tty);
|
||||
__tty_hangup(tty, 0);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(tty_vhangup);
|
||||
|
|
@ -740,6 +766,27 @@ void tty_vhangup_self(void)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_vhangup_session - hangup session leader exit
|
||||
* @tty: tty to hangup
|
||||
*
|
||||
* The session leader is exiting and hanging up its controlling terminal.
|
||||
* Every process in the foreground process group is signalled SIGHUP.
|
||||
*
|
||||
* We do this synchronously so that when the syscall returns the process
|
||||
* is complete. That guarantee is necessary for security reasons.
|
||||
*/
|
||||
|
||||
static void tty_vhangup_session(struct tty_struct *tty)
|
||||
{
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
char buf[64];
|
||||
|
||||
printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf));
|
||||
#endif
|
||||
__tty_hangup(tty, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_hung_up_p - was tty hung up
|
||||
* @filp: file pointer of tty
|
||||
|
|
@ -797,18 +844,18 @@ void disassociate_ctty(int on_exit)
|
|||
|
||||
tty = get_current_tty();
|
||||
if (tty) {
|
||||
struct pid *tty_pgrp = get_pid(tty->pgrp);
|
||||
if (on_exit) {
|
||||
if (tty->driver->type != TTY_DRIVER_TYPE_PTY)
|
||||
tty_vhangup(tty);
|
||||
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) {
|
||||
tty_vhangup_session(tty);
|
||||
} else {
|
||||
struct pid *tty_pgrp = tty_get_pgrp(tty);
|
||||
if (tty_pgrp) {
|
||||
kill_pgrp(tty_pgrp, SIGHUP, on_exit);
|
||||
kill_pgrp(tty_pgrp, SIGCONT, on_exit);
|
||||
put_pid(tty_pgrp);
|
||||
}
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
if (tty_pgrp) {
|
||||
kill_pgrp(tty_pgrp, SIGHUP, on_exit);
|
||||
if (!on_exit)
|
||||
kill_pgrp(tty_pgrp, SIGCONT, on_exit);
|
||||
put_pid(tty_pgrp);
|
||||
}
|
||||
|
||||
} else if (on_exit) {
|
||||
struct pid *old_pgrp;
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
|
|
@ -941,6 +988,14 @@ void start_tty(struct tty_struct *tty)
|
|||
|
||||
EXPORT_SYMBOL(start_tty);
|
||||
|
||||
/* We limit tty time update visibility to every 8 seconds or so. */
|
||||
static void tty_update_time(struct timespec *time)
|
||||
{
|
||||
unsigned long sec = get_seconds() & ~7;
|
||||
if ((long)(sec - time->tv_sec) > 0)
|
||||
time->tv_sec = sec;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_read - read method for tty device files
|
||||
* @file: pointer to tty file
|
||||
|
|
@ -960,10 +1015,11 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
|
|||
loff_t *ppos)
|
||||
{
|
||||
int i;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct tty_struct *tty = file_tty(file);
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
if (tty_paranoia_check(tty, file_inode(file), "tty_read"))
|
||||
if (tty_paranoia_check(tty, inode, "tty_read"))
|
||||
return -EIO;
|
||||
if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
|
||||
return -EIO;
|
||||
|
|
@ -977,6 +1033,9 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
|
|||
i = -EIO;
|
||||
tty_ldisc_deref(ld);
|
||||
|
||||
if (i > 0)
|
||||
tty_update_time(&inode->i_atime);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
@ -1077,8 +1136,10 @@ static inline ssize_t do_tty_write(
|
|||
break;
|
||||
cond_resched();
|
||||
}
|
||||
if (written)
|
||||
if (written) {
|
||||
tty_update_time(&file_inode(file)->i_mtime);
|
||||
ret = written;
|
||||
}
|
||||
out:
|
||||
tty_write_unlock(tty);
|
||||
return ret;
|
||||
|
|
@ -1344,9 +1405,7 @@ static int tty_reopen(struct tty_struct *tty)
|
|||
}
|
||||
tty->count++;
|
||||
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1463,6 +1522,17 @@ void tty_free_termios(struct tty_struct *tty)
|
|||
}
|
||||
EXPORT_SYMBOL(tty_free_termios);
|
||||
|
||||
/**
|
||||
* tty_flush_works - flush all works of a tty
|
||||
* @tty: tty device to flush works for
|
||||
*
|
||||
* Sync flush all works belonging to @tty.
|
||||
*/
|
||||
static void tty_flush_works(struct tty_struct *tty)
|
||||
{
|
||||
flush_work(&tty->SAK_work);
|
||||
flush_work(&tty->hangup_work);
|
||||
}
|
||||
|
||||
/**
|
||||
* release_one_tty - release tty structure memory
|
||||
|
|
@ -1548,6 +1618,7 @@ static void release_tty(struct tty_struct *tty, int idx)
|
|||
tty_free_termios(tty);
|
||||
tty_driver_remove_tty(tty->driver, tty);
|
||||
tty->port->itty = NULL;
|
||||
cancel_work_sync(&tty->port->buf.work);
|
||||
|
||||
if (tty->link)
|
||||
tty_kref_put(tty->link);
|
||||
|
|
@ -1777,12 +1848,21 @@ int tty_release(struct inode *inode, struct file *filp)
|
|||
return 0;
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
|
||||
printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf));
|
||||
#endif
|
||||
/*
|
||||
* Ask the line discipline code to release its structures
|
||||
*/
|
||||
tty_ldisc_release(tty, o_tty);
|
||||
|
||||
/* Wait for pending work before tty destruction commmences */
|
||||
tty_flush_works(tty);
|
||||
if (o_tty)
|
||||
tty_flush_works(o_tty);
|
||||
|
||||
#ifdef TTY_DEBUG_HANGUP
|
||||
printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf));
|
||||
#endif
|
||||
/*
|
||||
* The release_tty function takes care of the details of clearing
|
||||
* the slots and preserving the termios structure. The tty_unlock_pair
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ void tty_throttle(struct tty_struct *tty)
|
|||
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
|
||||
tty->ops->throttle)
|
||||
tty->ops->throttle(tty);
|
||||
tty->flow_change = 0;
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_throttle);
|
||||
|
|
@ -129,10 +130,73 @@ void tty_unthrottle(struct tty_struct *tty)
|
|||
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
|
||||
tty->ops->unthrottle)
|
||||
tty->ops->unthrottle(tty);
|
||||
tty->flow_change = 0;
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_unthrottle);
|
||||
|
||||
/**
|
||||
* tty_throttle_safe - flow control
|
||||
* @tty: terminal
|
||||
*
|
||||
* Similar to tty_throttle() but will only attempt throttle
|
||||
* if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental
|
||||
* throttle due to race conditions when throttling is conditional
|
||||
* on factors evaluated prior to throttling.
|
||||
*
|
||||
* Returns 0 if tty is throttled (or was already throttled)
|
||||
*/
|
||||
|
||||
int tty_throttle_safe(struct tty_struct *tty)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&tty->termios_mutex);
|
||||
if (!test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (tty->flow_change != TTY_THROTTLE_SAFE)
|
||||
ret = 1;
|
||||
else {
|
||||
set_bit(TTY_THROTTLED, &tty->flags);
|
||||
if (tty->ops->throttle)
|
||||
tty->ops->throttle(tty);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_unthrottle_safe - flow control
|
||||
* @tty: terminal
|
||||
*
|
||||
* Similar to tty_unthrottle() but will only attempt unthrottle
|
||||
* if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental
|
||||
* unthrottle due to race conditions when unthrottling is conditional
|
||||
* on factors evaluated prior to unthrottling.
|
||||
*
|
||||
* Returns 0 if tty is unthrottled (or was already unthrottled)
|
||||
*/
|
||||
|
||||
int tty_unthrottle_safe(struct tty_struct *tty)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&tty->termios_mutex);
|
||||
if (test_bit(TTY_THROTTLED, &tty->flags)) {
|
||||
if (tty->flow_change != TTY_UNTHROTTLE_SAFE)
|
||||
ret = 1;
|
||||
else {
|
||||
clear_bit(TTY_THROTTLED, &tty->flags);
|
||||
if (tty->ops->unthrottle)
|
||||
tty->ops->unthrottle(tty);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_wait_until_sent - wait for I/O to finish
|
||||
* @tty: tty we are waiting for
|
||||
|
|
@ -414,34 +478,6 @@ void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
|
||||
|
||||
/**
|
||||
* tty_get_baud_rate - get tty bit rates
|
||||
* @tty: tty to query
|
||||
*
|
||||
* Returns the baud rate as an integer for this terminal. The
|
||||
* termios lock must be held by the caller and the terminal bit
|
||||
* flags may be updated.
|
||||
*
|
||||
* Locking: none
|
||||
*/
|
||||
|
||||
speed_t tty_get_baud_rate(struct tty_struct *tty)
|
||||
{
|
||||
speed_t baud = tty_termios_baud_rate(&tty->termios);
|
||||
|
||||
if (baud == 38400 && tty->alt_speed) {
|
||||
if (!tty->warned) {
|
||||
printk(KERN_WARNING "Use of setserial/setrocket to "
|
||||
"set SPD_* flags is deprecated\n");
|
||||
tty->warned = 1;
|
||||
}
|
||||
baud = tty->alt_speed;
|
||||
}
|
||||
|
||||
return baud;
|
||||
}
|
||||
EXPORT_SYMBOL(tty_get_baud_rate);
|
||||
|
||||
/**
|
||||
* tty_termios_copy_hw - copy hardware settings
|
||||
* @new: New termios
|
||||
|
|
@ -1086,14 +1122,12 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(tty_mode_ioctl);
|
||||
|
||||
int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
|
||||
{
|
||||
struct tty_ldisc *ld;
|
||||
int retval = tty_check_change(tty);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ld = tty_ldisc_ref_wait(tty);
|
||||
/* Caller guarantees ldisc reference is held */
|
||||
static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg)
|
||||
{
|
||||
struct tty_ldisc *ld = tty->ldisc;
|
||||
|
||||
switch (arg) {
|
||||
case TCIFLUSH:
|
||||
if (ld && ld->ops->flush_buffer) {
|
||||
|
|
@ -1111,12 +1145,24 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
|
|||
tty_driver_flush_buffer(tty);
|
||||
break;
|
||||
default:
|
||||
tty_ldisc_deref(ld);
|
||||
return -EINVAL;
|
||||
}
|
||||
tty_ldisc_deref(ld);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tty_perform_flush(struct tty_struct *tty, unsigned long arg)
|
||||
{
|
||||
struct tty_ldisc *ld;
|
||||
int retval = tty_check_change(tty);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ld = tty_ldisc_ref_wait(tty);
|
||||
retval = __tty_perform_flush(tty, arg);
|
||||
if (ld)
|
||||
tty_ldisc_deref(ld);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_perform_flush);
|
||||
|
||||
int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
|
||||
|
|
@ -1155,7 +1201,7 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
|
|||
}
|
||||
return 0;
|
||||
case TCFLSH:
|
||||
return tty_perform_flush(tty, arg);
|
||||
return __tty_perform_flush(tty, arg);
|
||||
default:
|
||||
/* Try the mode commands */
|
||||
return tty_mode_ioctl(tty, file, cmd, arg);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,17 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#undef LDISC_DEBUG_HANGUP
|
||||
|
||||
#ifdef LDISC_DEBUG_HANGUP
|
||||
#define tty_ldisc_debug(tty, f, args...) ({ \
|
||||
char __b[64]; \
|
||||
printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \
|
||||
})
|
||||
#else
|
||||
#define tty_ldisc_debug(tty, f, args...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This guards the refcounted line discipline lists. The lock
|
||||
* must be taken with irqs off because there are hangup path
|
||||
|
|
@ -31,44 +42,6 @@ static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
|
|||
/* Line disc dispatch table */
|
||||
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
|
||||
|
||||
static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
|
||||
{
|
||||
if (ld)
|
||||
atomic_inc(&ld->users);
|
||||
return ld;
|
||||
}
|
||||
|
||||
static void put_ldisc(struct tty_ldisc *ld)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ON_ONCE(!ld))
|
||||
return;
|
||||
|
||||
/*
|
||||
* If this is the last user, free the ldisc, and
|
||||
* release the ldisc ops.
|
||||
*
|
||||
* We really want an "atomic_dec_and_raw_lock_irqsave()",
|
||||
* but we don't have it, so this does it by hand.
|
||||
*/
|
||||
raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
if (atomic_dec_and_test(&ld->users)) {
|
||||
struct tty_ldisc_ops *ldo = ld->ops;
|
||||
|
||||
ldo->refcount--;
|
||||
module_put(ldo->owner);
|
||||
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
|
||||
kfree(ld);
|
||||
return;
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
|
||||
if (waitqueue_active(&ld->wq_idle))
|
||||
wake_up(&ld->wq_idle);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_register_ldisc - install a line discipline
|
||||
* @disc: ldisc number
|
||||
|
|
@ -206,6 +179,29 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
|
|||
return ld;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_put - release the ldisc
|
||||
*
|
||||
* Complement of tty_ldisc_get().
|
||||
*/
|
||||
static inline void tty_ldisc_put(struct tty_ldisc *ld)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ON_ONCE(!ld))
|
||||
return;
|
||||
|
||||
raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
|
||||
/* unreleased reader reference(s) will cause this WARN */
|
||||
WARN_ON(!atomic_dec_and_test(&ld->users));
|
||||
|
||||
ld->ops->refcount--;
|
||||
module_put(ld->ops->owner);
|
||||
kfree(ld);
|
||||
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
}
|
||||
|
||||
static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
return (*pos < NR_LDISCS) ? pos : NULL;
|
||||
|
|
@ -254,24 +250,6 @@ const struct file_operations tty_ldiscs_proc_fops = {
|
|||
.release = seq_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* tty_ldisc_assign - set ldisc on a tty
|
||||
* @tty: tty to assign
|
||||
* @ld: line discipline
|
||||
*
|
||||
* Install an instance of a line discipline into a tty structure. The
|
||||
* ldisc must have a reference count above zero to ensure it remains.
|
||||
* The tty instance refcount starts at zero.
|
||||
*
|
||||
* Locking:
|
||||
* Caller must hold references
|
||||
*/
|
||||
|
||||
static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
{
|
||||
tty->ldisc = ld;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_try - internal helper
|
||||
* @tty: the tty
|
||||
|
|
@ -289,10 +267,13 @@ static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
|
|||
unsigned long flags;
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
/* FIXME: this allows reference acquire after TTY_LDISC is cleared */
|
||||
raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
ld = NULL;
|
||||
if (test_bit(TTY_LDISC, &tty->flags))
|
||||
ld = get_ldisc(tty->ldisc);
|
||||
if (test_bit(TTY_LDISC, &tty->flags) && tty->ldisc) {
|
||||
ld = tty->ldisc;
|
||||
atomic_inc(&ld->users);
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
return ld;
|
||||
}
|
||||
|
|
@ -352,15 +333,24 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
|
|||
|
||||
void tty_ldisc_deref(struct tty_ldisc *ld)
|
||||
{
|
||||
put_ldisc(ld);
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ON_ONCE(!ld))
|
||||
return;
|
||||
|
||||
raw_spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
/*
|
||||
* WARNs if one-too-many reader references were released
|
||||
* - the last reference must be released with tty_ldisc_put
|
||||
*/
|
||||
WARN_ON(atomic_dec_and_test(&ld->users));
|
||||
raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
|
||||
if (waitqueue_active(&ld->wq_idle))
|
||||
wake_up(&ld->wq_idle);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_deref);
|
||||
|
||||
static inline void tty_ldisc_put(struct tty_ldisc *ld)
|
||||
{
|
||||
put_ldisc(ld);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_enable - allow ldisc use
|
||||
* @tty: terminal to activate ldisc on
|
||||
|
|
@ -373,8 +363,9 @@ static inline void tty_ldisc_put(struct tty_ldisc *ld)
|
|||
* Clearing directly is allowed.
|
||||
*/
|
||||
|
||||
void tty_ldisc_enable(struct tty_struct *tty)
|
||||
static void tty_ldisc_enable(struct tty_struct *tty)
|
||||
{
|
||||
clear_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
set_bit(TTY_LDISC, &tty->flags);
|
||||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
wake_up(&tty_ldisc_wait);
|
||||
|
|
@ -479,7 +470,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
|||
/* There is an outstanding reference here so this is safe */
|
||||
old = tty_ldisc_get(old->ops->num);
|
||||
WARN_ON(IS_ERR(old));
|
||||
tty_ldisc_assign(tty, old);
|
||||
tty->ldisc = old;
|
||||
tty_set_termios_ldisc(tty, old->ops->num);
|
||||
if (tty_ldisc_open(tty, old) < 0) {
|
||||
tty_ldisc_put(old);
|
||||
|
|
@ -487,7 +478,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
|||
new_ldisc = tty_ldisc_get(N_TTY);
|
||||
if (IS_ERR(new_ldisc))
|
||||
panic("n_tty: get");
|
||||
tty_ldisc_assign(tty, new_ldisc);
|
||||
tty->ldisc = new_ldisc;
|
||||
tty_set_termios_ldisc(tty, N_TTY);
|
||||
r = tty_ldisc_open(tty, new_ldisc);
|
||||
if (r < 0)
|
||||
|
|
@ -497,39 +488,6 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_halt - shut down the line discipline
|
||||
* @tty: tty device
|
||||
*
|
||||
* Shut down the line discipline and work queue for this tty device.
|
||||
* The TTY_LDISC flag being cleared ensures no further references can
|
||||
* be obtained while the delayed work queue halt ensures that no more
|
||||
* data is fed to the ldisc.
|
||||
*
|
||||
* You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
|
||||
* in order to make sure any currently executing ldisc work is also
|
||||
* flushed.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_halt(struct tty_struct *tty)
|
||||
{
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
return cancel_work_sync(&tty->port->buf.work);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_flush_works - flush all works of a tty
|
||||
* @tty: tty device to flush works for
|
||||
*
|
||||
* Sync flush all works belonging to @tty.
|
||||
*/
|
||||
static void tty_ldisc_flush_works(struct tty_struct *tty)
|
||||
{
|
||||
flush_work(&tty->hangup_work);
|
||||
flush_work(&tty->SAK_work);
|
||||
flush_work(&tty->port->buf.work);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_wait_idle - wait for the ldisc to become idle
|
||||
* @tty: tty to wait for
|
||||
|
|
@ -546,6 +504,85 @@ static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout)
|
|||
return ret > 0 ? 0 : -EBUSY;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_halt - shut down the line discipline
|
||||
* @tty: tty device
|
||||
* @o_tty: paired pty device (can be NULL)
|
||||
* @timeout: # of jiffies to wait for ldisc refs to be released
|
||||
*
|
||||
* Shut down the line discipline and work queue for this tty device and
|
||||
* its paired pty (if exists). Clearing the TTY_LDISC flag ensures
|
||||
* no further references can be obtained, while waiting for existing
|
||||
* references to be released ensures no more data is fed to the ldisc.
|
||||
*
|
||||
* You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
|
||||
* in order to make sure any currently executing ldisc work is also
|
||||
* flushed.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_halt(struct tty_struct *tty, struct tty_struct *o_tty,
|
||||
long timeout)
|
||||
{
|
||||
int retval;
|
||||
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
if (o_tty)
|
||||
clear_bit(TTY_LDISC, &o_tty->flags);
|
||||
|
||||
retval = tty_ldisc_wait_idle(tty, timeout);
|
||||
if (!retval && o_tty)
|
||||
retval = tty_ldisc_wait_idle(o_tty, timeout);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
set_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
if (o_tty)
|
||||
set_bit(TTY_LDISC_HALTED, &o_tty->flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_hangup_halt - halt the line discipline for hangup
|
||||
* @tty: tty being hung up
|
||||
*
|
||||
* Shut down the line discipline and work queue for the tty device
|
||||
* being hungup. Clear the TTY_LDISC flag to ensure no further
|
||||
* references can be obtained and wait for remaining references to be
|
||||
* released to ensure no more data is fed to this ldisc.
|
||||
* Caller must hold legacy and ->ldisc_mutex.
|
||||
*
|
||||
* NB: tty_set_ldisc() is prevented from changing the ldisc concurrently
|
||||
* with this function by checking the TTY_HUPPING flag.
|
||||
*/
|
||||
static bool tty_ldisc_hangup_halt(struct tty_struct *tty)
|
||||
{
|
||||
char cur_n[TASK_COMM_LEN], tty_n[64];
|
||||
long timeout = 3 * HZ;
|
||||
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
|
||||
if (tty->ldisc) { /* Not yet closed */
|
||||
tty_unlock(tty);
|
||||
|
||||
while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
printk_ratelimited(KERN_WARNING
|
||||
"%s: waiting (%s) for %s took too long, but we keep waiting...\n",
|
||||
__func__, get_task_comm(cur_n, current),
|
||||
tty_name(tty, tty_n));
|
||||
}
|
||||
|
||||
set_bit(TTY_LDISC_HALTED, &tty->flags);
|
||||
|
||||
/* must reacquire both locks and preserve lock order */
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
}
|
||||
return !!tty->ldisc;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_set_ldisc - set line discipline
|
||||
* @tty: the terminal to set
|
||||
|
|
@ -563,7 +600,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
{
|
||||
int retval;
|
||||
struct tty_ldisc *o_ldisc, *new_ldisc;
|
||||
int work, o_work = 0;
|
||||
struct tty_struct *o_tty;
|
||||
|
||||
new_ldisc = tty_ldisc_get(ldisc);
|
||||
|
|
@ -589,15 +625,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
tty_unlock(tty);
|
||||
/*
|
||||
* Problem: What do we do if this blocks ?
|
||||
* We could deadlock here
|
||||
*/
|
||||
|
||||
tty_wait_until_sent(tty, 0);
|
||||
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/*
|
||||
|
|
@ -637,20 +664,16 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
* parallel to the change and re-referencing the tty.
|
||||
*/
|
||||
|
||||
work = tty_ldisc_halt(tty);
|
||||
if (o_tty)
|
||||
o_work = tty_ldisc_halt(o_tty);
|
||||
retval = tty_ldisc_halt(tty, o_tty, 5 * HZ);
|
||||
|
||||
/*
|
||||
* Wait for ->hangup_work and ->buf.work handlers to terminate.
|
||||
* Wait for hangup to complete, if pending.
|
||||
* We must drop the mutex here in case a hangup is also in process.
|
||||
*/
|
||||
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
|
||||
tty_ldisc_flush_works(tty);
|
||||
|
||||
retval = tty_ldisc_wait_idle(tty, 5 * HZ);
|
||||
flush_work(&tty->hangup_work);
|
||||
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
|
@ -675,7 +698,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|||
tty_ldisc_close(tty, o_ldisc);
|
||||
|
||||
/* Now set up the new line discipline. */
|
||||
tty_ldisc_assign(tty, new_ldisc);
|
||||
tty->ldisc = new_ldisc;
|
||||
tty_set_termios_ldisc(tty, ldisc);
|
||||
|
||||
retval = tty_ldisc_open(tty, new_ldisc);
|
||||
|
|
@ -705,10 +728,10 @@ enable:
|
|||
|
||||
/* Restart the work queue in case no characters kick it off. Safe if
|
||||
already running */
|
||||
if (work)
|
||||
schedule_work(&tty->port->buf.work);
|
||||
if (o_work)
|
||||
schedule_work(&tty->port->buf.work);
|
||||
if (o_tty)
|
||||
schedule_work(&o_tty->port->buf.work);
|
||||
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_unlock(tty);
|
||||
return retval;
|
||||
|
|
@ -749,11 +772,10 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
|
|||
|
||||
tty_ldisc_close(tty, tty->ldisc);
|
||||
tty_ldisc_put(tty->ldisc);
|
||||
tty->ldisc = NULL;
|
||||
/*
|
||||
* Switch the line discipline back
|
||||
*/
|
||||
tty_ldisc_assign(tty, ld);
|
||||
tty->ldisc = ld;
|
||||
tty_set_termios_ldisc(tty, ldisc);
|
||||
|
||||
return 0;
|
||||
|
|
@ -780,6 +802,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
|||
int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS;
|
||||
int err = 0;
|
||||
|
||||
tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
|
||||
|
||||
/*
|
||||
* FIXME! What are the locking issues here? This may me overdoing
|
||||
* things... This question is especially important now that we've
|
||||
|
|
@ -812,40 +836,12 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
|||
*/
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/*
|
||||
* this is like tty_ldisc_halt, but we need to give up
|
||||
* the BTM before calling cancel_work_sync, which may
|
||||
* need to wait for another function taking the BTM
|
||||
*/
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
tty_unlock(tty);
|
||||
cancel_work_sync(&tty->port->buf.work);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
retry:
|
||||
tty_lock(tty);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/* At this point we have a closed ldisc and we want to
|
||||
reopen it. We could defer this to the next open but
|
||||
it means auditing a lot of other paths so this is
|
||||
a FIXME */
|
||||
if (tty->ldisc) { /* Not yet closed */
|
||||
if (atomic_read(&tty->ldisc->users) != 1) {
|
||||
char cur_n[TASK_COMM_LEN], tty_n[64];
|
||||
long timeout = 3 * HZ;
|
||||
tty_unlock(tty);
|
||||
|
||||
while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
|
||||
timeout = MAX_SCHEDULE_TIMEOUT;
|
||||
printk_ratelimited(KERN_WARNING
|
||||
"%s: waiting (%s) for %s took too long, but we keep waiting...\n",
|
||||
__func__, get_task_comm(cur_n, current),
|
||||
tty_name(tty, tty_n));
|
||||
}
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
goto retry;
|
||||
}
|
||||
if (tty_ldisc_hangup_halt(tty)) {
|
||||
|
||||
/* At this point we have a halted ldisc; we want to close it and
|
||||
reopen a new ldisc. We could defer the reopen to the next
|
||||
open but it means auditing a lot of other paths so this is
|
||||
a FIXME */
|
||||
if (reset == 0) {
|
||||
|
||||
if (!tty_ldisc_reinit(tty, tty->termios.c_line))
|
||||
|
|
@ -864,6 +860,8 @@ retry:
|
|||
mutex_unlock(&tty->ldisc_mutex);
|
||||
if (reset)
|
||||
tty_reset_termios(tty);
|
||||
|
||||
tty_ldisc_debug(tty, "re-opened ldisc: %p\n", tty->ldisc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -899,11 +897,6 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
|
||||
static void tty_ldisc_kill(struct tty_struct *tty)
|
||||
{
|
||||
/* There cannot be users from userspace now. But there still might be
|
||||
* drivers holding a reference via tty_ldisc_ref. Do not steal them the
|
||||
* ldisc until they are done. */
|
||||
tty_ldisc_wait_idle(tty, MAX_SCHEDULE_TIMEOUT);
|
||||
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
/*
|
||||
* Now kill off the ldisc
|
||||
|
|
@ -931,18 +924,13 @@ static void tty_ldisc_kill(struct tty_struct *tty)
|
|||
void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||
{
|
||||
/*
|
||||
* Prevent flush_to_ldisc() from rescheduling the work for later. Then
|
||||
* kill any delayed work. As this is the final close it does not
|
||||
* race with the set_ldisc code path.
|
||||
* Shutdown this line discipline. As this is the final close,
|
||||
* it does not race with the set_ldisc code path.
|
||||
*/
|
||||
|
||||
tty_ldisc_halt(tty);
|
||||
if (o_tty)
|
||||
tty_ldisc_halt(o_tty);
|
||||
tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc);
|
||||
|
||||
tty_ldisc_flush_works(tty);
|
||||
if (o_tty)
|
||||
tty_ldisc_flush_works(o_tty);
|
||||
tty_ldisc_halt(tty, o_tty, MAX_SCHEDULE_TIMEOUT);
|
||||
|
||||
tty_lock_pair(tty, o_tty);
|
||||
/* This will need doing differently if we need to lock */
|
||||
|
|
@ -953,6 +941,8 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
tty_unlock_pair(tty, o_tty);
|
||||
/* And the memory resources remaining (buffers, termios) will be
|
||||
disposed of when the kref hits zero */
|
||||
|
||||
tty_ldisc_debug(tty, "ldisc closed\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -968,7 +958,7 @@ void tty_ldisc_init(struct tty_struct *tty)
|
|||
struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
|
||||
if (IS_ERR(ld))
|
||||
panic("n_tty: init_tty");
|
||||
tty_ldisc_assign(tty, ld);
|
||||
tty->ldisc = ld;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -980,8 +970,8 @@ void tty_ldisc_init(struct tty_struct *tty)
|
|||
*/
|
||||
void tty_ldisc_deinit(struct tty_struct *tty)
|
||||
{
|
||||
put_ldisc(tty->ldisc);
|
||||
tty_ldisc_assign(tty, NULL);
|
||||
tty_ldisc_put(tty->ldisc);
|
||||
tty->ldisc = NULL;
|
||||
}
|
||||
|
||||
void tty_ldisc_begin(void)
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ EXPORT_SYMBOL(tty_port_free_xmit_buf);
|
|||
*/
|
||||
void tty_port_destroy(struct tty_port *port)
|
||||
{
|
||||
cancel_work_sync(&port->buf.work);
|
||||
tty_buffer_free_all(port);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_destroy);
|
||||
|
|
@ -196,12 +197,24 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
|
|||
}
|
||||
EXPORT_SYMBOL(tty_port_tty_set);
|
||||
|
||||
static void tty_port_shutdown(struct tty_port *port)
|
||||
static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
mutex_lock(&port->mutex);
|
||||
if (port->ops->shutdown && !port->console &&
|
||||
test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
if (port->console)
|
||||
goto out;
|
||||
|
||||
if (test_and_clear_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
/*
|
||||
* Drop DTR/RTS if HUPCL is set. This causes any attached
|
||||
* modem to hang up the line.
|
||||
*/
|
||||
if (tty && C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(port);
|
||||
|
||||
if (port->ops->shutdown)
|
||||
port->ops->shutdown(port);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&port->mutex);
|
||||
}
|
||||
|
||||
|
|
@ -215,23 +228,57 @@ static void tty_port_shutdown(struct tty_port *port)
|
|||
|
||||
void tty_port_hangup(struct tty_port *port)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->count = 0;
|
||||
port->flags &= ~ASYNC_NORMAL_ACTIVE;
|
||||
if (port->tty) {
|
||||
set_bit(TTY_IO_ERROR, &port->tty->flags);
|
||||
tty_kref_put(port->tty);
|
||||
}
|
||||
tty = port->tty;
|
||||
if (tty)
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
port->tty = NULL;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
tty_port_shutdown(port, tty);
|
||||
tty_kref_put(tty);
|
||||
wake_up_interruptible(&port->open_wait);
|
||||
wake_up_interruptible(&port->delta_msr_wait);
|
||||
tty_port_shutdown(port);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_hangup);
|
||||
|
||||
/**
|
||||
* tty_port_tty_hangup - helper to hang up a tty
|
||||
*
|
||||
* @port: tty port
|
||||
* @check_clocal: hang only ttys with CLOCAL unset?
|
||||
*/
|
||||
void tty_port_tty_hangup(struct tty_port *port, bool check_clocal)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
|
||||
if (tty && (!check_clocal || !C_CLOCAL(tty))) {
|
||||
tty_hangup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
|
||||
|
||||
/**
|
||||
* tty_port_tty_wakeup - helper to wake up a tty
|
||||
*
|
||||
* @port: tty port
|
||||
*/
|
||||
void tty_port_tty_wakeup(struct tty_port *port)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
|
||||
if (tty) {
|
||||
tty_wakeup(tty);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
|
||||
|
||||
/**
|
||||
* tty_port_carrier_raised - carrier raised check
|
||||
* @port: tty port
|
||||
|
|
@ -350,7 +397,7 @@ int tty_port_block_til_ready(struct tty_port *port,
|
|||
|
||||
while (1) {
|
||||
/* Indicate we are open */
|
||||
if (tty->termios.c_cflag & CBAUD)
|
||||
if (C_BAUD(tty) && test_bit(ASYNCB_INITIALIZED, &port->flags))
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
|
||||
|
|
@ -395,6 +442,20 @@ int tty_port_block_til_ready(struct tty_port *port,
|
|||
}
|
||||
EXPORT_SYMBOL(tty_port_block_til_ready);
|
||||
|
||||
static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty)
|
||||
{
|
||||
unsigned int bps = tty_get_baud_rate(tty);
|
||||
long timeout;
|
||||
|
||||
if (bps > 1200) {
|
||||
timeout = (HZ * 10 * port->drain_delay) / bps;
|
||||
timeout = max_t(long, timeout, HZ / 10);
|
||||
} else {
|
||||
timeout = 2 * HZ;
|
||||
}
|
||||
schedule_timeout_interruptible(timeout);
|
||||
}
|
||||
|
||||
int tty_port_close_start(struct tty_port *port,
|
||||
struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
|
|
@ -427,31 +488,19 @@ int tty_port_close_start(struct tty_port *port,
|
|||
set_bit(ASYNCB_CLOSING, &port->flags);
|
||||
tty->closing = 1;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
/* Don't block on a stalled port, just pull the chain */
|
||||
if (tty->flow_stopped)
|
||||
tty_driver_flush_buffer(tty);
|
||||
if (test_bit(ASYNCB_INITIALIZED, &port->flags) &&
|
||||
port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent_from_close(tty, port->closing_wait);
|
||||
if (port->drain_delay) {
|
||||
unsigned int bps = tty_get_baud_rate(tty);
|
||||
long timeout;
|
||||
|
||||
if (bps > 1200)
|
||||
timeout = max_t(long,
|
||||
(HZ * 10 * port->drain_delay) / bps, HZ / 10);
|
||||
else
|
||||
timeout = 2 * HZ;
|
||||
schedule_timeout_interruptible(timeout);
|
||||
if (test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
/* Don't block on a stalled port, just pull the chain */
|
||||
if (tty->flow_stopped)
|
||||
tty_driver_flush_buffer(tty);
|
||||
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent_from_close(tty, port->closing_wait);
|
||||
if (port->drain_delay)
|
||||
tty_port_drain_delay(port, tty);
|
||||
}
|
||||
/* Flush the ldisc buffering */
|
||||
tty_ldisc_flush(tty);
|
||||
|
||||
/* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
|
||||
hang up the line */
|
||||
if (tty->termios.c_cflag & HUPCL)
|
||||
tty_port_lower_dtr_rts(port);
|
||||
|
||||
/* Don't call port->drop for the last reference. Callers will want
|
||||
to drop the last active reference in ->shutdown() or the tty
|
||||
shutdown path */
|
||||
|
|
@ -486,7 +535,7 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
|
|||
{
|
||||
if (tty_port_close_start(port, tty, filp) == 0)
|
||||
return;
|
||||
tty_port_shutdown(port);
|
||||
tty_port_shutdown(port, tty);
|
||||
set_bit(TTY_IO_ERROR, &tty->flags);
|
||||
tty_port_close_end(port, tty);
|
||||
tty_port_tty_set(port, NULL);
|
||||
|
|
|
|||
|
|
@ -194,8 +194,7 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int
|
|||
q = p->inverse_translations[i];
|
||||
|
||||
if (!q) {
|
||||
q = p->inverse_translations[i] = (unsigned char *)
|
||||
kmalloc(MAX_GLYPH, GFP_KERNEL);
|
||||
q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL);
|
||||
if (!q) return;
|
||||
}
|
||||
memset(q, 0, MAX_GLYPH);
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ vcs_poll_data_free(struct vcs_poll_data *poll)
|
|||
static struct vcs_poll_data *
|
||||
vcs_poll_data_get(struct file *file)
|
||||
{
|
||||
struct vcs_poll_data *poll = file->private_data;
|
||||
struct vcs_poll_data *poll = file->private_data, *kill = NULL;
|
||||
|
||||
if (poll)
|
||||
return poll;
|
||||
|
|
@ -122,10 +122,12 @@ vcs_poll_data_get(struct file *file)
|
|||
file->private_data = poll;
|
||||
} else {
|
||||
/* someone else raced ahead of us */
|
||||
vcs_poll_data_free(poll);
|
||||
kill = poll;
|
||||
poll = file->private_data;
|
||||
}
|
||||
spin_unlock(&file->f_lock);
|
||||
if (kill)
|
||||
vcs_poll_data_free(kill);
|
||||
|
||||
return poll;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -779,7 +779,6 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
|
|||
con_set_default_unimap(vc);
|
||||
vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
|
||||
if (!vc->vc_screenbuf) {
|
||||
tty_port_destroy(&vc->port);
|
||||
kfree(vc);
|
||||
vc_cons[currcons].d = NULL;
|
||||
return -ENOMEM;
|
||||
|
|
@ -986,26 +985,25 @@ static int vt_resize(struct tty_struct *tty, struct winsize *ws)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void vc_deallocate(unsigned int currcons)
|
||||
struct vc_data *vc_deallocate(unsigned int currcons)
|
||||
{
|
||||
struct vc_data *vc = NULL;
|
||||
|
||||
WARN_CONSOLE_UNLOCKED();
|
||||
|
||||
if (vc_cons_allocated(currcons)) {
|
||||
struct vc_data *vc = vc_cons[currcons].d;
|
||||
struct vt_notifier_param param = { .vc = vc };
|
||||
struct vt_notifier_param param;
|
||||
|
||||
param.vc = vc = vc_cons[currcons].d;
|
||||
atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, ¶m);
|
||||
vcs_remove_sysfs(currcons);
|
||||
vc->vc_sw->con_deinit(vc);
|
||||
put_pid(vc->vt_pid);
|
||||
module_put(vc->vc_sw->owner);
|
||||
kfree(vc->vc_screenbuf);
|
||||
if (currcons >= MIN_NR_CONSOLES) {
|
||||
tty_port_destroy(&vc->port);
|
||||
kfree(vc);
|
||||
}
|
||||
vc_cons[currcons].d = NULL;
|
||||
}
|
||||
return vc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -283,6 +283,51 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* deallocate a single console, if possible (leave 0) */
|
||||
static int vt_disallocate(unsigned int vc_num)
|
||||
{
|
||||
struct vc_data *vc = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (!vc_num)
|
||||
return 0;
|
||||
|
||||
console_lock();
|
||||
if (VT_BUSY(vc_num))
|
||||
ret = -EBUSY;
|
||||
else
|
||||
vc = vc_deallocate(vc_num);
|
||||
console_unlock();
|
||||
|
||||
if (vc && vc_num >= MIN_NR_CONSOLES) {
|
||||
tty_port_destroy(&vc->port);
|
||||
kfree(vc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* deallocate all unused consoles, but leave 0 */
|
||||
static void vt_disallocate_all(void)
|
||||
{
|
||||
struct vc_data *vc[MAX_NR_CONSOLES];
|
||||
int i;
|
||||
|
||||
console_lock();
|
||||
for (i = 1; i < MAX_NR_CONSOLES; i++)
|
||||
if (!VT_BUSY(i))
|
||||
vc[i] = vc_deallocate(i);
|
||||
else
|
||||
vc[i] = NULL;
|
||||
console_unlock();
|
||||
|
||||
for (i = 1; i < MAX_NR_CONSOLES; i++) {
|
||||
if (vc[i] && i >= MIN_NR_CONSOLES) {
|
||||
tty_port_destroy(&vc[i]->port);
|
||||
kfree(vc[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -769,24 +814,10 @@ int vt_ioctl(struct tty_struct *tty,
|
|||
ret = -ENXIO;
|
||||
break;
|
||||
}
|
||||
if (arg == 0) {
|
||||
/* deallocate all unused consoles, but leave 0 */
|
||||
console_lock();
|
||||
for (i=1; i<MAX_NR_CONSOLES; i++)
|
||||
if (! VT_BUSY(i))
|
||||
vc_deallocate(i);
|
||||
console_unlock();
|
||||
} else {
|
||||
/* deallocate a single console, if possible */
|
||||
arg--;
|
||||
if (VT_BUSY(arg))
|
||||
ret = -EBUSY;
|
||||
else if (arg) { /* leave 0 */
|
||||
console_lock();
|
||||
vc_deallocate(arg);
|
||||
console_unlock();
|
||||
}
|
||||
}
|
||||
if (arg == 0)
|
||||
vt_disallocate_all();
|
||||
else
|
||||
ret = vt_disallocate(--arg);
|
||||
break;
|
||||
|
||||
case VT_RESIZE:
|
||||
|
|
|
|||
Loading…
Reference in a new issue