* - don't use the panic function in serial167_init
* - do resource release on failure on serial167_init
* - include missing restore_flags in mvme167_serial_console_setup
+ *
+ * Kars de Jong <jongk@linux-m68k.org> - 2004/09/06
+ * - replace bottom half handler with task queue handler
*/
#include <linux/config.h>
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/module.h>
+#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/bitops.h>
#include <asm/mvme16xhw.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
#define SERIAL_TYPE_NORMAL 1
-DECLARE_TASK_QUEUE(tq_cyclades);
-
static struct tty_driver *cy_serial_driver;
extern int serial_console;
static struct cyclades_port *serial_console_info = NULL;
{-1 }, /* ttyS2 */
{-1 }, /* ttyS3 */
};
-#define NR_PORTS (sizeof(cy_port)/sizeof(struct cyclades_port))
+#define NR_PORTS ARRAY_SIZE(cy_port)
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
* memory if large numbers of serial ports are open.
*/
static unsigned char *tmp_buf = 0;
-DECLARE_MUTEX(tmp_buf_sem);
/*
* This is used to look up the divisor speeds and the timeouts
cy_sched_event(struct cyclades_port *info, int event)
{
info->event |= 1 << event; /* remember what kind of event and who */
- queue_task(&info->tqueue, &tq_cyclades); /* it belongs to */
- mark_bh(CYCLADES_BH); /* then trigger event */
+ schedule_work(&info->tqueue);
} /* cy_sched_event */
base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
return IRQ_HANDLED;
}
- if (tty->flip.count < TTY_FLIPBUF_SIZE){
- tty->flip.count++;
+ if (tty_buffer_request_room(tty, 1) != 0){
if (err & info->read_status_mask){
if(err & CyBREAK){
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
- *tty->flip.char_buf_ptr++ = data;
+ tty_insert_flip_char(tty, data, TTY_BREAK);
if (info->flags & ASYNC_SAK){
do_SAK(tty);
}
}else if(err & CyFRAME){
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
- *tty->flip.char_buf_ptr++ = data;
+ tty_insert_flip_char(tty, data, TTY_FRAME);
}else if(err & CyPARITY){
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
- *tty->flip.char_buf_ptr++ = data;
+ tty_insert_flip_char(tty, data, TTY_PARITY);
}else if(err & CyOVERRUN){
- *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
/*
If the flip buffer itself is
overflowing, we still loose
the next incoming character.
*/
- if(tty->flip.count < TTY_FLIPBUF_SIZE){
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = data;
- }
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
+ }
/* These two conditions may imply */
/* a normal read should be done. */
/* else if(data & CyTIMEOUT) */
/* else if(data & CySPECHAR) */
}else{
- *tty->flip.flag_buf_ptr++ = 0;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, 0, TTY_NORMAL);
}
}else{
- *tty->flip.flag_buf_ptr++ = 0;
- *tty->flip.char_buf_ptr++ = 0;
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
}
}else{
/* there was a software buffer overrun
and nothing could be done about it!!! */
}
}
- queue_task(&tty->flip.tqueue, &tq_timer);
+ schedule_delayed_work(&tty->flip.work, 1);
/* end of service */
base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
return IRQ_HANDLED;
#endif
while(char_count--){
data = base_addr[CyRDR];
- if (tty->flip.count >= TTY_FLIPBUF_SIZE){
- continue;
- }
- tty->flip.count++;
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
- *tty->flip.char_buf_ptr++ = data;
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
#ifdef CYCLOM_16Y_HACK
udelay(10L);
#endif
}
- queue_task(&tty->flip.tqueue, &tq_timer);
+ schedule_delayed_work(&tty->flip.work, 1);
}
/* end of service */
base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
* This routine is used to handle the "bottom half" processing for the
* serial driver, known also the "software interrupt" processing.
* This processing is done at the kernel interrupt level, after the
- * cy_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
+ * cy#/_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
* is where time-consuming activities which can not be done in the
* interrupt driver proper are done; the interrupt driver schedules
* them using cy_sched_event(), and they get done here.
* This is done through one level of indirection--the task queue.
* When a hardware interrupt service routine wants service by the
* driver's bottom half, it enqueues the appropriate tq_struct (one
- * per port) to the tq_cyclades work queue and sets a request flag
- * via mark_bh for processing that queue. When the time is right,
- * do_cyclades_bh is called (because of the mark_bh) and it requests
+ * per port) to the keventd work queue and sets a request flag
* that the work queue be processed.
*
* Although this may seem unwieldy, it gives the system a way to
* structure) to the bottom half of the driver. Previous kernels
* had to poll every port to see if that port needed servicing.
*/
-static void
-do_cyclades_bh(void)
-{
- run_task_queue(&tq_cyclades);
-} /* do_cyclades_bh */
-
static void
do_softint(void *private_)
{
port is already active, there is no need to kick it.
*/
static int
-cy_write(struct tty_struct * tty, int from_user,
+cy_write(struct tty_struct * tty,
const unsigned char *buf, int count)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
return 0;
}
- if (from_user) {
- down(&tmp_buf_sem);
- while (1) {
- c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0)
- break;
-
- c -= copy_from_user(tmp_buf, buf, c);
- if (!c) {
- if (!total)
- total = -EFAULT;
- break;
- }
-
- local_irq_save(flags);
- c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
+ while (1) {
+ local_irq_save(flags);
+ c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
+ if (c <= 0) {
local_irq_restore(flags);
-
- buf += c;
- count -= c;
- total += c;
+ break;
}
- up(&tmp_buf_sem);
- } else {
- while (1) {
- local_irq_save(flags);
- c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0) {
- local_irq_restore(flags);
- break;
- }
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- local_irq_restore(flags);
+ memcpy(info->xmit_buf + info->xmit_head, buf, c);
+ info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+ info->xmit_cnt += c;
+ local_irq_restore(flags);
- buf += c;
- count -= c;
- total += c;
- }
+ buf += c;
+ count -= c;
+ total += c;
}
if (info->xmit_cnt
info->tty = 0;
if (info->blocked_open) {
if (info->close_delay) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(info->close_delay);
+ msleep_interruptible(jiffies_to_msecs(info->close_delay));
}
wake_up_interruptible(&info->open_wait);
}
return ret;
}
- init_bh(CYCLADES_BH, do_cyclades_bh);
-
port_num = 0;
info = cy_port;
for (index = 0; index < 1; index++) {
info->blocked_open = 0;
info->default_threshold = 0;
info->default_timeout = 0;
- info->tqueue.routine = do_softint;
- info->tqueue.data = info;
+ INIT_WORK(&info->tqueue, do_softint, info);
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
/* info->session */