diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-23 09:39:23 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-04-23 09:39:23 -0700 |
commit | 10af77c193681398e5dbe830db181d86047fcd41 (patch) | |
tree | b843eb8dae09a53efb410dd11d2132dba4fe4d15 /drivers/tty | |
parent | 66f75a5d028beaf67c931435fdc3e7823125730c (diff) | |
parent | 5f1a38952b7e932a1c169c28917b9a831f641bcc (diff) | |
download | op-kernel-dev-10af77c193681398e5dbe830db181d86047fcd41.zip op-kernel-dev-10af77c193681398e5dbe830db181d86047fcd41.tar.gz |
Merge 3.4-rc4 into tty-next
This resolves the merge problem with:
drivers/tty/serial/pch_uart.c
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/bfin_jtag_comm.c | 44 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_console.c | 96 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_console.h | 4 | ||||
-rw-r--r-- | drivers/tty/hvc/hvcs.c | 74 | ||||
-rw-r--r-- | drivers/tty/hvc/hvsi.c | 128 | ||||
-rw-r--r-- | drivers/tty/hvc/hvsi_lib.c | 2 | ||||
-rw-r--r-- | drivers/tty/ipwireless/tty.c | 81 | ||||
-rw-r--r-- | drivers/tty/serial/68328serial.c | 383 | ||||
-rw-r--r-- | drivers/tty/serial/68328serial.h | 186 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250.c | 44 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250.h | 2 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_pci.c | 45 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 109 | ||||
-rw-r--r-- | drivers/tty/serial/crisv10.c | 28 | ||||
-rw-r--r-- | drivers/tty/serial/of_serial.c | 26 | ||||
-rw-r--r-- | drivers/tty/serial/omap-serial.c | 74 | ||||
-rw-r--r-- | drivers/tty/serial/pch_uart.c | 53 | ||||
-rw-r--r-- | drivers/tty/tty_buffer.c | 85 | ||||
-rw-r--r-- | drivers/tty/vt/vt.c | 68 |
19 files changed, 652 insertions, 880 deletions
diff --git a/drivers/tty/bfin_jtag_comm.c b/drivers/tty/bfin_jtag_comm.c index 946f799..61fc74f 100644 --- a/drivers/tty/bfin_jtag_comm.c +++ b/drivers/tty/bfin_jtag_comm.c @@ -62,9 +62,7 @@ static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d) static struct tty_driver *bfin_jc_driver; static struct task_struct *bfin_jc_kthread; -static struct tty_struct * volatile bfin_jc_tty; -static unsigned long bfin_jc_count; -static DEFINE_MUTEX(bfin_jc_tty_mutex); +static struct tty_port port; static volatile struct circ_buf bfin_jc_write_buf; static int @@ -73,18 +71,21 @@ bfin_jc_emudat_manager(void *arg) uint32_t inbound_len = 0, outbound_len = 0; while (!kthread_should_stop()) { + struct tty_struct *tty = tty_port_tty_get(&port); /* no one left to give data to, so sleep */ - if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) { + if (tty == NULL && circ_empty(&bfin_jc_write_buf)) { pr_debug("waiting for readers\n"); __set_current_state(TASK_UNINTERRUPTIBLE); schedule(); __set_current_state(TASK_RUNNING); + continue; } /* no data available, so just chill */ if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) { pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n", inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head); + tty_kref_put(tty); if (inbound_len) schedule(); else @@ -94,9 +95,6 @@ bfin_jc_emudat_manager(void *arg) /* if incoming data is ready, eat it */ if (bfin_read_DBGSTAT() & EMUDIF) { - struct tty_struct *tty; - mutex_lock(&bfin_jc_tty_mutex); - tty = (struct tty_struct *)bfin_jc_tty; if (tty != NULL) { uint32_t emudat = bfin_read_emudat(); if (inbound_len == 0) { @@ -110,7 +108,6 @@ bfin_jc_emudat_manager(void *arg) tty_flip_buffer_push(tty); } } - mutex_unlock(&bfin_jc_tty_mutex); } /* if outgoing data is ready, post it */ @@ -120,7 +117,6 @@ bfin_jc_emudat_manager(void *arg) bfin_write_emudat(outbound_len); pr_debug("outgoing length: 0x%08x\n", outbound_len); } else { - struct tty_struct *tty; int tail = bfin_jc_write_buf.tail; size_t ate = (4 <= outbound_len ? 4 : outbound_len); uint32_t emudat = @@ -132,14 +128,12 @@ bfin_jc_emudat_manager(void *arg) ); bfin_jc_write_buf.tail += ate; outbound_len -= ate; - mutex_lock(&bfin_jc_tty_mutex); - tty = (struct tty_struct *)bfin_jc_tty; if (tty) tty_wakeup(tty); - mutex_unlock(&bfin_jc_tty_mutex); pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate); } } + tty_kref_put(tty); } __set_current_state(TASK_RUNNING); @@ -149,24 +143,28 @@ bfin_jc_emudat_manager(void *arg) static int bfin_jc_open(struct tty_struct *tty, struct file *filp) { - mutex_lock(&bfin_jc_tty_mutex); - pr_debug("open %lu\n", bfin_jc_count); - ++bfin_jc_count; - bfin_jc_tty = tty; + unsigned long flags; + + spin_lock_irqsave(&port.lock, flags); + port.count++; + spin_unlock_irqrestore(&port.lock, flags); + tty_port_tty_set(&port, tty); wake_up_process(bfin_jc_kthread); - mutex_unlock(&bfin_jc_tty_mutex); return 0; } static void bfin_jc_close(struct tty_struct *tty, struct file *filp) { - mutex_lock(&bfin_jc_tty_mutex); - pr_debug("close %lu\n", bfin_jc_count); - if (--bfin_jc_count == 0) - bfin_jc_tty = NULL; + unsigned long flags; + bool last; + + spin_lock_irqsave(&port.lock, flags); + last = --port.count == 0; + spin_unlock_irqrestore(&port.lock, flags); + if (last) + tty_port_tty_set(&port, NULL); wake_up_process(bfin_jc_kthread); - mutex_unlock(&bfin_jc_tty_mutex); } /* XXX: we dont handle the put_char() case where we must handle count = 1 */ @@ -242,6 +240,8 @@ static int __init bfin_jc_init(void) { int ret; + tty_port_init(&port); + bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME); if (IS_ERR(bfin_jc_kthread)) return PTR_ERR(bfin_jc_kthread); diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 8880adf..2d691eb 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -107,7 +107,7 @@ static struct hvc_struct *hvc_get_by_index(int index) list_for_each_entry(hp, &hvc_structs, next) { spin_lock_irqsave(&hp->lock, flags); if (hp->index == index) { - kref_get(&hp->kref); + tty_port_get(&hp->port); spin_unlock_irqrestore(&hp->lock, flags); spin_unlock(&hvc_structs_lock); return hp; @@ -229,9 +229,9 @@ static int __init hvc_console_init(void) console_initcall(hvc_console_init); /* callback when the kboject ref count reaches zero. */ -static void destroy_hvc_struct(struct kref *kref) +static void hvc_port_destruct(struct tty_port *port) { - struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); + struct hvc_struct *hp = container_of(port, struct hvc_struct, port); unsigned long flags; spin_lock(&hvc_structs_lock); @@ -264,7 +264,7 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) /* make sure no no tty has been registered in this index */ hp = hvc_get_by_index(index); if (hp) { - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); return -1; } @@ -313,20 +313,17 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) if (!(hp = hvc_get_by_index(tty->index))) return -ENODEV; - spin_lock_irqsave(&hp->lock, flags); + spin_lock_irqsave(&hp->port.lock, flags); /* Check and then increment for fast path open. */ - if (hp->count++ > 0) { - tty_kref_get(tty); - spin_unlock_irqrestore(&hp->lock, flags); + if (hp->port.count++ > 0) { + spin_unlock_irqrestore(&hp->port.lock, flags); hvc_kick(); return 0; } /* else count == 0 */ + spin_unlock_irqrestore(&hp->port.lock, flags); tty->driver_data = hp; - - hp->tty = tty_kref_get(tty); - - spin_unlock_irqrestore(&hp->lock, flags); + tty_port_tty_set(&hp->port, tty); if (hp->ops->notifier_add) rc = hp->ops->notifier_add(hp, hp->data); @@ -338,12 +335,9 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) * tty fields and return the kref reference. */ if (rc) { - spin_lock_irqsave(&hp->lock, flags); - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); - tty_kref_put(tty); + tty_port_tty_set(&hp->port, NULL); tty->driver_data = NULL; - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); } /* Force wakeup of the polling thread */ @@ -370,12 +364,12 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) hp = tty->driver_data; - spin_lock_irqsave(&hp->lock, flags); + spin_lock_irqsave(&hp->port.lock, flags); - if (--hp->count == 0) { + if (--hp->port.count == 0) { + spin_unlock_irqrestore(&hp->port.lock, flags); /* We are done with the tty pointer now. */ - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); + tty_port_tty_set(&hp->port, NULL); if (hp->ops->notifier_del) hp->ops->notifier_del(hp, hp->data); @@ -390,14 +384,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) */ tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT); } else { - if (hp->count < 0) + if (hp->port.count < 0) printk(KERN_ERR "hvc_close %X: oops, count is %d\n", - hp->vtermno, hp->count); - spin_unlock_irqrestore(&hp->lock, flags); + hp->vtermno, hp->port.count); + spin_unlock_irqrestore(&hp->port.lock, flags); } - tty_kref_put(tty); - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); } static void hvc_hangup(struct tty_struct *tty) @@ -412,32 +405,31 @@ static void hvc_hangup(struct tty_struct *tty) /* cancel pending tty resize work */ cancel_work_sync(&hp->tty_resize); - spin_lock_irqsave(&hp->lock, flags); + spin_lock_irqsave(&hp->port.lock, flags); /* * The N_TTY line discipline has problems such that in a close vs * open->hangup case this can be called after the final close so prevent * that from happening for now. */ - if (hp->count <= 0) { - spin_unlock_irqrestore(&hp->lock, flags); + if (hp->port.count <= 0) { + spin_unlock_irqrestore(&hp->port.lock, flags); return; } - temp_open_count = hp->count; - hp->count = 0; - hp->n_outbuf = 0; - hp->tty = NULL; + temp_open_count = hp->port.count; + hp->port.count = 0; + spin_unlock_irqrestore(&hp->port.lock, flags); + tty_port_tty_set(&hp->port, NULL); - spin_unlock_irqrestore(&hp->lock, flags); + hp->n_outbuf = 0; if (hp->ops->notifier_hangup) hp->ops->notifier_hangup(hp, hp->data); while(temp_open_count) { --temp_open_count; - tty_kref_put(tty); - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); } } @@ -478,7 +470,8 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count if (!hp) return -EPIPE; - if (hp->count <= 0) + /* FIXME what's this (unprotected) check for? */ + if (hp->port.count <= 0) return -EIO; spin_lock_irqsave(&hp->lock, flags); @@ -526,13 +519,12 @@ static void hvc_set_winsz(struct work_struct *work) hp = container_of(work, struct hvc_struct, tty_resize); - spin_lock_irqsave(&hp->lock, hvc_flags); - if (!hp->tty) { - spin_unlock_irqrestore(&hp->lock, hvc_flags); + tty = tty_port_tty_get(&hp->port); + if (!tty) return; - } - ws = hp->ws; - tty = tty_kref_get(hp->tty); + + spin_lock_irqsave(&hp->lock, hvc_flags); + ws = hp->ws; spin_unlock_irqrestore(&hp->lock, hvc_flags); tty_do_resize(tty, &ws); @@ -601,7 +593,7 @@ int hvc_poll(struct hvc_struct *hp) } /* No tty attached, just skip */ - tty = tty_kref_get(hp->tty); + tty = tty_port_tty_get(&hp->port); if (tty == NULL) goto bail; @@ -681,8 +673,7 @@ int hvc_poll(struct hvc_struct *hp) tty_flip_buffer_push(tty); } - if (tty) - tty_kref_put(tty); + tty_kref_put(tty); return poll_mask; } @@ -817,6 +808,10 @@ static const struct tty_operations hvc_ops = { #endif }; +static const struct tty_port_operations hvc_port_ops = { + .destruct = hvc_port_destruct, +}; + struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, const struct hv_ops *ops, int outbuf_size) @@ -842,7 +837,8 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, hp->outbuf_size = outbuf_size; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; - kref_init(&hp->kref); + tty_port_init(&hp->port); + hp->port.ops = &hvc_port_ops; INIT_WORK(&hp->tty_resize, hvc_set_winsz); spin_lock_init(&hp->lock); @@ -875,9 +871,9 @@ int hvc_remove(struct hvc_struct *hp) unsigned long flags; struct tty_struct *tty; - spin_lock_irqsave(&hp->lock, flags); - tty = tty_kref_get(hp->tty); + tty = tty_port_tty_get(&hp->port); + spin_lock_irqsave(&hp->lock, flags); if (hp->index < MAX_NR_HVC_CONSOLES) vtermnos[hp->index] = -1; @@ -891,7 +887,7 @@ int hvc_remove(struct hvc_struct *hp) * kref cause it to be removed, which will probably be the tty_vhangup * below. */ - kref_put(&hp->kref, destroy_hvc_struct); + tty_port_put(&hp->port); /* * This function call will auto chain call hvc_hangup. diff --git a/drivers/tty/hvc/hvc_console.h b/drivers/tty/hvc/hvc_console.h index c335a14..674d23c 100644 --- a/drivers/tty/hvc/hvc_console.h +++ b/drivers/tty/hvc/hvc_console.h @@ -46,10 +46,9 @@ #define HVC_ALLOC_TTY_ADAPTERS 8 struct hvc_struct { + struct tty_port port; spinlock_t lock; int index; - struct tty_struct *tty; - int count; int do_wakeup; char *outbuf; int outbuf_size; @@ -61,7 +60,6 @@ struct hvc_struct { struct winsize ws; struct work_struct tty_resize; struct list_head next; - struct kref kref; /* ref count & hvc_struct lifetime */ }; /* implemented by a low level driver */ diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 3436436..d56788c 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -261,6 +261,7 @@ static DEFINE_SPINLOCK(hvcs_pi_lock); /* One vty-server per hvcs_struct */ struct hvcs_struct { + struct tty_port port; spinlock_t lock; /* @@ -269,9 +270,6 @@ struct hvcs_struct { */ unsigned int index; - struct tty_struct *tty; - int open_count; - /* * Used to tell the driver kernel_thread what operations need to take * place upon this hvcs_struct instance. @@ -290,12 +288,11 @@ struct hvcs_struct { int chars_in_buffer; /* - * Any variable below the kref is valid before a tty is connected and + * Any variable below is valid before a tty is connected and * stays valid after the tty is disconnected. These shouldn't be * whacked until the kobject refcount reaches zero though some entries * may be changed via sysfs initiatives. */ - struct kref kref; /* ref count & hvcs_struct lifetime */ int connected; /* is the vty-server currently connected to a vty? */ uint32_t p_unit_address; /* partner unit address */ uint32_t p_partition_ID; /* partner partition ID */ @@ -304,9 +301,6 @@ struct hvcs_struct { struct vio_dev *vdev; }; -/* Required to back map a kref to its containing object */ -#define from_kref(k) container_of(k, struct hvcs_struct, kref) - static LIST_HEAD(hvcs_structs); static DEFINE_SPINLOCK(hvcs_structs_lock); static DEFINE_MUTEX(hvcs_init_mutex); @@ -422,7 +416,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribut spin_lock_irqsave(&hvcsd->lock, flags); - if (hvcsd->open_count > 0) { + if (hvcsd->port.count > 0) { spin_unlock_irqrestore(&hvcsd->lock, flags); printk(KERN_INFO "HVCS: vterm state unchanged. " "The hvcs device node is still in use.\n"); @@ -564,7 +558,7 @@ static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance) static void hvcs_try_write(struct hvcs_struct *hvcsd) { uint32_t unit_address = hvcsd->vdev->unit_address; - struct tty_struct *tty = hvcsd->tty; + struct tty_struct *tty = hvcsd->port.tty; int sent; if (hvcsd->todo_mask & HVCS_TRY_WRITE) { @@ -602,7 +596,7 @@ static int hvcs_io(struct hvcs_struct *hvcsd) spin_lock_irqsave(&hvcsd->lock, flags); unit_address = hvcsd->vdev->unit_address; - tty = hvcsd->tty; + tty = hvcsd->port.tty; hvcs_try_write(hvcsd); @@ -701,10 +695,9 @@ static void hvcs_return_index(int index) hvcs_index_list[index] = -1; } -/* callback when the kref ref count reaches zero */ -static void destroy_hvcs_struct(struct kref *kref) +static void hvcs_destruct_port(struct tty_port *p) { - struct hvcs_struct *hvcsd = from_kref(kref); + struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port); struct vio_dev *vdev; unsigned long flags; @@ -741,6 +734,10 @@ static void destroy_hvcs_struct(struct kref *kref) kfree(hvcsd); } +static const struct tty_port_operations hvcs_port_ops = { + .destruct = hvcs_destruct_port, +}; + static int hvcs_get_index(void) { int i; @@ -789,10 +786,9 @@ static int __devinit hvcs_probe( if (!hvcsd) return -ENODEV; - + tty_port_init(&hvcsd->port); + hvcsd->port.ops = &hvcs_port_ops; spin_lock_init(&hvcsd->lock); - /* Automatically incs the refcount the first time */ - kref_init(&hvcsd->kref); hvcsd->vdev = dev; dev_set_drvdata(&dev->dev, hvcsd); @@ -852,7 +848,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) spin_lock_irqsave(&hvcsd->lock, flags); - tty = hvcsd->tty; + tty = hvcsd->port.tty; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -860,7 +856,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev) * Let the last holder of this object cause it to be removed, which * would probably be tty_hangup below. */ - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); /* * The hangup is a scheduled function which will auto chain call @@ -1094,7 +1090,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index) list_for_each_entry(hvcsd, &hvcs_structs, next) { spin_lock_irqsave(&hvcsd->lock, flags); if (hvcsd->index == index) { - kref_get(&hvcsd->kref); + tty_port_get(&hvcsd->port); spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock(&hvcs_structs_lock); return hvcsd; @@ -1138,8 +1134,8 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) if ((retval = hvcs_partner_connect(hvcsd))) goto error_release; - hvcsd->open_count = 1; - hvcsd->tty = tty; + hvcsd->port.count = 1; + hvcsd->port.tty = tty; tty->driver_data = hvcsd; memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN); @@ -1160,7 +1156,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) * and will grab the spinlock and free the connection if it fails. */ if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); printk(KERN_WARNING "HVCS: enable device failed.\n"); return rc; } @@ -1171,8 +1167,8 @@ fast_open: hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - kref_get(&hvcsd->kref); - hvcsd->open_count++; + tty_port_get(&hvcsd->port); + hvcsd->port.count++; hvcsd->todo_mask |= HVCS_SCHED_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1186,7 +1182,7 @@ open_success: error_release: spin_unlock_irqrestore(&hvcsd->lock, flags); - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); printk(KERN_WARNING "HVCS: partner connect failed.\n"); return retval; @@ -1216,7 +1212,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - if (--hvcsd->open_count == 0) { + if (--hvcsd->port.count == 0) { vio_disable_interrupts(hvcsd->vdev); @@ -1225,7 +1221,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) * execute any operations on the TTY even though it is obligated * to deliver any pending I/O to the hypervisor. */ - hvcsd->tty = NULL; + hvcsd->port.tty = NULL; irq = hvcsd->vdev->irq; spin_unlock_irqrestore(&hvcsd->lock, flags); @@ -1240,16 +1236,16 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; free_irq(irq, hvcsd); - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); return; - } else if (hvcsd->open_count < 0) { + } else if (hvcsd->port.count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" " is missmanaged.\n", - hvcsd->vdev->unit_address, hvcsd->open_count); + hvcsd->vdev->unit_address, hvcsd->port.count); } spin_unlock_irqrestore(&hvcsd->lock, flags); - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); } static void hvcs_hangup(struct tty_struct * tty) @@ -1261,7 +1257,7 @@ static void hvcs_hangup(struct tty_struct * tty) spin_lock_irqsave(&hvcsd->lock, flags); /* Preserve this so that we know how many kref refs to put */ - temp_open_count = hvcsd->open_count; + temp_open_count = hvcsd->port.count; /* * Don't kref put inside the spinlock because the destruction @@ -1273,10 +1269,10 @@ static void hvcs_hangup(struct tty_struct * tty) hvcsd->todo_mask = 0; /* I don't think the tty needs the hvcs_struct pointer after a hangup */ - hvcsd->tty->driver_data = NULL; - hvcsd->tty = NULL; + tty->driver_data = NULL; + hvcsd->port.tty = NULL; - hvcsd->open_count = 0; + hvcsd->port.count = 0; /* This will drop any buffered data on the floor which is OK in a hangup * scenario. */ @@ -1301,7 +1297,7 @@ static void hvcs_hangup(struct tty_struct * tty) * NOTE: If this hangup was signaled from user space then the * final put will never happen. */ - kref_put(&hvcsd->kref, destroy_hvcs_struct); + tty_port_put(&hvcsd->port); } } @@ -1347,7 +1343,7 @@ static int hvcs_write(struct tty_struct *tty, * the middle of a write operation? This is a crummy place to do this * but we want to keep it all in the spinlock. */ - if (hvcsd->open_count <= 0) { + if (hvcsd->port.count <= 0) { spin_unlock_irqrestore(&hvcsd->lock, flags); return -ENODEV; } @@ -1421,7 +1417,7 @@ static int hvcs_write_room(struct tty_struct *tty) { struct hvcs_struct *hvcsd = tty->driver_data; - if (!hvcsd || hvcsd->open_count <= 0) + if (!hvcsd || hvcsd->port.count <= 0) return 0; return HVCS_BUFF_LEN - hvcsd->chars_in_buffer; diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index a7488b7..6f5bc49 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -69,14 +69,13 @@ #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) struct hvsi_struct { + struct tty_port port; struct delayed_work writer; struct work_struct handshaker; wait_queue_head_t emptyq; /* woken when outbuf is emptied */ wait_queue_head_t stateq; /* woken when HVSI state changes */ spinlock_t lock; int index; - struct tty_struct *tty; - int count; uint8_t throttle_buf[128]; uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ /* inbuf is for packet reassembly. leave a little room for leftovers. */ @@ -237,7 +236,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count) } static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, - struct tty_struct **to_hangup, struct hvsi_struct **to_handshake) + struct tty_struct *tty, struct hvsi_struct **to_handshake) { struct hvsi_control *header = (struct hvsi_control *)packet; @@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, /* CD went away; no more connection */ pr_debug("hvsi%i: CD dropped\n", hp->index); hp->mctrl &= TIOCM_CD; - /* If userland hasn't done an open(2) yet, hp->tty is NULL. */ - if (hp->tty && !(hp->tty->flags & CLOCAL)) - *to_hangup = hp->tty; + if (tty && !C_CLOCAL(tty)) + tty_hangup(tty); } break; case VSV_CLOSE_PROTOCOL: @@ -331,7 +329,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) } } -static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) +static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty, + const char *buf, int len) { int i; @@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) continue; } #endif /* CONFIG_MAGIC_SYSRQ */ - tty_insert_flip_char(hp->tty, c, 0); + tty_insert_flip_char(tty, c, 0); } } @@ -360,7 +359,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) * revisited. */ #define TTY_THRESHOLD_THROTTLE 128 -static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, +static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty, const uint8_t *packet) { const struct hvsi_header *header = (const struct hvsi_header *)packet; @@ -371,14 +370,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); if (datalen == 0) - return NULL; + return false; if (overflow > 0) { pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); datalen = TTY_THRESHOLD_THROTTLE; } - hvsi_insert_chars(hp, data, datalen); + hvsi_insert_chars(hp, tty, data, datalen); if (overflow > 0) { /* @@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, hp->n_throttle = overflow; } - return hp->tty; + return true; } /* @@ -399,14 +398,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, * machine during console handshaking (in which case tty = NULL and we ignore * incoming data). */ -static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, - struct tty_struct **hangup, struct hvsi_struct **handshake) +static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty, + struct hvsi_struct **handshake) { uint8_t *packet = hp->inbuf; int chunklen; + bool flip = false; - *flip = NULL; - *hangup = NULL; *handshake = NULL; chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); @@ -440,12 +438,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, case VS_DATA_PACKET_HEADER: if (!is_open(hp)) break; - if (hp->tty == NULL) + if (tty == NULL) break; /* no tty buffer to put data in */ - *flip = hvsi_recv_data(hp, packet); + flip = hvsi_recv_data(hp, tty, packet); break; case VS_CONTROL_PACKET_HEADER: - hvsi_recv_control(hp, packet, hangup, handshake); + hvsi_recv_control(hp, packet, tty, handshake); break; case VS_QUERY_RESPONSE_PACKET_HEADER: hvsi_recv_response(hp, packet); @@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, packet += len_packet(packet); - if (*hangup || *handshake) { - pr_debug("%s: hangup or handshake\n", __func__); - /* - * we need to send the hangup now before receiving any more data. - * If we get "data, hangup, data", we can't deliver the second - * data before the hangup. - */ + if (*handshake) { + pr_debug("%s: handshake\n", __func__); break; } } compact_inbuf(hp, packet); + if (flip) + tty_flip_buffer_push(tty); + return 1; } -static void hvsi_send_overflow(struct hvsi_struct *hp) +static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty) { pr_debug("%s: delivering %i bytes overflow\n", __func__, hp->n_throttle); - hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); + hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle); hp->n_throttle = 0; } @@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp) static irqreturn_t hvsi_interrupt(int irq, void *arg) { struct hvsi_struct *hp = (struct hvsi_struct *)arg; - struct tty_struct *flip; - struct tty_struct *hangup; struct hvsi_struct *handshake; + struct tty_struct *tty; unsigned long flags; int again = 1; pr_debug("%s\n", __func__); + tty = tty_port_tty_get(&hp->port); + while (again) { spin_lock_irqsave(&hp->lock, flags); - again = hvsi_load_chunk(hp, &flip, &hangup, &handshake); + again = hvsi_load_chunk(hp, tty, &handshake); spin_unlock_irqrestore(&hp->lock, flags); - /* - * we have to call tty_flip_buffer_push() and tty_hangup() outside our - * spinlock. But we also have to keep going until we've read all the - * available data. - */ - - if (flip) { - /* there was data put in the tty flip buffer */ - tty_flip_buffer_push(flip); - flip = NULL; - } - - if (hangup) { - tty_hangup(hangup); - } - if (handshake) { pr_debug("hvsi%i: attempting re-handshake\n", handshake->index); schedule_work(&handshake->handshaker); @@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) } spin_lock_irqsave(&hp->lock, flags); - if (hp->tty && hp->n_throttle - && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { - /* we weren't hung up and we weren't throttled, so we can deliver the - * rest now */ - flip = hp->tty; - hvsi_send_overflow(hp); + if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) { + /* we weren't hung up and we weren't throttled, so we can + * deliver the rest now */ + hvsi_send_overflow(hp, tty); + tty_flip_buffer_push(tty); } spin_unlock_irqrestore(&hp->lock, flags); - if (flip) { - tty_flip_buffer_push(flip); - } + tty_kref_put(tty); return IRQ_HANDLED; } @@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) if (hp->state == HVSI_FSP_DIED) return -EIO; + tty_port_tty_set(&hp->port, tty); spin_lock_irqsave(&hp->lock, flags); - hp->tty = tty; - hp->count++; + hp->port.count++; atomic_set(&hp->seqno, 0); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); spin_unlock_irqrestore(&hp->lock, flags); @@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hp->lock, flags); - if (--hp->count == 0) { - hp->tty = NULL; + if (--hp->port.count == 0) { + tty_port_tty_set(&hp->port, NULL); hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ /* only close down connection if it is not the console */ @@ -841,9 +819,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) spin_lock_irqsave(&hp->lock, flags); } - } else if (hp->count < 0) + } else if (hp->port.count < 0) printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", - hp - hvsi_ports, hp->count); + hp - hvsi_ports, hp->port.count); spin_unlock_irqrestore(&hp->lock, flags); } @@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty) pr_debug("%s\n", __func__); - spin_lock_irqsave(&hp->lock, flags); + tty_port_tty_set(&hp->port, NULL); - hp->count = 0; + spin_lock_irqsave(&hp->lock, flags); + hp->port.count = 0; hp->n_outbuf = 0; - hp->tty = NULL; - spin_unlock_irqrestore(&hp->lock, flags); } @@ -888,6 +865,7 @@ 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; @@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work) start_j = 0; #endif /* DEBUG */ wake_up_all(&hp->emptyq); - tty_wakeup(hp->tty); + tty = tty_port_tty_get(&hp->port); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } } out: @@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty, * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls * will see there is no room in outbuf and return. */ - while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { - int chunksize = min(count, hvsi_write_room(hp->tty)); + while ((count > 0) && (hvsi_write_room(tty) > 0)) { + int chunksize = min(count, hvsi_write_room(tty)); BUG_ON(hp->n_outbuf < 0); memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); @@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty) { struct hvsi_struct *hp = tty->driver_data; unsigned long flags; - int shouldflip = 0; pr_debug("%s\n", __func__); spin_lock_irqsave(&hp->lock, flags); if (hp->n_throttle) { - hvsi_send_overflow(hp); - shouldflip = 1; + hvsi_send_overflow(hp, tty); + tty_flip_buffer_push(tty); } spin_unlock_irqrestore(&hp->lock, flags); - if (shouldflip) - tty_flip_buffer_push(hp->tty); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); } @@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void) init_waitqueue_head(&hp->emptyq); init_waitqueue_head(&hp->stateq); spin_lock_init(&hp->lock); + tty_port_init(&hp->port); hp->index = hvsi_count; hp->inbuf_end = hp->inbuf; hp->state = HVSI_CLOSED; diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c index 6f4dd83..59c135d 100644 --- a/drivers/tty/hvc/hvsi_lib.c +++ b/drivers/tty/hvc/hvsi_lib.c @@ -377,7 +377,7 @@ int hvsilib_open(struct hvsi_priv *pv, struct hvc_struct *hp) pr_devel("HVSI@%x: open !\n", pv->termno); /* Keep track of the tty data structure */ - pv->tty = tty_kref_get(hp->tty); + pv->tty = tty_port_tty_get(&hp->port); hvsilib_establish(pv); diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index 4daf962..f8b5fa0 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -44,14 +44,13 @@ #define TTYTYPE_RAS_RAW (2) struct ipw_tty { + struct tty_port port; int index; struct ipw_hardware *hardware; unsigned int channel_idx; unsigned int secondary_channel_idx; int tty_type; struct ipw_network *network; - struct tty_struct *linux_tty; - int open_count; unsigned int control_lines; struct mutex ipw_tty_mutex; int tx_bytes_queued; @@ -73,23 +72,6 @@ static char *tty_type_name(int tty_type) return channel_names[tty_type]; } -static void report_registering(struct ipw_tty *tty) -{ - char *iftype = tty_type_name(tty->tty_type); - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": registering %s device ttyIPWp%d\n", iftype, tty->index); -} - -static void report_deregistering(struct ipw_tty *tty) -{ - char *iftype = tty_type_name(tty->tty_type); - - printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": deregistering %s device ttyIPWp%d\n", iftype, - tty->index); -} - static struct ipw_tty *get_tty(int index) { /* @@ -117,12 +99,12 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) mutex_unlock(&tty->ipw_tty_mutex); return -ENODEV; } - if (tty->open_count == 0) + if (tty->port.count == 0) tty->tx_bytes_queued = 0; - tty->open_count++; + tty->port.count++; - tty->linux_tty = linux_tty; + tty->port.tty = linux_tty; linux_tty->driver_data = tty; linux_tty->low_latency = 1; @@ -136,13 +118,13 @@ static int ipw_open(struct tty_struct *linux_tty, struct file *filp) static void do_ipw_close(struct ipw_tty *tty) { - tty->open_count--; + tty->port.count--; - if (tty->open_count == 0) { - struct tty_struct *linux_tty = tty->linux_tty; + if (tty->port.count == 0) { + struct tty_struct *linux_tty = tty->port.tty; if (linux_tty != NULL) { - tty->linux_tty = NULL; + tty->port.tty = NULL; linux_tty->driver_data = NULL; if (tty->tty_type == TTYTYPE_MODEM) @@ -159,7 +141,7 @@ static void ipw_hangup(struct tty_struct *linux_tty) return; mutex_lock(&tty->ipw_tty_mutex); - if (tty->open_count == 0) { + if (tty->port.count == 0) { mutex_unlock(&tty->ipw_tty_mutex); return; } @@ -182,13 +164,13 @@ void ipwireless_tty_received(struct ipw_tty *tty, unsigned char *data, int work = 0; mutex_lock(&tty->ipw_tty_mutex); - linux_tty = tty->linux_tty; + linux_tty = tty->port.tty; if (linux_tty == NULL) { mutex_unlock(&tty->ipw_tty_mutex); return; } - if (!tty->open_count) { + if (!tty->port.count) { mutex_unlock(&tty->ipw_tty_mutex); return; } @@ -230,7 +212,7 @@ static int ipw_write(struct tty_struct *linux_tty, return -ENODEV; mutex_lock(&tty->ipw_tty_mutex); - if (!tty->open_count) { + if (!tty->port.count) { mutex_unlock(&tty->ipw_tty_mutex); return -EINVAL; } @@ -270,7 +252,7 @@ static int ipw_write_room(struct tty_struct *linux_tty) if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; room = IPWIRELESS_TX_QUEUE_SIZE - tty->tx_bytes_queued; @@ -312,7 +294,7 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty) if (!tty) return 0; - if (!tty->open_count) + if (!tty->port.count) return 0; return tty->tx_bytes_queued; @@ -393,7 +375,7 @@ static int ipw_tiocmget(struct tty_struct *linux_tty) if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; return get_control_lines(tty); @@ -409,7 +391,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; return set_control_lines(tty, set, clear); @@ -423,7 +405,7 @@ static int ipw_ioctl(struct tty_struct *linux_tty, if (!tty) return -ENODEV; - if (!tty->open_count) + if (!tty->port.count) return -EINVAL; /* FIXME: Exactly how is the tty object locked here .. */ @@ -492,6 +474,7 @@ static int add_tty(int j, ttys[j]->network = network; ttys[j]->tty_type = tty_type; mutex_init(&ttys[j]->ipw_tty_mutex); + tty_port_init(&ttys[j]->port); tty_register_device(ipw_tty_driver, j, NULL); ipwireless_associate_network_tty(network, channel_idx, ttys[j]); @@ -500,8 +483,12 @@ static int add_tty(int j, ipwireless_associate_network_tty(network, secondary_channel_idx, ttys[j]); - if (get_tty(j) == ttys[j]) - report_registering(ttys[j]); + /* check if we provide raw device (if loopback is enabled) */ + if (get_tty(j)) + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": registering %s device ttyIPWp%d\n", + tty_type_name(tty_type), j); + return 0; } @@ -560,19 +547,21 @@ void ipwireless_tty_free(struct ipw_tty *tty) if (ttyj) { mutex_lock(&ttyj->ipw_tty_mutex); - if (get_tty(j) == ttyj) - report_deregistering(ttyj); + if (get_tty(j)) + printk(KERN_INFO IPWIRELESS_PCCARD_NAME + ": deregistering %s device ttyIPWp%d\n", + tty_type_name(ttyj->tty_type), j); ttyj->closing = 1; - if (ttyj->linux_tty != NULL) { + if (ttyj->port.tty != NULL) { mutex_unlock(&ttyj->ipw_tty_mutex); - tty_hangup(ttyj->linux_tty); - /* Wait till the tty_hangup has completed */ - flush_work_sync(&ttyj->linux_tty->hangup_work); + tty_vhangup(ttyj->port.tty); /* FIXME: Exactly how is the tty object locked here against a parallel ioctl etc */ + /* FIXME2: hangup does not mean all processes + * are gone */ mutex_lock(&ttyj->ipw_tty_mutex); } - while (ttyj->open_count) + while (ttyj->port.count) do_ipw_close(ttyj); ipwireless_disassociate_network_ttys(network, ttyj->channel_idx); @@ -661,8 +650,8 @@ ipwireless_tty_notify_control_line_change(struct ipw_tty *tty, */ if ((old_control_lines & IPW_CONTROL_LINE_DCD) && !(tty->control_lines & IPW_CONTROL_LINE_DCD) - && tty->linux_tty) { - tty_hangup(tty->linux_tty); + && tty->port.tty) { + tty_hangup(tty->port.tty); } } diff --git a/drivers/tty/serial/68328serial.c b/drivers/tty/serial/68328serial.c index 5ce78252..3ed20e4 100644 --- a/drivers/tty/serial/68328serial.c +++ b/drivers/tty/serial/68328serial.c @@ -17,6 +17,7 @@ #include <asm/dbg.h> #include <linux/module.h> #include <linux/errno.h> +#include <linux/serial.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/timer.h> @@ -56,8 +57,6 @@ #endif /* CONFIG_M68VZ328 */ #endif /* CONFIG_M68EZ328 */ -#include "68328serial.h" - /* Turn off usage of real serial interrupt code, to "support" Copilot */ #ifdef CONFIG_XCOPILOT_BUGS #undef USE_INTS @@ -65,33 +64,82 @@ #define USE_INTS #endif -static struct m68k_serial m68k_soft[NR_PORTS]; +/* + * I believe this is the optimal setting that reduces the number of interrupts. + * At high speeds the output might become a little "bursted" (use USTCNT_TXHE + * if that bothers you), but in most cases it will not, since we try to + * transmit characters every time rs_interrupt is called. Thus, quite often + * you'll see that a receive interrupt occures before the transmit one. + * -- Vladimir Gurevich + */ +#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) -static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS; +/* + * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special + * "Old data interrupt" which occures whenever the data stay in the FIFO + * longer than 30 bits time. This allows us to use FIFO without compromising + * latency. '328 does not have this feature and without the real 328-based + * board I would assume that RXRE is the safest setting. + * + * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of + * interrupts. RXFE (receive queue full) causes the system to lose data + * at least at 115200 baud + * + * If your board is busy doing other stuff, you might consider to use + * RXRE (data ready intrrupt) instead. + * + * The other option is to make these INTR masks run-time configurable, so + * that people can dynamically adapt them according to the current usage. + * -- Vladimir Gurevich + */ -/* multiple ports are contiguous in memory */ -m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; +/* (es) */ +#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) +#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) +#elif defined(CONFIG_M68328) +#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) +#else +#error Please, define the Rx interrupt events for your CPU +#endif +/* (/es) */ -struct tty_struct m68k_ttys; -struct m68k_serial *m68k_consinfo = 0; +/* + * This is our internal structure for each serial port's state. + */ +struct m68k_serial { + struct tty_port tport; + char is_cons; /* Is this our console. */ + int magic; + int baud_base; + int port; + int irq; + int type; /* UART type */ + int custom_divisor; + int x_char; /* xon/xoff character */ + int line; + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; +}; -#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */ +#define SERIAL_MAGIC 0x5301 -struct tty_driver *serial_driver; +/* + * Define the number of ports supported and their irqs. + */ +#define NR_PORTS 1 -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 +static struct m68k_serial m68k_soft[NR_PORTS]; -/* Debugging... DEBUG_INTR is bad to use when one of the zs - * lines is your console ;( - */ -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW +static unsigned int uart_irqs[NR_PORTS] = { UART_IRQ_NUM }; -#define RS_ISR_PASS_LIMIT 256 +/* multiple ports are contiguous in memory */ +m68328_uart *uart_addr = (m68328_uart *)USTCNT_ADDR; + +struct tty_driver *serial_driver; -static void change_speed(struct m68k_serial *info); +static void change_speed(struct m68k_serial *info, struct tty_struct *tty); /* * Setup for console. Argument comes from the boot command line. @@ -143,17 +191,6 @@ static int baud_table[] = { 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 0 }; -/* Sets or clears DTR/RTS on the requested line */ -static inline void m68k_rtsdtr(struct m68k_serial *ss, int set) -{ - if (set) { - /* set the RTS/CTS line */ - } else { - /* clear it */ - } - return; -} - /* Utility routines */ static inline int get_baud(struct m68k_serial *ss) { @@ -189,7 +226,8 @@ static void rs_stop(struct tty_struct *tty) static int rs_put_char(char ch) { - int flags, loops = 0; + unsigned long flags; + int loops = 0; local_irq_save(flags); @@ -224,28 +262,9 @@ static void rs_start(struct tty_struct *tty) local_irq_restore(flags); } -/* Drop into either the boot monitor or kadb upon receiving a break - * from keyboard/console input. - */ -static void batten_down_hatches(void) -{ - /* Drop into the debugger */ -} - -static void status_handle(struct m68k_serial *info, unsigned short status) +static void receive_chars(struct m68k_serial *info, struct tty_struct *tty, + unsigned short rx) { - /* If this is console input and this is a - * 'break asserted' status change interrupt - * see if we can drop into the debugger - */ - if((status & URX_BREAK) && info->break_abort) - batten_down_hatches(); - return; -} - -static void receive_chars(struct m68k_serial *info, unsigned short rx) -{ - struct tty_struct *tty = info->tty; m68328_uart *uart = &uart_addr[info->line]; unsigned char ch, flag; @@ -259,7 +278,6 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx) if(info->is_cons) { if(URX_BREAK & rx) { /* whee, break received */ - status_handle(info, rx); return; #ifdef CONFIG_MAGIC_SYSRQ } else if (ch == 0x10) { /* ^P */ @@ -280,16 +298,13 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx) flag = TTY_NORMAL; - if(rx & URX_PARITY_ERROR) { + if (rx & URX_PARITY_ERROR) flag = TTY_PARITY; - status_handle(info, rx); - } else if(rx & URX_OVRUN) { + else if (rx & URX_OVRUN) flag = TTY_OVERRUN; - status_handle(info, rx); - } else if(rx & URX_FRAME_ERROR) { + else if (rx & URX_FRAME_ERROR) flag = TTY_FRAME; - status_handle(info, rx); - } + tty_insert_flip_char(tty, ch, flag); #ifndef CONFIG_XCOPILOT_BUGS } while((rx = uart->urx.w) & URX_DATA_READY); @@ -301,7 +316,7 @@ clear_and_exit: return; } -static void transmit_chars(struct m68k_serial *info) +static void transmit_chars(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; @@ -312,7 +327,7 @@ static void transmit_chars(struct m68k_serial *info) goto clear_and_return; } - if((info->xmit_cnt <= 0) || info->tty->stopped) { + if ((info->xmit_cnt <= 0) || !tty || tty->stopped) { /* That's peculiar... TX ints off */ uart->ustcnt &= ~USTCNT_TX_INTR_MASK; goto clear_and_return; @@ -340,6 +355,7 @@ clear_and_return: irqreturn_t rs_interrupt(int irq, void *dev_id) { struct m68k_serial *info = dev_id; + struct tty_struct *tty = tty_port_tty_get(&info->tport); m68328_uart *uart; unsigned short rx; unsigned short tx; @@ -350,20 +366,24 @@ irqreturn_t rs_interrupt(int irq, void *dev_id) #ifdef USE_INTS tx = uart->utx.w; - if (rx & URX_DATA_READY) receive_chars(info, rx); - if (tx & UTX_TX_AVAIL) transmit_chars(info); + if (rx & URX_DATA_READY) + receive_chars(info, tty, rx); + if (tx & UTX_TX_AVAIL) + transmit_chars(info, tty); #else - receive_chars(info, rx); + receive_chars(info, tty, rx); #endif + tty_kref_put(tty); + return IRQ_HANDLED; } -static int startup(struct m68k_serial * info) +static int startup(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; - if (info->flags & S_INITIALIZED) + if (info->tport.flags & ASYNC_INITIALIZED) return 0; if (!info->xmit_buf) { @@ -380,7 +400,6 @@ static int startup(struct m68k_serial * info) */ uart->ustcnt = USTCNT_UEN; - info->xmit_fifo_size = 1; uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN; (void)uart->urx.w; @@ -394,17 +413,17 @@ static int startup(struct m68k_serial * info) uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK; #endif - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); + if (tty) + clear_bit(TTY_IO_ERROR, &tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* * and set the speed of the serial port */ - change_speed(info); + change_speed(info, tty); - info->flags |= S_INITIALIZED; + info->tport.flags |= ASYNC_INITIALIZED; local_irq_restore(flags); return 0; } @@ -413,13 +432,13 @@ static int startup(struct m68k_serial * info) * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void shutdown(struct m68k_serial * info) +static void shutdown(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; uart->ustcnt = 0; /* All off! */ - if (!(info->flags & S_INITIALIZED)) + if (!(info->tport.flags & ASYNC_INITIALIZED)) return; local_irq_save(flags); @@ -429,10 +448,10 @@ static void shutdown(struct m68k_serial * info) info->xmit_buf = 0; } - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); + if (tty) + set_bit(TTY_IO_ERROR, &tty->flags); - info->flags &= ~S_INITIALIZED; + info->tport.flags &= ~ASYNC_INITIALIZED; local_irq_restore(flags); } @@ -488,7 +507,7 @@ struct { * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static void change_speed(struct m68k_serial *info) +static void change_speed(struct m68k_serial *info, struct tty_struct *tty) { m68328_uart *uart = &uart_addr[info->line]; unsigned short port; @@ -496,9 +515,7 @@ static void change_speed(struct m68k_serial *info) unsigned cflag; int i; - if (!info->tty || !info->tty->termios) - return; - cflag = info->tty->termios->c_cflag; + cflag = tty->termios->c_cflag; if (!(port = info->port)) return; @@ -510,7 +527,6 @@ static void change_speed(struct m68k_serial *info) i = (i & ~CBAUDEX) + B38400; } - info->baud = baud_table[i]; uart->ubaud = PUT_FIELD(UBAUD_DIVIDE, hw_baud_table[i].divisor) | PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale); @@ -807,10 +823,10 @@ static int get_serial_info(struct m68k_serial * info, tmp.line = info->line; tmp.port = info->port; tmp.irq = info->irq; - tmp.flags = info->flags; + tmp.flags = info->tport.flags; tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; + tmp.close_delay = info->tport.close_delay; + tmp.closing_wait = info->tport.closing_wait; tmp.custom_divisor = info->custom_divisor; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; @@ -818,9 +834,10 @@ static int get_serial_info(struct m68k_serial * info, return 0; } -static int set_serial_info(struct m68k_serial * info, +static int set_serial_info(struct m68k_serial *info, struct tty_struct *tty, struct serial_struct * new_info) { + struct tty_port *port = &info->tport; struct serial_struct new_serial; struct m68k_serial old_info; int retval = 0; @@ -834,17 +851,17 @@ static int set_serial_info(struct m68k_serial * info, if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.baud_base != info->baud_base) || (new_serial.type != info->type) || - (new_serial.close_delay != info->close_delay) || - ((new_serial.flags & ~S_USR_MASK) != - (info->flags & ~S_USR_MASK))) + (new_serial.close_delay != port->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (port->flags & ~ASYNC_USR_MASK))) return -EPERM; - info->flags = ((info->flags & ~S_USR_MASK) | - (new_serial.flags & S_USR_MASK)); + port->flags = ((port->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); info->custom_divisor = new_serial.custom_divisor; goto check_and_exit; } - if (info->count > 1) + if (port->count > 1) return -EBUSY; /* @@ -853,14 +870,14 @@ static int set_serial_info(struct m68k_serial * info, */ info->baud_base = new_serial.baud_base; - info->flags = ((info->flags & ~S_FLAGS) | - (new_serial.flags & S_FLAGS)); + port->flags = ((port->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); info->type = new_serial.type; - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; + port->close_delay = new_serial.close_delay; + port->closing_wait = new_serial.closing_wait; check_and_exit: - retval = startup(info); + retval = startup(info, tty); return retval; } @@ -946,7 +963,7 @@ static int rs_ioctl(struct tty_struct *tty, return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: - return set_serial_info(info, + return set_serial_info(info, tty, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, (unsigned int *) arg); @@ -965,7 +982,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - change_speed(info); + change_speed(info, tty); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -988,6 +1005,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) static void rs_close(struct tty_struct *tty, struct file * filp) { struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; + struct tty_port *port = &info->tport; m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; @@ -1001,7 +1019,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) return; } - if ((tty->count == 1) && (info->count != 1)) { + if ((tty->count == 1) && (port->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always @@ -1010,26 +1028,26 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * serial port won't be shutdown. */ printk("rs_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; + "port->count is %d\n", port->count); + port->count = 1; } - if (--info->count < 0) { + if (--port->count < 0) { printk("rs_close: bad serial port count for ttyS%d: %d\n", - info->line, info->count); - info->count = 0; + info->line, port->count); + port->count = 0; } - if (info->count) { + if (port->count) { local_irq_restore(flags); return; } - info->flags |= S_CLOSING; + port->flags |= ASYNC_CLOSING; /* * 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 != S_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the @@ -1040,13 +1058,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp) uart->ustcnt &= ~USTCNT_RXEN; uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); - shutdown(info); + shutdown(info, tty); rs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; - info->event = 0; - info->tty = NULL; + tty_port_tty_set(&info->tport, NULL); #warning "This is not and has never been valid so fix it" #if 0 if (tty->ldisc.num != ldiscs[N_TTY].num) { @@ -1058,14 +1075,13 @@ static void rs_close(struct tty_struct *tty, struct file * filp) (tty->ldisc.open)(tty); } #endif - if (info->blocked_open) { - if (info->close_delay) { - msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } - wake_up_interruptible(&info->open_wait); + if (port->blocked_open) { + if (port->close_delay) + msleep_interruptible(jiffies_to_msecs(port->close_delay)); + wake_up_interruptible(&port->open_wait); } - info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); - wake_up_interruptible(&info->close_wait); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); + wake_up_interruptible(&port->close_wait); local_irq_restore(flags); } @@ -1080,107 +1096,14 @@ void rs_hangup(struct tty_struct *tty) return; rs_flush_buffer(tty); - shutdown(info); - info->event = 0; - info->count = 0; - info->flags &= ~S_NORMAL_ACTIVE; - info->tty = NULL; - wake_up_interruptible(&info->open_wait); + shutdown(info, tty); + info->tport.count = 0; + info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; + tty_port_tty_set(&info->tport, NULL); + wake_up_interruptible(&info->tport.open_wait); } /* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct m68k_serial *info) -{ - DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (info->flags & S_CLOSING) { - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - if (info->flags & S_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - info->flags |= S_NORMAL_ACTIVE; - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - /* - * 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 - * 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); - - info->count--; - info->blocked_open++; - while (1) { - local_irq_disable(); - m68k_rtsdtr(info, 1); - local_irq_enable(); - current->state = TASK_INTERRUPTIBLE; - if (tty_hung_up_p(filp) || - !(info->flags & S_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & S_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & S_CLOSING) && do_clocal) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - tty_unlock(); - schedule(); - tty_lock(); - } - current->state = TASK_RUNNING; - remove_wait_queue(&info->open_wait, &wait); - if (!tty_hung_up_p(filp)) - info->count++; - info->blocked_open--; - - if (retval) - return retval; - info->flags |= S_NORMAL_ACTIVE; - return 0; -} - -/* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its S structure into * the IRQ chain. It also performs the serial-specific @@ -1196,18 +1119,18 @@ int rs_open(struct tty_struct *tty, struct file * filp) if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV; - info->count++; + info->tport.count++; tty->driver_data = info; - info->tty = tty; + tty_port_tty_set(&info->tport, tty); /* * Start up serial port */ - retval = startup(info); + retval = startup(info, tty); if (retval) return retval; - return block_til_ready(tty, filp, info); + return tty_port_block_til_ready(&info->tport, tty, filp); } /* Finally, routines used to initialize the serial driver. */ @@ -1235,11 +1158,15 @@ static const struct tty_operations rs_ops = { .set_ldisc = rs_set_ldisc, }; +static const struct tty_port_operations rs_port_ops = { +}; + /* rs_init inits the driver */ static int __init rs68328_init(void) { - int flags, i; + unsigned long flags; + int i; struct m68k_serial *info; serial_driver = alloc_tty_driver(NR_PORTS); @@ -1273,19 +1200,13 @@ rs68328_init(void) for(i=0;i<NR_PORTS;i++) { info = &m68k_soft[i]; + tty_port_init(&info->tport); + info->tport.ops = &rs_port_ops; info->magic = SERIAL_MAGIC; info->port = (int) &uart_addr[i]; - info->tty = NULL; info->irq = uart_irqs[i]; info->custom_divisor = 16; - info->close_delay = 50; - info->closing_wait = 3000; info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); info->line = i; info->is_cons = 1; /* Means shortcuts work */ diff --git a/drivers/tty/serial/68328serial.h b/drivers/tty/serial/68328serial.h deleted file mode 100644 index 3d2faab..0000000 --- a/drivers/tty/serial/68328serial.h +++ /dev/null @@ -1,186 +0,0 @@ -/* 68328serial.h: Definitions for the mc68328 serial driver. - * - * Copyright (C) 1995 David S. Miller <davem@caip.rutgers.edu> - * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com> - * Copyright (C) 1998, 1999 D. Jeff Dionne <jeff@uclinux.org> - * Copyright (C) 1999 Vladimir Gurevich <vgurevic@cisco.com> - * - * VZ Support/Fixes Evan Stawnyczy <e@lineo.ca> - */ - -#ifndef _MC683XX_SERIAL_H -#define _MC683XX_SERIAL_H - - -struct serial_struct { - int type; - int line; - int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char reserved_char[2]; - int hub6; /* FIXME: We don't have AT&T Hub6 boards! */ - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - int reserved[4]; -}; - -/* - * For the close wait times, 0 means wait forever for serial port to - * flush its output. 65535 means don't wait at all. - */ -#define S_CLOSING_WAIT_INF 0 -#define S_CLOSING_WAIT_NONE 65535 - -/* - * Definitions for S_struct (and serial_struct) flags field - */ -#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes - on the callout port */ -#define S_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ -#define S_SAK 0x0004 /* Secure Attention Key (Orange book) */ -#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ - -#define S_SPD_MASK 0x0030 -#define S_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ - -#define S_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ -#define S_SPD_CUST 0x0030 /* Use user-specified divisor */ - -#define S_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ -#define S_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ -#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ -#define S_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ -#define S_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ - -#define S_FLAGS 0x0FFF /* Possible legal S flags */ -#define S_USR_MASK 0x0430 /* Legal flags that non-privileged - * users can set or reset */ - -/* Internal flags used only by kernel/chr_drv/serial.c */ -#define S_INITIALIZED 0x80000000 /* Serial port was initialized */ -#define S_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ -#define S_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ -#define S_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ -#define S_CLOSING 0x08000000 /* Serial port is closing */ -#define S_CTS_FLOW 0x04000000 /* Do CTS flow control */ -#define S_CHECK_CD 0x02000000 /* i.e., CLOCAL */ - -/* Software state per channel */ - -#ifdef __KERNEL__ - -/* - * I believe this is the optimal setting that reduces the number of interrupts. - * At high speeds the output might become a little "bursted" (use USTCNT_TXHE - * if that bothers you), but in most cases it will not, since we try to - * transmit characters every time rs_interrupt is called. Thus, quite often - * you'll see that a receive interrupt occures before the transmit one. - * -- Vladimir Gurevich - */ -#define USTCNT_TX_INTR_MASK (USTCNT_TXEE) - -/* - * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special - * "Old data interrupt" which occures whenever the data stay in the FIFO - * longer than 30 bits time. This allows us to use FIFO without compromising - * latency. '328 does not have this feature and without the real 328-based - * board I would assume that RXRE is the safest setting. - * - * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of - * interrupts. RXFE (receive queue full) causes the system to lose data - * at least at 115200 baud - * - * If your board is busy doing other stuff, you might consider to use - * RXRE (data ready intrrupt) instead. - * - * The other option is to make these INTR masks run-time configurable, so - * that people can dynamically adapt them according to the current usage. - * -- Vladimir Gurevich - */ - -/* (es) */ -#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN) -#elif defined(CONFIG_M68328) -#define USTCNT_RX_INTR_MASK (USTCNT_RXRE) -#else -#error Please, define the Rx interrupt events for your CPU -#endif -/* (/es) */ - -/* - * This is our internal structure for each serial port's state. - * - * Many fields are paralleled by the structure used by the serial_struct - * structure. - * - * For definitions of the flags field, see tty.h - */ - -struct m68k_serial { - char soft_carrier; /* Use soft carrier on this channel */ - char break_abort; /* Is serial console in, so process brk/abrt */ - char is_cons; /* Is this our console. */ - - /* We need to know the current clock divisor - * to read the bps rate the chip has currently - * loaded. - */ - unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ - int baud; - int magic; - int baud_base; - int port; - int irq; - int flags; /* defined in tty.h */ - int type; /* UART type */ - struct tty_struct *tty; - int read_status_mask; - int ignore_status_mask; - int timeout; - int xmit_fifo_size; - int custom_divisor; - 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 count; /* # of fd on device */ - int blocked_open; /* # of blocked opens */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; -}; - - -#define SERIAL_MAGIC 0x5301 - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#define SERIAL_XMIT_SIZE 4096 - -/* - * Events are used to schedule things to happen at timer-interrupt - * time, instead of at rs interrupt time. - */ -#define RS_EVENT_WRITE_WAKEUP 0 - -/* - * Define the number of ports supported and their irqs. - */ -#define NR_PORTS 1 -#define UART_IRQ_DEFNS {UART_IRQ_NUM} - -#endif /* __KERNEL__ */ -#endif /* !(_MC683XX_SERIAL_H) */ diff --git a/drivers/tty/serial/8250/8250.c b/drivers/tty/serial/8250/8250.c index 5c27f7e..182efcc9 100644 --- a/drivers/tty/serial/8250/8250.c +++ b/drivers/tty/serial/8250/8250.c @@ -568,6 +568,16 @@ static void serial8250_clear_fifos(struct uart_8250_port *p) } } +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) +{ + unsigned char fcr; + + serial8250_clear_fifos(p); + fcr = uart_config[p->port.type].fcr; + serial_out(p, UART_FCR, fcr); +} +EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); + /* * IER sleep support. UARTs which have EFRs need the "extended * capability" bit enabled. Note that on XR16C850s, we need to @@ -1332,27 +1342,6 @@ static void serial8250_enable_ms(struct uart_port *port) } /* - * Clear the Tegra rx fifo after a break - * - * FIXME: This needs to become a port specific callback once we have a - * framework for this - */ -static void clear_rx_fifo(struct uart_8250_port *up) -{ - unsigned int status, tmout = 10000; - do { - status = serial_in(up, UART_LSR); - if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) - status = serial_in(up, UART_RX); - else - break; - if (--tmout == 0) - break; - udelay(1); - } while (1); -} - -/* * serial8250_rx_chars: processes according to the passed in LSR * value, and returns the remaining LSR bits not handled * by this Rx routine. @@ -1386,20 +1375,10 @@ serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) up->lsr_saved_flags = 0; if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { - /* - * For statistics only - */ if (lsr & UART_LSR_BI) { lsr &= ~(UART_LSR_FE | UART_LSR_PE); port->icount.brk++; /* - * If tegra port then clear the rx fifo to - * accept another break/character. - */ - if (port->type == PORT_TEGRA) - clear_rx_fifo(up); - - /* * We do the SysRQ and SAK checking * here because otherwise the break * may get masked by ignore_status_mask @@ -3037,6 +3016,7 @@ static int __devinit serial8250_probe(struct platform_device *dev) port.serial_in = p->serial_in; port.serial_out = p->serial_out; port.handle_irq = p->handle_irq; + port.handle_break = p->handle_break; port.set_termios = p->set_termios; port.pm = p->pm; port.dev = &dev->dev; @@ -3209,6 +3189,8 @@ int serial8250_register_port(struct uart_port *port) uart->port.set_termios = port->set_termios; if (port->pm) uart->port.pm = port->pm; + if (port->handle_break) + uart->port.handle_break = port->handle_break; if (serial8250_isa_config != NULL) serial8250_isa_config(0, &uart->port, diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 2868a1d..c9d0ebe 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -96,6 +96,8 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) up->port.serial_out(&up->port, offset, value); } +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p); + #if defined(__alpha__) && !defined(CONFIG_PCI) /* * Digital did something really horribly wrong with the OUT1 and OUT2 diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 858dca8..24ea98c 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/tty.h> +#include <linux/serial_reg.h> #include <linux/serial_core.h> #include <linux/8250_pci.h> #include <linux/bitops.h> @@ -1092,11 +1093,49 @@ static int skip_tx_en_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static void kt_handle_break(struct uart_port *p) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + /* + * On receipt of a BI, serial device in Intel ME (Intel + * management engine) needs to have its fifos cleared for sane + * SOL (Serial Over Lan) output. + */ + serial8250_clear_and_reinit_fifos(up); +} + +static unsigned int kt_serial_in(struct uart_port *p, int offset) +{ + struct uart_8250_port *up = + container_of(p, struct uart_8250_port, port); + unsigned int val; + + /* + * When the Intel ME (management engine) gets reset its serial + * port registers could return 0 momentarily. Functions like + * serial8250_console_write, read and save the IER, perform + * some operation and then restore it. In order to avoid + * setting IER register inadvertently to 0, if the value read + * is 0, double check with ier value in uart_8250_port and use + * that instead. up->ier should be the same value as what is + * currently configured. + */ + val = inb(p->iobase + offset); + if (offset == UART_IER) { + if (val == 0) + val = up->ier; + } + return val; +} + static int kt_serial_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_port *port, int idx) { port->flags |= UPF_BUG_THRE; + port->serial_in = kt_serial_in; + port->handle_break = kt_handle_break; return skip_tx_en_setup(priv, board, port, idx); } @@ -2775,6 +2814,12 @@ void pciserial_suspend_ports(struct serial_private *priv) for (i = 0; i < priv->nr; i++) if (priv->line[i] >= 0) serial8250_suspend_port(priv->line[i]); + + /* + * Ensure that every init quirk is properly torn down + */ + if (priv->quirk->exit) + priv->quirk->exit(priv->dev); } EXPORT_SYMBOL_GPL(pciserial_suspend_ports); diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 3d569cd..2d13914 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -67,30 +67,6 @@ #define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE) #define UART_DUMMY_DR_RX (1 << 16) - -#define UART_WA_SAVE_NR 14 - -static void pl011_lockup_wa(unsigned long data); -static const u32 uart_wa_reg[UART_WA_SAVE_NR] = { - ST_UART011_DMAWM, - ST_UART011_TIMEOUT, - ST_UART011_LCRH_RX, - UART011_IBRD, - UART011_FBRD, - ST_UART011_LCRH_TX, - UART011_IFLS, - ST_UART011_XFCR, - ST_UART011_XON1, - ST_UART011_XON2, - ST_UART011_XOFF1, - ST_UART011_XOFF2, - UART011_CR, - UART011_IMSC -}; - -static u32 uart_wa_regdata[UART_WA_SAVE_NR]; -static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0); - /* There is by now at least one vendor with differing details, so handle it */ struct vendor_data { unsigned int ifls; @@ -100,6 +76,7 @@ struct vendor_data { bool oversampling; bool interrupt_may_hang; /* vendor-specific */ bool dma_threshold; + bool cts_event_workaround; }; static struct vendor_data vendor_arm = { @@ -109,6 +86,7 @@ static struct vendor_data vendor_arm = { .lcrh_rx = UART011_LCRH, .oversampling = false, .dma_threshold = false, + .cts_event_workaround = false, }; static struct vendor_data vendor_st = { @@ -119,6 +97,7 @@ static struct vendor_data vendor_st = { .oversampling = true, .interrupt_may_hang = true, .dma_threshold = true, + .cts_event_workaround = true, }; static struct uart_amba_port *amba_ports[UART_NR]; @@ -1054,69 +1033,6 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) #define pl011_dma_flush_buffer NULL #endif - -/* - * pl011_lockup_wa - * This workaround aims to break the deadlock situation - * when after long transfer over uart in hardware flow - * control, uart interrupt registers cannot be cleared. - * Hence uart transfer gets blocked. - * - * It is seen that during such deadlock condition ICR - * don't get cleared even on multiple write. This leads - * pass_counter to decrease and finally reach zero. This - * can be taken as trigger point to run this UART_BT_WA. - * - */ -static void pl011_lockup_wa(unsigned long data) -{ - struct uart_amba_port *uap = amba_ports[0]; - void __iomem *base = uap->port.membase; - struct circ_buf *xmit = &uap->port.state->xmit; - struct tty_struct *tty = uap->port.state->port.tty; - int buf_empty_retries = 200; - int loop; - - /* Stop HCI layer from submitting data for tx */ - tty->hw_stopped = 1; - while (!uart_circ_empty(xmit)) { - if (buf_empty_retries-- == 0) - break; - udelay(100); - } - - /* Backup registers */ - for (loop = 0; loop < UART_WA_SAVE_NR; loop++) - uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]); - - /* Disable UART so that FIFO data is flushed out */ - writew(0x00, uap->port.membase + UART011_CR); - - /* Soft reset UART module */ - if (uap->port.dev->platform_data) { - struct amba_pl011_data *plat; - - plat = uap->port.dev->platform_data; - if (plat->reset) - plat->reset(); - } - - /* Restore registers */ - for (loop = 0; loop < UART_WA_SAVE_NR; loop++) - writew(uart_wa_regdata[loop] , - uap->port.membase + uart_wa_reg[loop]); - - /* Initialise the old status of the modem signals */ - uap->old_status = readw(uap->port.membase + UART01x_FR) & - UART01x_FR_MODEM_ANY; - - if (readl(base + UART011_MIS) & 0x2) - printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n"); - - /* Start Tx/Rx */ - tty->hw_stopped = 0; -} - static void pl011_stop_tx(struct uart_port *port) { struct uart_amba_port *uap = (struct uart_amba_port *)port; @@ -1245,12 +1161,26 @@ static irqreturn_t pl011_int(int irq, void *dev_id) unsigned long flags; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; int handled = 0; + unsigned int dummy_read; spin_lock_irqsave(&uap->port.lock, flags); status = readw(uap->port.membase + UART011_MIS); if (status) { do { + if (uap->vendor->cts_event_workaround) { + /* workaround to make sure that all bits are unlocked.. */ + writew(0x00, uap->port.membase + UART011_ICR); + + /* + * WA: introduce 26ns(1 uart clk) delay before W1C; + * single apb access will incur 2 pclk(133.12Mhz) delay, + * so add 2 dummy reads + */ + dummy_read = readw(uap->port.membase + UART011_ICR); + dummy_read = readw(uap->port.membase + UART011_ICR); + } + writew(status & ~(UART011_TXIS|UART011_RTIS| UART011_RXIS), uap->port.membase + UART011_ICR); @@ -1267,11 +1197,8 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (status & UART011_TXIS) pl011_tx_chars(uap); - if (pass_counter-- == 0) { - if (uap->interrupt_may_hang) - tasklet_schedule(&pl011_lockup_tlet); + if (pass_counter-- == 0) break; - } status = readw(uap->port.membase + UART011_MIS); } while (status != 0); diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 5b07c0c..80b6b1b 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -952,19 +952,6 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = /* Input */ #define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) - -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the memcpy_fromfs blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf; -static DEFINE_MUTEX(tmp_buf_mutex); - /* Calculate the chartime depending on baudrate, numbor of bits etc. */ static void update_char_time(struct e100_serial * info) { @@ -3150,7 +3137,7 @@ static int rs_raw_write(struct tty_struct *tty, /* first some sanity checks */ - if (!tty || !info->xmit.buf || !tmp_buf) + if (!tty || !info->xmit.buf) return 0; #ifdef SERIAL_DEBUG_DATA @@ -4106,7 +4093,6 @@ rs_open(struct tty_struct *tty, struct file * filp) { struct e100_serial *info; int retval; - unsigned long page; int allocated_resources = 0; info = rs_table + tty->index; @@ -4124,17 +4110,6 @@ rs_open(struct tty_struct *tty, struct file * filp) tty->low_latency = !!(info->flags & ASYNC_LOW_LATENCY); - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) { - return -ENOMEM; - } - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } - /* * If the port is in the middle of closing, bail out now */ @@ -4487,6 +4462,7 @@ static int __init rs_init(void) info->enabled = 0; } } + tty_port_init(&info->port); info->uses_dma_in = 0; info->uses_dma_out = 0; info->line = i; diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index e8c9cee..5410c06 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c @@ -12,10 +12,13 @@ #include <linux/init.h> #include <linux/module.h> #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> +#include <linux/of_serial.h> #include <linux/of_platform.h> #include <linux/nwpserial.h> @@ -24,6 +27,26 @@ struct of_serial_info { int line; }; +#ifdef CONFIG_ARCH_TEGRA +void tegra_serial_handle_break(struct uart_port *p) +{ + unsigned int status, tmout = 10000; + + do { + status = p->serial_in(p, UART_LSR); + if (status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) + status = p->serial_in(p, UART_RX); + else + break; + if (--tmout == 0) + break; + udelay(1); + } while (1); +} +/* FIXME remove this export when tegra finishes conversion to open firmware */ +EXPORT_SYMBOL_GPL(tegra_serial_handle_break); +#endif + /* * Fill a struct uart_port for a given device node */ @@ -84,6 +107,9 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev, | UPF_FIXED_PORT | UPF_FIXED_TYPE; port->dev = &ofdev->dev; + if (type == PORT_TEGRA) + port->handle_break = tegra_serial_handle_break; + return 0; } diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index d00b38e..d3cda0c 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -44,6 +44,13 @@ #include <plat/dmtimer.h> #include <plat/omap-serial.h> +#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y)) + +#define OMAP_UART_REV_42 0x0402 +#define OMAP_UART_REV_46 0x0406 +#define OMAP_UART_REV_52 0x0502 +#define OMAP_UART_REV_63 0x0603 + #define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/ /* SCR register bitmasks */ @@ -53,6 +60,17 @@ #define OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT 6 #define OMAP_UART_FCR_RX_FIFO_TRIG_MASK (0x3 << 6) +/* MVR register bitmasks */ +#define OMAP_UART_MVR_SCHEME_SHIFT 30 + +#define OMAP_UART_LEGACY_MVR_MAJ_MASK 0xf0 +#define OMAP_UART_LEGACY_MVR_MAJ_SHIFT 4 +#define OMAP_UART_LEGACY_MVR_MIN_MASK 0x0f + +#define OMAP_UART_MVR_MAJ_MASK 0x700 +#define OMAP_UART_MVR_MAJ_SHIFT 8 +#define OMAP_UART_MVR_MIN_MASK 0x3f + static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS]; /* Forward declaration of functions */ @@ -1346,6 +1364,59 @@ static void uart_tx_dma_callback(int lch, u16 ch_status, void *data) return; } +static void omap_serial_fill_features_erratas(struct uart_omap_port *up) +{ + u32 mvr, scheme; + u16 revision, major, minor; + + mvr = serial_in(up, UART_OMAP_MVER); + + /* Check revision register scheme */ + scheme = mvr >> OMAP_UART_MVR_SCHEME_SHIFT; + + switch (scheme) { + case 0: /* Legacy Scheme: OMAP2/3 */ + /* MINOR_REV[0:4], MAJOR_REV[4:7] */ + major = (mvr & OMAP_UART_LEGACY_MVR_MAJ_MASK) >> + OMAP_UART_LEGACY_MVR_MAJ_SHIFT; + minor = (mvr & OMAP_UART_LEGACY_MVR_MIN_MASK); + break; + case 1: + /* New Scheme: OMAP4+ */ + /* MINOR_REV[0:5], MAJOR_REV[8:10] */ + major = (mvr & OMAP_UART_MVR_MAJ_MASK) >> + OMAP_UART_MVR_MAJ_SHIFT; + minor = (mvr & OMAP_UART_MVR_MIN_MASK); + break; + default: + dev_warn(&up->pdev->dev, + "Unknown %s revision, defaulting to highest\n", + up->name); + /* highest possible revision */ + major = 0xff; + minor = 0xff; + } + + /* normalize revision for the driver */ + revision = UART_BUILD_REVISION(major, minor); + + switch (revision) { + case OMAP_UART_REV_46: + up->errata |= (UART_ERRATA_i202_MDR1_ACCESS | + UART_ERRATA_i291_DMA_FORCEIDLE); + break; + case OMAP_UART_REV_52: + up->errata |= (UART_ERRATA_i202_MDR1_ACCESS | + UART_ERRATA_i291_DMA_FORCEIDLE); + break; + case OMAP_UART_REV_63: + up->errata |= UART_ERRATA_i202_MDR1_ACCESS; + break; + default: + break; + } +} + static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) { struct omap_uart_port_info *omap_up_info; @@ -1439,7 +1510,6 @@ static int serial_omap_probe(struct platform_device *pdev) "%d\n", DEFAULT_CLK_SPEED); } up->uart_dma.uart_base = mem->start; - up->errata = omap_up_info->errata; if (omap_up_info->dma_enabled) { up->uart_dma.uart_dma_tx = dma_tx->start; @@ -1469,6 +1539,8 @@ static int serial_omap_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); + omap_serial_fill_features_erratas(up); + ui[up->port.line] = up; serial_omap_add_console_port(up); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index c2816f4..4fdec6a6 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -39,6 +39,7 @@ enum { PCH_UART_HANDLED_RX_ERR_INT_SHIFT, PCH_UART_HANDLED_RX_TRG_INT_SHIFT, PCH_UART_HANDLED_MS_INT_SHIFT, + PCH_UART_HANDLED_LS_INT_SHIFT, }; enum { @@ -63,6 +64,8 @@ enum { PCH_UART_HANDLED_RX_TRG_INT_SHIFT)<<1)) #define PCH_UART_HANDLED_MS_INT (1<<((PCH_UART_HANDLED_MS_INT_SHIFT)<<1)) +#define PCH_UART_HANDLED_LS_INT (1<<((PCH_UART_HANDLED_LS_INT_SHIFT)<<1)) + #define PCH_UART_RBR 0x00 #define PCH_UART_THR 0x00 @@ -229,7 +232,6 @@ struct eg20t_port { int start_tx; int start_rx; int tx_empty; - int int_dis_flag; int trigger; int trigger_level; struct pch_uart_buffer rxbuf; @@ -237,7 +239,6 @@ struct eg20t_port { unsigned int fcr; unsigned int mcr; unsigned int use_dma; - unsigned int use_dma_flag; struct dma_async_tx_descriptor *desc_tx; struct dma_async_tx_descriptor *desc_rx; struct pch_dma_slave param_tx; @@ -560,14 +561,10 @@ static int pch_uart_hal_read(struct eg20t_port *priv, unsigned char *buf, return i; } -static unsigned int pch_uart_hal_get_iid(struct eg20t_port *priv) +static unsigned char pch_uart_hal_get_iid(struct eg20t_port *priv) { - unsigned int iir; - int ret; - - iir = ioread8(priv->membase + UART_IIR); - ret = (iir & (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP)); - return ret; + return ioread8(priv->membase + UART_IIR) &\ + (PCH_UART_IIR_IID | PCH_UART_IIR_TOI | PCH_UART_IIR_IP); } static u8 pch_uart_hal_get_line_status(struct eg20t_port *priv) @@ -666,10 +663,13 @@ static void pch_free_dma(struct uart_port *port) dma_release_channel(priv->chan_rx); priv->chan_rx = NULL; } - if (sg_dma_address(&priv->sg_rx)) - dma_free_coherent(port->dev, port->fifosize, - sg_virt(&priv->sg_rx), - sg_dma_address(&priv->sg_rx)); + + if (priv->rx_buf_dma) { + dma_free_coherent(port->dev, port->fifosize, priv->rx_buf_virt, + priv->rx_buf_dma); + priv->rx_buf_virt = NULL; + priv->rx_buf_dma = 0; + } return; } @@ -1053,12 +1053,17 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) unsigned int handled; u8 lsr; int ret = 0; - unsigned int iid; + unsigned char iid; unsigned long flags; + int next = 1; + u8 msr; spin_lock_irqsave(&priv->port.lock, flags); handled = 0; - while ((iid = pch_uart_hal_get_iid(priv)) > 1) { + while (next) { + iid = pch_uart_hal_get_iid(priv); + if (iid & PCH_UART_IIR_IP) /* No Interrupt */ + break; switch (iid) { case PCH_UART_IID_RLS: /* Receiver Line Status */ lsr = pch_uart_hal_get_line_status(priv); @@ -1066,6 +1071,8 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) UART_LSR_PE | UART_LSR_OE)) { pch_uart_err_ir(priv, lsr); ret = PCH_UART_HANDLED_RX_ERR_INT; + } else { + ret = PCH_UART_HANDLED_LS_INT; } break; case PCH_UART_IID_RDR: /* Received Data Ready */ @@ -1092,20 +1099,22 @@ static irqreturn_t pch_uart_interrupt(int irq, void *dev_id) ret = handle_tx(priv); break; case PCH_UART_IID_MS: /* Modem Status */ - ret = PCH_UART_HANDLED_MS_INT; + msr = pch_uart_hal_get_modem(priv); + next = 0; /* MS ir prioirty is the lowest. So, MS ir + means final interrupt */ + if ((msr & UART_MSR_ANY_DELTA) == 0) + break; + ret |= PCH_UART_HANDLED_MS_INT; break; default: /* Never junp to this label */ - dev_err(priv->port.dev, "%s:iid=%d (%lu)\n", __func__, + dev_err(priv->port.dev, "%s:iid=%02x (%lu)\n", __func__, iid, jiffies); ret = -1; + next = 0; break; } handled |= (unsigned int)ret; } - if (handled == 0 && iid <= 1) { - if (priv->int_dis_flag) - priv->int_dis_flag = 0; - } spin_unlock_irqrestore(&priv->port.lock, flags); return IRQ_RETVAL(handled); @@ -1200,7 +1209,6 @@ static void pch_uart_stop_rx(struct uart_port *port) priv = container_of(port, struct eg20t_port, port); priv->start_rx = 0; pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_RX_INT); - priv->int_dis_flag = 1; } /* Enable the modem status interrupts. */ @@ -1447,7 +1455,6 @@ static int pch_uart_verify_port(struct uart_port *port, __func__); return -EOPNOTSUPP; #endif - priv->use_dma_flag = 1; dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n"); if (!priv->use_dma) pch_request_dma(port); diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 6c9b7cd..91e326f 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -185,25 +185,19 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ } - /** - * tty_buffer_request_room - grow tty buffer if needed + * __tty_buffer_request_room - grow tty buffer if needed * @tty: tty structure * @size: size desired * * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. - * - * Locking: Takes tty->buf.lock + * Locking: Caller must hold tty->buf.lock */ -int tty_buffer_request_room(struct tty_struct *tty, size_t size) +static int __tty_buffer_request_room(struct tty_struct *tty, size_t size) { struct tty_buffer *b, *n; int left; - unsigned long flags; - - spin_lock_irqsave(&tty->buf.lock, flags); - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to remove this conditional if its worth it. This would be invisible to the callers */ @@ -225,9 +219,30 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size) size = left; } - spin_unlock_irqrestore(&tty->buf.lock, flags); return size; } + + +/** + * tty_buffer_request_room - grow tty buffer if needed + * @tty: tty structure + * @size: size desired + * + * Make at least size bytes of linear space available for the tty + * buffer. If we fail return the size we managed to find. + * + * Locking: Takes tty->buf.lock + */ +int tty_buffer_request_room(struct tty_struct *tty, size_t size) +{ + unsigned long flags; + int length; + + spin_lock_irqsave(&tty->buf.lock, flags); + length = __tty_buffer_request_room(tty, size); + spin_unlock_irqrestore(&tty->buf.lock, flags); + return length; +} EXPORT_SYMBOL_GPL(tty_buffer_request_room); /** @@ -249,14 +264,22 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int space = tty_buffer_request_room(tty, goal); - struct tty_buffer *tb = tty->buf.tail; + int space; + unsigned long flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, flags); + space = __tty_buffer_request_room(tty, goal); + tb = tty->buf.tail; /* If there is no space then tb may be NULL */ - if (unlikely(space == 0)) + if (unlikely(space == 0)) { + spin_unlock_irqrestore(&tty->buf.lock, flags); break; + } memcpy(tb->char_buf_ptr + tb->used, chars, space); memset(tb->flag_buf_ptr + tb->used, flag, space); tb->used += space; + spin_unlock_irqrestore(&tty->buf.lock, flags); copied += space; chars += space; /* There is a small chance that we need to split the data over @@ -286,14 +309,22 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int space = tty_buffer_request_room(tty, goal); - struct tty_buffer *tb = tty->buf.tail; + int space; + unsigned long __flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, __flags); + space = __tty_buffer_request_room(tty, goal); + tb = tty->buf.tail; /* If there is no space then tb may be NULL */ - if (unlikely(space == 0)) + if (unlikely(space == 0)) { + spin_unlock_irqrestore(&tty->buf.lock, __flags); break; + } memcpy(tb->char_buf_ptr + tb->used, chars, space); memcpy(tb->flag_buf_ptr + tb->used, flags, space); tb->used += space; + spin_unlock_irqrestore(&tty->buf.lock, __flags); copied += space; chars += space; flags += space; @@ -344,13 +375,20 @@ EXPORT_SYMBOL(tty_schedule_flip); int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) { - int space = tty_buffer_request_room(tty, size); + int space; + unsigned long flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, flags); + space = __tty_buffer_request_room(tty, size); + + tb = tty->buf.tail; if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; *chars = tb->char_buf_ptr + tb->used; memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); tb->used += space; } + spin_unlock_irqrestore(&tty->buf.lock, flags); return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string); @@ -374,13 +412,20 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) { - int space = tty_buffer_request_room(tty, size); + int space; + unsigned long __flags; + struct tty_buffer *tb; + + spin_lock_irqsave(&tty->buf.lock, __flags); + space = __tty_buffer_request_room(tty, size); + + tb = tty->buf.tail; if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; *chars = tb->char_buf_ptr + tb->used; *flags = tb->flag_buf_ptr + tb->used; tb->used += space; } + spin_unlock_irqrestore(&tty->buf.lock, __flags); return space; } EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 2156188..84cbf29 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -3892,36 +3892,6 @@ static void set_palette(struct vc_data *vc) vc->vc_sw->con_set_palette(vc, color_table); } -static int set_get_cmap(unsigned char __user *arg, int set) -{ - int i, j, k; - - WARN_CONSOLE_UNLOCKED(); - - for (i = 0; i < 16; i++) - if (set) { - get_user(default_red[i], arg++); - get_user(default_grn[i], arg++); - get_user(default_blu[i], arg++); - } else { - put_user(default_red[i], arg++); - put_user(default_grn[i], arg++); - put_user(default_blu[i], arg++); - } - if (set) { - for (i = 0; i < MAX_NR_CONSOLES; i++) - if (vc_cons_allocated(i)) { - for (j = k = 0; j < 16; j++) { - vc_cons[i].d->vc_palette[k++] = default_red[j]; - vc_cons[i].d->vc_palette[k++] = default_grn[j]; - vc_cons[i].d->vc_palette[k++] = default_blu[j]; - } - set_palette(vc_cons[i].d); - } - } - return 0; -} - /* * Load palette into the DAC registers. arg points to a colour * map, 3 bytes per colour, 16 colours, range from 0 to 255. @@ -3929,24 +3899,50 @@ static int set_get_cmap(unsigned char __user *arg, int set) int con_set_cmap(unsigned char __user *arg) { - int rc; + int i, j, k; + unsigned char colormap[3*16]; + + if (copy_from_user(colormap, arg, sizeof(colormap))) + return -EFAULT; console_lock(); - rc = set_get_cmap (arg,1); + for (i = k = 0; i < 16; i++) { + default_red[i] = colormap[k++]; + default_grn[i] = colormap[k++]; + default_blu[i] = colormap[k++]; + } + for (i = 0; i < MAX_NR_CONSOLES; i++) { + if (!vc_cons_allocated(i)) + continue; + for (j = k = 0; j < 16; j++) { + vc_cons[i].d->vc_palette[k++] = default_red[j]; + vc_cons[i].d->vc_palette[k++] = default_grn[j]; + vc_cons[i].d->vc_palette[k++] = default_blu[j]; + } + set_palette(vc_cons[i].d); + } console_unlock(); - return rc; + return 0; } int con_get_cmap(unsigned char __user *arg) { - int rc; + int i, k; + unsigned char colormap[3*16]; console_lock(); - rc = set_get_cmap (arg,0); + for (i = k = 0; i < 16; i++) { + colormap[k++] = default_red[i]; + colormap[k++] = default_grn[i]; + colormap[k++] = default_blu[i]; + } console_unlock(); - return rc; + if (copy_to_user(arg, colormap, sizeof(colormap))) + return -EFAULT; + + return 0; } void reset_palette(struct vc_data *vc) |