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

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)