patch-2.4.4 linux/drivers/s390/char/hwc_rw.c

Next file: linux/drivers/s390/char/hwc_tty.c
Previous file: linux/drivers/s390/char/hwc_con.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.3/linux/drivers/s390/char/hwc_rw.c linux/drivers/s390/char/hwc_rw.c
@@ -30,9 +30,13 @@
 #include <asm/s390_ext.h>
 
 #ifndef MIN
-#define MIN(a,b) ((a<b) ? a : b)
+#define MIN(a,b) (((a<b) ? a : b))
 #endif
 
+#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
+
+#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
+
 #define HWC_RW_PRINT_HEADER "hwc low level driver: "
 
 #define  USE_VM_DETECTION
@@ -118,16 +122,16 @@
 static unsigned char
  _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
 
-/* pedantic: long because we use set_bit on it --RR */
-typedef long kmem_pages_t;
+typedef unsigned long kmem_pages_t;
 
 #define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)
 
-#define HWC_TIMER_RUNS	1
-#define HWC_FLUSH	2
-#define HWC_INIT	4
-#define HWC_BROKEN	8
-#define HWC_INTERRUPT	16
+#define HWC_WTIMER_RUNS	1
+#define HWC_FLUSH		2
+#define HWC_INIT		4
+#define HWC_BROKEN		8
+#define HWC_INTERRUPT		16
+#define HWC_PTIMER_RUNS	32
 
 static struct {
 
@@ -169,6 +173,7 @@
 	unsigned char write_prio:1;
 	unsigned char read_nonprio:1;
 	unsigned char read_prio:1;
+	unsigned char read_statechange:1;
 
 	unsigned char flags;
 
@@ -177,6 +182,8 @@
 	spinlock_t lock;
 
 	struct timer_list write_timer;
+
+	struct timer_list poll_timer;
 } hwc_data =
 {
 	{
@@ -186,7 +193,7 @@
 		    0,
 		    80,
 		    1,
-		    50,
+		    MAX_KMEM_PAGES,
 		    MAX_KMEM_PAGES,
 
 		    0,
@@ -214,6 +221,7 @@
 	    0,
 	    0,
 	    0,
+	    0,
 	    NULL
 
 };
@@ -345,9 +353,6 @@
 
 	memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t));
 
-	if (!hwc_data.write_nonprio && hwc_data.write_prio)
-		hwcb->msgbuf.type = ET_PMsgCmd;
-
 	return 0;
 }
 
@@ -647,25 +652,58 @@
 	return count;
 }
 
+static int write_event_data_1 (void);
+
+static void 
+do_poll_hwc (unsigned long data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave (&hwc_data.lock, flags);
+
+	write_event_data_1 ();
+
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
+}
+
+void 
+start_poll_hwc (void)
+{
+	init_timer (&hwc_data.poll_timer);
+	hwc_data.poll_timer.function = do_poll_hwc;
+	hwc_data.poll_timer.data = (unsigned long) NULL;
+	hwc_data.poll_timer.expires = jiffies + 2 * HZ;
+	add_timer (&hwc_data.poll_timer);
+	hwc_data.flags |= HWC_PTIMER_RUNS;
+}
+
 static int 
 write_event_data_1 (void)
 {
 	unsigned short int condition_code;
 	int retval;
+	write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB;
 
-	if ((!hwc_data.write_prio) && (!hwc_data.write_nonprio))
-		return -EPERM;
+	if ((!hwc_data.write_prio) &&
+	    (!hwc_data.write_nonprio) &&
+	    hwc_data.read_statechange)
+		return -EOPNOTSUPP;
 
 	if (hwc_data.current_servc)
 		return -EBUSY;
 
 	retval = sane_write_hwcb ();
 	if (retval < 0)
-		return retval;
+		return -EIO;
 
 	if (!OUT_HWCB_MTO)
 		return -ENODATA;
 
+	if (!hwc_data.write_nonprio && hwc_data.write_prio)
+		hwcb->msgbuf.type = ET_PMsgCmd;
+	else
+		hwcb->msgbuf.type = ET_Msg;
+
 	condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB);
 
 #ifdef DUMP_HWC_WRITE_ERROR
@@ -688,6 +726,8 @@
 	case HWC_BUSY:
 		retval = -EBUSY;
 		break;
+	case HWC_NOT_OPERATIONAL:
+		start_poll_hwc ();
 	default:
 		retval = -EIO;
 	}
@@ -710,7 +750,7 @@
 write_event_data_2 (void)
 {
 	write_hwcb_t *hwcb;
-	int retval;
+	int retval = 0;
 
 #ifdef DUMP_HWC_WRITE_ERROR
 	unsigned char *param;
@@ -765,11 +805,22 @@
 	}
 #endif
 
-	if (hwcb->response_code == 0x0020) {
+	switch (hwcb->response_code) {
+	case 0x0020:
 
 		retval = OUT_HWCB_CHAR;
 		release_write_hwcb ();
-	} else {
+		break;
+	case 0x0040:
+	case 0x0340:
+	case 0x40F0:
+		if (!hwc_data.read_statechange) {
+			hwcb->response_code = 0;
+			start_poll_hwc ();
+		}
+		retval = -EIO;
+		break;
+	default:
 		internal_print (
 				       DELAYED_WRITE,
 				       HWC_RW_PRINT_HEADER
@@ -782,6 +833,13 @@
 		retval = -EIO;
 	}
 
+	if (retval == -EIO) {
+
+		hwcb->control_mask[0] = 0;
+		hwcb->control_mask[1] = 0;
+		hwcb->control_mask[2] = 0;
+		hwcb->response_code = 0;
+	}
 	hwc_data.current_servc = 0;
 	hwc_data.current_hwcb = NULL;
 
@@ -826,9 +884,9 @@
 		 unsigned short count)
 {
 
-	if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) {
+	if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) {
 		del_timer (&hwc_data.write_timer);
-		hwc_data.flags &= ~HWC_TIMER_RUNS;
+		hwc_data.flags &= ~HWC_WTIMER_RUNS;
 	}
 	hwc_data.obuf_start += count;
 
@@ -937,7 +995,7 @@
 				if (obuf_cursor < obuf_columns) {
 					hwc_data.obuf[hwc_data.obuf_start +
 						      obuf_cursor]
-					    = 0x20;
+					    = HWC_ASCEBC (' ');
 					obuf_cursor++;
 				} else
 					break;
@@ -955,7 +1013,7 @@
 			while (spaces) {
 				hwc_data.obuf[hwc_data.obuf_start +
 					      obuf_cursor - spaces]
-				    = 0x20;
+				    = HWC_ASCEBC (' ');
 				spaces--;
 			}
 
@@ -985,9 +1043,7 @@
 			if (isprint (ch))
 				hwc_data.obuf[hwc_data.obuf_start +
 					      obuf_cursor++]
-				    = (MACHINE_IS_VM) ?
-				    _ascebc[ch] :
-				    _ascebc_500[ch];
+				    = HWC_ASCEBC (ch);
 		}
 		if (obuf_cursor > obuf_count)
 			obuf_count = obuf_cursor;
@@ -1006,11 +1062,10 @@
 
 			if (hwc_data.ioctls.final_nl > 0) {
 
-				if (hwc_data.flags & HWC_TIMER_RUNS) {
+				if (hwc_data.flags & HWC_WTIMER_RUNS) {
 
-					hwc_data.write_timer.expires =
-					    jiffies +
-					    hwc_data.ioctls.final_nl * HZ / 10;
+					mod_timer (&hwc_data.write_timer,
+						   jiffies + hwc_data.ioctls.final_nl * HZ / 10);
 				} else {
 
 					init_timer (&hwc_data.write_timer);
@@ -1022,7 +1077,7 @@
 					    jiffies +
 					    hwc_data.ioctls.final_nl * HZ / 10;
 					add_timer (&hwc_data.write_timer);
-					hwc_data.flags |= HWC_TIMER_RUNS;
+					hwc_data.flags |= HWC_WTIMER_RUNS;
 				}
 			} else;
 
@@ -1306,14 +1361,11 @@
 	if (hwc_data.ioctls.delim)
 		count = seperate_cases (start, count);
 
-	if (MACHINE_IS_VM)
-		EBCASC (start, count);
-	else
-		EBCASC_500 (start, count);
+	HWC_EBCASC_STR (start, count);
 
-	if (hwc_data.ioctls.echo) {
+	if (hwc_data.ioctls.echo)
 		do_hwc_write (0, start, count, IMMEDIATE_WRITE);
-	}
+
 	if (hwc_data.calls != NULL)
 		if (hwc_data.calls->move_input != NULL)
 			(hwc_data.calls->move_input) (start, count);
@@ -1416,7 +1468,7 @@
 	return retval;
 }
 
-inline static int 
+static int 
 eval_evbuf (gds_vector_t * start, void *end)
 {
 	gds_vector_t *vec;
@@ -1434,6 +1486,128 @@
 	return retval;
 }
 
+static inline int 
+eval_hwc_receive_mask (_hwcb_mask_t mask)
+{
+
+	hwc_data.write_nonprio
+	    = ((mask & ET_Msg_Mask) == ET_Msg_Mask);
+
+	hwc_data.write_prio
+	    = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
+
+	if (hwc_data.write_prio || hwc_data.write_nonprio) {
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can write messages\n");
+		return 0;
+	} else {
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can not write messages\n");
+		return -1;
+	}
+}
+
+static inline int 
+eval_hwc_send_mask (_hwcb_mask_t mask)
+{
+
+	hwc_data.read_statechange
+	    = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask);
+	if (hwc_data.read_statechange)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				     "can read state change notifications\n");
+	else
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				 "can not read state change notifications\n");
+
+	hwc_data.read_nonprio
+	    = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask);
+	if (hwc_data.read_nonprio)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can read commands\n");
+
+	hwc_data.read_prio
+	    = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
+	if (hwc_data.read_prio)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can read priority commands\n");
+
+	if (hwc_data.read_prio || hwc_data.read_nonprio) {
+		return 0;
+	} else {
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				     "can not read commands from operator\n");
+		return -1;
+	}
+}
+
+static int 
+eval_statechangebuf (statechangebuf_t * scbuf)
+{
+	int retval = 0;
+
+	internal_print (
+			       DELAYED_WRITE,
+			       HWC_RW_PRINT_HEADER
+			       "HWC state change detected\n");
+
+	if (scbuf->validity_hwc_active_facility_mask) {
+
+	}
+	if (scbuf->validity_hwc_receive_mask) {
+
+		if (scbuf->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+			__asm__ ("LHI 1,0xe50\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "J .+0 \n\t"
+		      :
+		      :	 "a" (scbuf)
+		      :	 "1", "2");
+#endif
+		} else {
+
+			retval += eval_hwc_receive_mask
+			    (scbuf->hwc_receive_mask);
+		}
+	}
+	if (scbuf->validity_hwc_send_mask) {
+
+		if (scbuf->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+			__asm__ ("LHI 1,0xe51\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "J .+0 \n\t"
+		      :
+		      :	 "a" (scbuf)
+		      :	 "1", "2");
+#endif
+		} else {
+
+			retval += eval_hwc_send_mask
+			    (scbuf->hwc_send_mask);
+		}
+	}
+	if (scbuf->validity_read_data_function_mask) {
+
+	}
+	return retval;
+}
+
 static int 
 process_evbufs (void *start, void *end)
 {
@@ -1466,17 +1640,17 @@
 			retval += eval_evbuf (evbuf_data, evbuf_end);
 			break;
 		case ET_StateChange:
-
-			retval = -ENOSYS;
+			retval += eval_statechangebuf
+			    ((statechangebuf_t *) evbuf);
 			break;
 		default:
-			printk (
-				       KERN_WARNING
-				       HWC_RW_PRINT_HEADER
-				       "unconditional read: "
-				       "unknown event buffer found, "
-				       "type 0x%x",
-				       evbuf->type);
+			internal_print (
+					       DELAYED_WRITE,
+					       HWC_RW_PRINT_HEADER
+					       "unconditional read: "
+					       "unknown event buffer found, "
+					       "type 0x%x",
+					       evbuf->type);
 			retval = -ENOSYS;
 		}
 		evbuf = (evbuf_t *) evbuf_end;
@@ -1491,11 +1665,14 @@
 	read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
 	int retval;
 
+#if 0
+
 	if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
 		return -EOPNOTSUPP;
 
 	if (hwc_data.current_servc)
 		return -EBUSY;
+#endif
 
 	memset (hwcb, 0x00, PAGE_SIZE);
 	memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t));
@@ -1601,26 +1778,21 @@
 		internal_print (
 				       IMMEDIATE_WRITE,
 				       HWC_RW_PRINT_HEADER
-			   "unconditional read: invalid function code - this "
-			 "must not occur in a correct driver, please contact "
-				       "author\n");
+			       "unconditional read: invalid function code\n");
 		return -EIO;
 
 	case 0x70F0:
 		internal_print (
 				       IMMEDIATE_WRITE,
 				       HWC_RW_PRINT_HEADER
-			  "unconditional read: invalid selection mask - this "
-			 "must not occur in a correct driver, please contact "
-				       "author\n");
+			      "unconditional read: invalid selection mask\n");
 		return -EIO;
 
 	case 0x0040:
 		internal_print (
 				       IMMEDIATE_WRITE,
 				       HWC_RW_PRINT_HEADER
-			    "unconditional read: HWC equipment check - don't "
-				       "know how to handle this case\n");
+				 "unconditional read: HWC equipment check\n");
 		return -EIO;
 
 	default:
@@ -1677,27 +1849,7 @@
 	init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
 	int retval = 0;
 
-	if (hwcb->hwc_receive_mask & ET_Msg_Mask)
-		hwc_data.write_nonprio = 1;
-
-	if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask)
-		hwc_data.write_prio = 1;
-
-	if (hwcb->hwc_send_mask & ET_OpCmd_Mask) {
-		internal_print (DELAYED_WRITE,
-				HWC_RW_PRINT_HEADER
-				"capable of receipt of commands\n");
-		hwc_data.read_nonprio = 1;
-	}
-	if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask) {
-		internal_print (DELAYED_WRITE,
-				HWC_RW_PRINT_HEADER
-				"capable of receipt of priority commands\n");
-		hwc_data.read_nonprio = 1;
-	}
-	if ((hwcb->response_code != 0x0020) ||
-	    (!hwc_data.write_nonprio) ||
-	    ((!hwc_data.read_nonprio) && (!hwc_data.read_prio)))
+	if (hwcb->response_code != 0x0020) {
 #ifdef DUMP_HWC_INIT_ERROR
 		__asm__ ("LHI 1,0xe11\n\t"
 			 "LRA 2,0(%0)\n\t"
@@ -1707,8 +1859,24 @@
 	      :	 "a" (hwcb), "a" (&(hwcb->response_code))
 	      :	 "1", "2", "3");
 #else
-		retval = -EIO;
+		retval = -1;
 #endif
+	} else {
+		if (hwcb->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+			__asm__ ("LHI 1,0xe52\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "J .+0 \n\t"
+		      :
+		      :	 "a" (hwcb)
+		      :	 "1", "2");
+#endif
+		} else {
+			retval += eval_hwc_receive_mask
+			    (hwcb->hwc_receive_mask);
+			retval += eval_hwc_send_mask (hwcb->hwc_send_mask);
+		}
+	}
 
 	hwc_data.current_servc = 0;
 	hwc_data.current_hwcb = NULL;
@@ -1934,6 +2102,10 @@
 	} else {
 		spin_lock (&hwc_data.lock);
 
+		if (hwc_data.flags & HWC_PTIMER_RUNS) {
+			del_timer (&hwc_data.poll_timer);
+			hwc_data.flags &= ~HWC_PTIMER_RUNS;
+		}
 		if (!hwc_data.current_servc) {
 
 			unconditional_read_1 ();

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)