X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fs390%2Fchar%2Fsclp_vt220.c;h=9e02625c82cfc2853b3fa5be86fb883ddb82c8c2;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=32d4397263e0578f892927f6c23cca9d1ebda334;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 32d439726..9e02625c8 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,6 @@ struct sclp_vt220_request { struct list_head list; struct sclp_req sclp_req; int retry_count; - struct timer_list retry_timer; }; /* VT220 SCCB */ @@ -96,7 +96,7 @@ static int sclp_vt220_initialized = 0; static int sclp_vt220_flush_later; static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf); -static void __sclp_vt220_emit(struct sclp_vt220_request *request); +static int __sclp_vt220_emit(struct sclp_vt220_request *request); static void sclp_vt220_emit_current(void); /* Registration structure for our interest in SCLP event buffers */ @@ -116,55 +116,33 @@ static void sclp_vt220_process_queue(struct sclp_vt220_request *request) { unsigned long flags; - struct sclp_vt220_request *next; void *page; - /* Put buffer back to list of empty buffers */ - page = request->sclp_req.sccb; - spin_lock_irqsave(&sclp_vt220_lock, flags); - /* Move request from outqueue to empty queue */ - list_del(&request->list); - sclp_vt220_outqueue_count--; - list_add_tail((struct list_head *) page, &sclp_vt220_empty); - /* Check if there is a pending buffer on the out queue. */ - next = NULL; - if (!list_empty(&sclp_vt220_outqueue)) - next = list_entry(sclp_vt220_outqueue.next, - struct sclp_vt220_request, list); - spin_unlock_irqrestore(&sclp_vt220_lock, flags); - if (next != NULL) - __sclp_vt220_emit(next); - else if (sclp_vt220_flush_later) + do { + /* Put buffer back to list of empty buffers */ + page = request->sclp_req.sccb; + spin_lock_irqsave(&sclp_vt220_lock, flags); + /* Move request from outqueue to empty queue */ + list_del(&request->list); + sclp_vt220_outqueue_count--; + list_add_tail((struct list_head *) page, &sclp_vt220_empty); + /* Check if there is a pending buffer on the out queue. */ + request = NULL; + if (!list_empty(&sclp_vt220_outqueue)) + request = list_entry(sclp_vt220_outqueue.next, + struct sclp_vt220_request, list); + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + } while (request && __sclp_vt220_emit(request)); + if (request == NULL && sclp_vt220_flush_later) sclp_vt220_emit_current(); wake_up(&sclp_vt220_waitq); /* Check if the tty needs a wake up call */ if (sclp_vt220_tty != NULL) { - if ((sclp_vt220_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - (sclp_vt220_tty->ldisc.write_wakeup != NULL)) - (sclp_vt220_tty->ldisc.write_wakeup)(sclp_vt220_tty); - wake_up_interruptible(&sclp_vt220_tty->write_wait); + tty_wakeup(sclp_vt220_tty); } } -/* - * Retry sclp write request after waiting some time for an sclp equipment - * check to pass. - */ -static void -sclp_vt220_retry(unsigned long data) -{ - struct sclp_vt220_request *request; - struct sclp_vt220_sccb *sccb; - - request = (struct sclp_vt220_request *) data; - request->sclp_req.status = SCLP_REQ_FILLED; - sccb = (struct sclp_vt220_sccb *) request->sclp_req.sccb; - sccb->header.response_code = 0x0000; - sclp_add_request(&request->sclp_req); -} - -#define SCLP_BUFFER_MAX_RETRY 5 -#define SCLP_BUFFER_RETRY_INTERVAL 2 +#define SCLP_BUFFER_MAX_RETRY 1 /* * Callback through which the result of a write request is reported by the @@ -192,29 +170,26 @@ sclp_vt220_callback(struct sclp_req *request, void *data) break; case 0x0340: /* Contained SCLP equipment check */ - if (vt220_request->retry_count++ > SCLP_BUFFER_MAX_RETRY) + if (++vt220_request->retry_count > SCLP_BUFFER_MAX_RETRY) break; /* Remove processed buffers and requeue rest */ if (sclp_remove_processed((struct sccb_header *) sccb) > 0) { /* Not all buffers were processed */ sccb->header.response_code = 0x0000; vt220_request->sclp_req.status = SCLP_REQ_FILLED; - sclp_add_request(request); - return; + if (sclp_add_request(request) == 0) + return; } break; case 0x0040: /* SCLP equipment check */ - if (vt220_request->retry_count++ > SCLP_BUFFER_MAX_RETRY) + if (++vt220_request->retry_count > SCLP_BUFFER_MAX_RETRY) break; - /* Wait some time, then retry request */ - vt220_request->retry_timer.function = sclp_vt220_retry; - vt220_request->retry_timer.data = - (unsigned long) vt220_request; - vt220_request->retry_timer.expires = - jiffies + SCLP_BUFFER_RETRY_INTERVAL*HZ; - add_timer(&vt220_request->retry_timer); - return; + sccb->header.response_code = 0x0000; + vt220_request->sclp_req.status = SCLP_REQ_FILLED; + if (sclp_add_request(request) == 0) + return; + break; default: break; @@ -223,22 +198,22 @@ sclp_vt220_callback(struct sclp_req *request, void *data) } /* - * Emit vt220 request buffer to SCLP. + * Emit vt220 request buffer to SCLP. Return zero on success, non-zero + * otherwise. */ -static void +static int __sclp_vt220_emit(struct sclp_vt220_request *request) { if (!(sclp_vt220_register.sclp_send_mask & EvTyp_VT220Msg_Mask)) { request->sclp_req.status = SCLP_REQ_FAILED; - sclp_vt220_callback(&request->sclp_req, (void *) request); - return; + return -EIO; } request->sclp_req.command = SCLP_CMDW_WRITEDATA; request->sclp_req.status = SCLP_REQ_FILLED; request->sclp_req.callback = sclp_vt220_callback; request->sclp_req.callback_data = (void *) request; - sclp_add_request(&request->sclp_req); + return sclp_add_request(&request->sclp_req); } /* @@ -256,12 +231,12 @@ sclp_vt220_emit(struct sclp_vt220_request *request) spin_unlock_irqrestore(&sclp_vt220_lock, flags); /* Emit only the first buffer immediately - callback takes care of * the rest */ - if (count == 0) - __sclp_vt220_emit(request); + if (count == 0 && __sclp_vt220_emit(request)) + sclp_vt220_process_queue(request); } /* - * Queue and emit current request. + * Queue and emit current request. Return zero on success, non-zero otherwise. */ static void sclp_vt220_emit_current(void) @@ -303,7 +278,6 @@ sclp_vt220_initialize_page(void *page) /* Place request structure at end of page */ request = ((struct sclp_vt220_request *) ((addr_t) page + PAGE_SIZE)) - 1; - init_timer(&request->retry_timer); request->retry_count = 0; request->sclp_req.sccb = page; /* SCCB goes at start of page */ @@ -476,32 +450,9 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, * number of characters actually accepted for writing. */ static int -sclp_vt220_write(struct tty_struct *tty, int from_user, - const unsigned char *buf, int count) +sclp_vt220_write(struct tty_struct *tty, const unsigned char *buf, int count) { - int length; - int ret; - - if (!from_user) - return __sclp_vt220_write(buf, count, 1, 0); - /* Use intermediate buffer to prevent calling copy_from_user() while - * holding a lock. */ - ret = 0; - while (count > 0) { - length = count < SCLP_VT220_BUF_SIZE ? - count : SCLP_VT220_BUF_SIZE; - length -= copy_from_user(tty->driver_data, buf, length); - if (length == 0) { - if (!ret) - return -EFAULT; - break; - } - length = __sclp_vt220_write(tty->driver_data, length, 1, 0); - buf += length; - count -= length; - ret += length; - } - return ret; + return __sclp_vt220_write(buf, count, 1, 0); } #define SCLP_VT220_SESSION_ENDED 0x01 @@ -532,16 +483,7 @@ sclp_vt220_receiver_fn(struct evbuf_header *evbuf) /* Send input to line discipline */ buffer++; count--; - /* Prevent buffer overrun by discarding input. Note that - * because buffer_push works asynchronously, we cannot wait - * for the buffer to be emptied. */ - if (count + sclp_vt220_tty->flip.count > TTY_FLIPBUF_SIZE) - count = TTY_FLIPBUF_SIZE - sclp_vt220_tty->flip.count; - memcpy(sclp_vt220_tty->flip.char_buf_ptr, buffer, count); - memset(sclp_vt220_tty->flip.flag_buf_ptr, TTY_NORMAL, count); - sclp_vt220_tty->flip.char_buf_ptr += count; - sclp_vt220_tty->flip.flag_buf_ptr += count; - sclp_vt220_tty->flip.count += count; + tty_insert_flip_string(sclp_vt220_tty, buffer, count); tty_flip_buffer_push(sclp_vt220_tty); break; }