patch-2.2.18 linux/drivers/s390/char/con3215.c
Next file: linux/drivers/s390/char/hwc.h
Previous file: linux/drivers/s390/ccwcache.c
Back to the patch index
Back to the overall index
- Lines: 430
- Date:
Sat Dec 9 20:56:00 2000
- Orig file:
v2.2.17/drivers/s390/char/con3215.c
- Orig date:
Sat Sep 9 18:42:40 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/s390/char/con3215.c linux/drivers/s390/char/con3215.c
@@ -5,6 +5,10 @@
* S390 version
* Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *
+ * Updated:
+ * Aug-2000: Added tab support
+ * Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu)
*/
#include <linux/config.h>
@@ -45,6 +49,8 @@
#define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */
#define RAW3215_BH_PENDING 256 /* indication for bh scheduling */
+#define TAB_STOP_SIZE 8 /* tab stop size */
+
struct _raw3215_info; /* forward declaration ... */
int raw3215_condevice = -1; /* preset console device */
@@ -87,6 +93,7 @@
char *message; /* pending message from raw3215_irq */
int msg_dstat; /* dstat for pending message */
int msg_cstat; /* cstat for pending message */
+ int line_pos; /* position on the line (for tabs) */
} raw3215_info;
static raw3215_info *raw3215[NR_3215]; /* array of 3215 devices structures */
@@ -103,11 +110,13 @@
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
+extern void tod_wait(unsigned long usecs);
+
__initfunc(void con3215_setup(char *str, char *ints))
{
int vdev;
- vdev = simple_strtoul(str,&str,10);
+ vdev = simple_strtoul(str,&str,0);
if (vdev >= 0 && vdev < 65536)
raw3215_condevice = vdev;
return;
@@ -167,7 +176,7 @@
ccw->cmd_code = 0x0A; /* read inquiry */
ccw->flags = 0x20; /* ignore incorrect length */
ccw->count = 160;
- ccw->cda = (void *) virt_to_phys(raw->inbuf);
+ ccw->cda = (__u32) __pa(raw->inbuf);
}
/*
@@ -178,7 +187,7 @@
*/
static void raw3215_mk_write_req(raw3215_info *raw)
{
- raw3215_req *req;
+ raw3215_req *req;
ccw1_t *ccw;
int len, count, ix, lines;
@@ -186,28 +195,28 @@
return;
/* check if there is a queued write request */
req = raw->queued_write;
- if (req == NULL) {
+ if (req == NULL) {
/* no queued write request, use new req structure */
- req = raw3215_alloc_req();
+ req = raw3215_alloc_req();
req->type = RAW3215_WRITE;
- req->info = raw;
+ req->info = raw;
raw->queued_write = req;
} else {
raw->written -= req->len;
-}
+ }
ccw = req->ccws;
req->start = (raw->head - raw->count + raw->written) &
(RAW3215_BUFFER_SIZE - 1);
-/*
+ /*
* now we have to count newlines. We can at max accept
* RAW3215_MAX_NEWLINE newlines in a single ssch due to
* a restriction in VM
- */
+ */
lines = 0;
ix = req->start;
while (lines < RAW3215_MAX_NEWLINE && ix != raw->head) {
- if (raw->buffer[ix] == '\n')
+ if (raw->buffer[ix] == 0x15)
lines++;
ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1);
}
@@ -226,21 +235,20 @@
ccw[-1].flags |= 0x40; /* use command chaining */
ccw->cmd_code = 0x01; /* write, auto carrier return */
ccw->flags = 0x20; /* ignore incorrect length ind. */
- ccw->cda =
- (void *) virt_to_phys(raw->buffer + ix);
+ ccw->cda = (__u32) __pa(raw->buffer + ix);
count = len;
if (ix + count > RAW3215_BUFFER_SIZE)
- count = RAW3215_BUFFER_SIZE-ix;
+ count = RAW3215_BUFFER_SIZE - ix;
ccw->count = count;
len -= count;
ix = (ix + count) & (RAW3215_BUFFER_SIZE - 1);
ccw++;
}
-/*
+ /*
* Add a NOP to the channel program. 3215 devices are purely
* emulated and its much better to avoid the channel end
* interrupt in this case.
- */
+ */
if (ccw > req->ccws)
ccw[-1].flags |= 0x40; /* use command chaining */
ccw->cmd_code = 0x03; /* NOP */
@@ -319,7 +327,7 @@
if ((raw->queued_write->delayable == 0) ||
(raw->flags & RAW3215_FLUSHING)) {
/* execute write requests bigger than minimum size */
- raw3215_start_io(raw);
+ raw3215_start_io(raw);
if (raw->flags & RAW3215_TIMER_RUNS) {
del_timer(&raw->timer);
raw->flags &= ~RAW3215_TIMER_RUNS;
@@ -459,7 +467,7 @@
return; /* That shouldn't happen ... */
if (req->type == RAW3215_READ && raw->tty != NULL) {
tty = raw->tty;
- count = 160 - req->residual;
+ count = 160 - req->residual;
if (MACHINE_IS_P390) {
slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE);
if (count > slen)
@@ -517,7 +525,7 @@
} else if (req->type == RAW3215_WRITE) {
raw->count -= req->len;
raw->written -= req->len;
- }
+ }
raw->flags &= ~RAW3215_WORKING;
raw3215_free_req(req);
/* check for empty wait */
@@ -530,7 +538,7 @@
raw3215_sched_bh(raw);
break;
default:
- /* Strange interrupt, I'll do my best to clean up */
+ /* Strange interrupt, I'll do my best to clean up */
if ((raw = raw3215_find_info(irq)) == NULL)
return; /* That shouldn't happen ... */
if (req != NULL && req->type != RAW3215_FREE) {
@@ -540,18 +548,46 @@
}
raw->flags &= ~RAW3215_WORKING;
raw3215_free_req(req);
- }
- raw->message = KERN_WARNING
- "Spurious interrupt in in raw3215_irq "
- "(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
- raw->msg_dstat = dstat;
- raw->msg_cstat = cstat;
+ }
+ raw->message = KERN_WARNING
+ "Spurious interrupt in in raw3215_irq "
+ "(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
+ raw->msg_dstat = dstat;
+ raw->msg_cstat = cstat;
raw3215_sched_bh(raw);
}
return;
}
/*
+ * Wait until length bytes are available int the output buffer.
+ * Has to be called with the s390irq lock held. Can be called
+ * disabled.
+ */
+void raw3215_make_room(raw3215_info *raw, unsigned int length)
+{
+ while (RAW3215_BUFFER_SIZE - raw->count < length) {
+ /* there might be a request pending */
+ raw->flags |= RAW3215_FLUSHING;
+ raw3215_mk_write_req(raw);
+ raw3215_try_io(raw);
+ raw->flags &= ~RAW3215_FLUSHING;
+ if (wait_cons_dev(raw->irq) != 0) {
+ /* that shouldn't happen */
+ raw->count = 0;
+ raw->written = 0;
+ }
+ /* Enough room freed up ? */
+ if (RAW3215_BUFFER_SIZE - raw->count >= length)
+ break;
+ /* there might be another cpu waiting for the lock */
+ s390irq_spin_unlock(raw->irq);
+ tod_wait(100);
+ s390irq_spin_lock(raw->irq);
+ }
+}
+
+/*
* String write routine for 3215 devices
*/
static int
@@ -569,16 +605,7 @@
RAW3215_BUFFER_SIZE : length;
length -= count;
- while (RAW3215_BUFFER_SIZE - raw->count < count) {
- /* there might be a request pending */
- raw3215_mk_write_req(raw);
- raw3215_try_io(raw);
- if (wait_cons_dev(raw->irq) != 0) {
- /* that shouldn't happen */
- raw->count = 0;
- raw->written = 0;
- }
- }
+ raw3215_make_room(raw, count);
/* copy string to output buffer and convert it to EBCDIC */
if (from_user) {
@@ -599,6 +626,7 @@
raw->head = (raw->head + c) &
(RAW3215_BUFFER_SIZE - 1);
raw->count += c;
+ raw->line_pos += c;
str += c;
count -= c;
ret += c;
@@ -615,6 +643,7 @@
raw->head = (raw->head + c) &
(RAW3215_BUFFER_SIZE - 1);
raw->count += c;
+ raw->line_pos += c;
str += c;
count -= c;
ret += c;
@@ -622,8 +651,8 @@
}
if (!(raw->flags & RAW3215_WORKING)) {
raw3215_mk_write_req(raw);
- /* start or queue request */
- raw3215_try_io(raw);
+ /* start or queue request */
+ raw3215_try_io(raw);
}
s390irq_spin_unlock_irqrestore(raw->irq, flags);
}
@@ -634,29 +663,35 @@
/*
* Put character routine for 3215 devices
*/
+
static void raw3215_putchar(raw3215_info *raw, unsigned char ch)
{
unsigned long flags;
+ unsigned int length, i;
s390irq_spin_lock_irqsave(raw->irq, flags);
- while (RAW3215_BUFFER_SIZE - raw->count < 1) {
- /* there might be a request pending */
- raw3215_mk_write_req(raw);
- raw3215_try_io(raw);
- if (wait_cons_dev(raw->irq) != 0) {
- /* that shouldn't happen */
- raw->count = 0;
- raw->written = 0;
- }
+ if (ch == '\t') {
+ length = TAB_STOP_SIZE - (raw->line_pos%TAB_STOP_SIZE);
+ raw->line_pos += length;
+ ch = ' ';
+ } else if (ch == '\n') {
+ length = 1;
+ raw->line_pos = 0;
+ } else {
+ length = 1;
+ raw->line_pos++;
}
+ raw3215_make_room(raw, length);
- raw->buffer[raw->head] = (char) _ascebc[(int) ch];
- raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
- raw->count++;
+ for (i = 0; i < length; i++) {
+ raw->buffer[raw->head] = (char) _ascebc[(int) ch];
+ raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
+ raw->count++;
+ }
if (!(raw->flags & RAW3215_WORKING)) {
raw3215_mk_write_req(raw);
- /* start or queue request */
- raw3215_try_io(raw);
+ /* start or queue request */
+ raw3215_try_io(raw);
}
s390irq_spin_unlock_irqrestore(raw->irq, flags);
}
@@ -690,6 +725,7 @@
if (request_irq(raw->irq, raw3215_irq, SA_INTERRUPT,
"3215 terminal driver", &raw->devstat) != 0)
return -1;
+ raw->line_pos = 0;
raw->flags |= RAW3215_ACTIVE;
s390irq_spin_lock_irqsave(raw->irq, flags);
set_cons_dev(raw->irq);
@@ -720,6 +756,7 @@
s390irq_spin_unlock_irqrestore(raw->irq, flags);
schedule();
s390irq_spin_lock_irqsave(raw->irq, flags);
+ remove_wait_queue(&raw->empty_wait, &wait);
current->state = TASK_RUNNING;
raw->flags &= ~(RAW3215_ACTIVE | RAW3215_CLOSING);
}
@@ -739,12 +776,12 @@
while (count <= number && irq != -ENODEV) {
if (get_dev_info(irq, &dinfo) == -ENODEV)
break;
- if (dinfo.devno == raw3215_condevice ||
+ if (dinfo.devno == raw3215_condevice ||
dinfo.sid_data.cu_type == 0x3215) {
- count++;
+ count++;
if (count > number)
- return irq;
-}
+ return irq;
+ }
irq = get_irq_next(irq);
}
return -1; /* console not found */
@@ -762,7 +799,8 @@
if (!MACHINE_IS_VM && !MACHINE_IS_P390)
return 0;
raw = raw3215[0]; /* 3215 console is the first one */
- if (raw->irq == -1) /* now console device found in con3215_init */
+ if (raw == NULL || raw->irq == -1)
+ /* console device not found in con3215_init */
return -1;
return raw3215_startup(raw);
}
@@ -774,11 +812,24 @@
con3215_write(struct console *co, const char *str, unsigned int count)
{
raw3215_info *raw;
+ int i;
if (count <= 0)
return;
- raw = raw3215[0]; /* console 3215 is the first one */
- raw3215_write(raw, str, 0, count);
+ raw = raw3215[0]; /* console 3215 is the first one */
+ while (count > 0) {
+ for (i = 0; i < count; i++)
+ if (str[i] == '\t' || str[i] == '\n')
+ break;
+ raw3215_write(raw, str, 0, i);
+ count -= i;
+ str += i;
+ if (count > 0) {
+ raw3215_putchar(raw, *str);
+ count--;
+ str++;
+ }
+ }
}
kdev_t con3215_device(struct console *c)
@@ -797,17 +848,7 @@
raw = raw3215[0]; /* console 3215 is the first one */
s390irq_spin_lock_irqsave(raw->irq, flags);
- while (raw->count > 0) {
- /* there might be a request pending */
- raw->flags |= RAW3215_FLUSHING;
- raw3215_try_io(raw);
- if (wait_cons_dev(raw->irq) != 0) {
- /* that shouldn't happen */
- raw->count = 0;
- raw->written = 0;
- }
- raw->flags &= ~RAW3215_FLUSHING;
- }
+ raw3215_make_room(raw, RAW3215_BUFFER_SIZE);
s390irq_spin_unlock_irqrestore(raw->irq, flags);
}
@@ -914,7 +955,12 @@
raw3215_info *raw;
raw = (raw3215_info *) tty->driver_data;
- return RAW3215_BUFFER_SIZE - raw->count;
+
+ /* Subtract TAB_STOP_SIZE to allow for a tab, 8 <<< 64K */
+ if ((RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE) >= 0)
+ return RAW3215_BUFFER_SIZE - raw->count - TAB_STOP_SIZE;
+ else
+ return 0;
}
/*
@@ -924,7 +970,7 @@
const unsigned char *buf, int count)
{
raw3215_info *raw;
- int ret;
+ int ret = 0;
if (!tty)
return 0;
@@ -1062,8 +1108,8 @@
if (!MACHINE_IS_VM && !MACHINE_IS_P390)
return kmem_start;
if (MACHINE_IS_VM) {
- cpcmd("TERM CONMODE 3215", NULL, 0);
- cpcmd("TERM AUTOCR OFF", NULL, 0);
+ cpcmd("TERM CONMODE 3215", NULL, 0);
+ cpcmd("TERM AUTOCR OFF", NULL, 0);
}
kmem_start = (kmem_start + 7) & -8L;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)