1 /* CON1052.C    (c)Copyright Jan Jaeger, 2004-2009                   */
2 /*              Emulated 1052 on hercules console                    */
3 
4 #include "hstdinc.h"
5 
6 #include "hercules.h"
7 
8 #include "devtype.h"
9 
10 #include "opcode.h"
11 
12 #include "sr.h"
13 
14 #if defined(OPTION_DYNAMIC_LOAD) && defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
15  SYSBLK *psysblk;
16  #define sysblk (*psysblk)
17 void* (*panel_command) (void*);
18 #endif
19 
20 #if defined(OPTION_DYNAMIC_LOAD)
21 static void* con1052_panel_command  (char *cmd);
22 #endif
23 
24 #define BUFLEN_1052     150             /* 1052 Send/Receive buffer  */
25 
26 /*-------------------------------------------------------------------*/
27 /* Ivan Warren 20040227                                              */
28 /* This table is used by channel.c to determine if a CCW code is an  */
29 /* immediate command or not                                          */
30 /* The tape is addressed in the DEVHND structure as 'DEVIMM immed'   */
31 /* 0 : Command is NOT an immediate command                           */
32 /* 1 : Command is an immediate command                               */
33 /* Note : An immediate command is defined as a command which returns */
34 /* CE (channel end) during initialisation (that is, no data is       */
35 /* actually transfered. In this case, IL is not indicated for a CCW  */
36 /* Format 0 or for a CCW Format 1 when IL Suppression Mode is in     */
37 /* effect                                                            */
38 /*-------------------------------------------------------------------*/
39 static BYTE con1052_immed[256]=
40  /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
41   { 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,  /* 00 */
42     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 10 */
43     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 20 */
44     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 30 */
45     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 40 */
46     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 50 */
47     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 60 */
48     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 70 */
49     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 80 */
50     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* 90 */
51     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* A0 */
52     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* B0 */
53     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* C0 */
54     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* D0 */
55     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  /* E0 */
56     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* F0 */
57 
58 /*-------------------------------------------------------------------*/
59 /* INITIALIZE THE 1052/3215 DEVICE HANDLER                           */
60 /*-------------------------------------------------------------------*/
61 static int
con1052_init_handler(DEVBLK * dev,int argc,char * argv[])62 con1052_init_handler ( DEVBLK *dev, int argc, char *argv[] )
63 {
64     int ac=0;
65 
66     /* Integrated console is always connected */
67     dev->connected = 1;
68 
69     /* Set number of sense bytes */
70     dev->numsense = 1;
71 
72     /* Initialize device dependent fields */
73     dev->keybdrem = 0;
74 
75     /* Set length of print buffer */
76     dev->bufsize = BUFLEN_1052;
77 
78     /* Assume we want to prompt */
79     dev->prompt1052 = 1;
80 
81     /* Default command character is "/" */
82     strcpy(dev->filename,"/");
83 
84     /* Is there an argument? */
85     if (argc > 0)
86     {
87         /* Look at the argument and set noprompt flag if specified. */
88         if (strcasecmp(argv[ac], "noprompt") == 0)
89         {
90             dev->prompt1052 = 0;
91             ac++; argc--;
92         }
93         else
94             strlcpy(dev->filename,argv[ac],sizeof(dev->filename));
95     }
96 
97     if(!sscanf(dev->typname,"%hx",&(dev->devtype)))
98         dev->devtype = 0x1052;
99 
100     /* Initialize the device identifier bytes */
101     dev->devid[0] = 0xFF;
102     dev->devid[1] = dev->devtype >> 8;
103     dev->devid[2] = dev->devtype & 0xFF;
104     dev->devid[3] = 0x00;
105     dev->devid[4] = dev->devtype >> 8;
106     dev->devid[5] = dev->devtype & 0xFF;
107     dev->devid[6] = 0x00;
108     dev->numdevid = 7;
109 
110     return 0;
111 } /* end function con1052_init_handler */
112 
113 
114 /*-------------------------------------------------------------------*/
115 /* QUERY THE 1052/3215 DEVICE DEFINITION                             */
116 /*-------------------------------------------------------------------*/
117 static void
con1052_query_device(DEVBLK * dev,char ** class,int buflen,char * buffer)118 con1052_query_device (DEVBLK *dev, char **class,
119                 int buflen, char *buffer)
120 {
121     BEGIN_DEVICE_CLASS_QUERY( "CON", dev, class, buflen, buffer );
122 
123     snprintf(buffer, buflen,
124         "*syscons cmdpref(%s)%s",
125         dev->filename,
126         !dev->prompt1052 ? " noprompt" : "");
127 
128 } /* end function con1052_query_device */
129 
130 
131 /*-------------------------------------------------------------------*/
132 /* CLOSE THE 1052/3215 DEVICE HANDLER                                */
133 /*-------------------------------------------------------------------*/
134 static int
con1052_close_device(DEVBLK * dev)135 con1052_close_device ( DEVBLK *dev )
136 {
137     UNREFERENCED(dev);
138 
139     return 0;
140 } /* end function con1052_close_device */
141 
142 
143 /*-------------------------------------------------------------------*/
144 /* EXECUTE A 1052/3215 CHANNEL COMMAND WORD                          */
145 /*-------------------------------------------------------------------*/
146 static void
con1052_execute_ccw(DEVBLK * dev,BYTE code,BYTE flags,BYTE chained,U16 count,BYTE prevcode,int ccwseq,BYTE * iobuf,BYTE * more,BYTE * unitstat,U16 * residual)147 con1052_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags,
148         BYTE chained, U16 count, BYTE prevcode, int ccwseq,
149         BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual )
150 {
151 int     len;                            /* Length of data            */
152 int     num;                            /* Number of bytes to move   */
153 BYTE    c;                              /* Print character           */
154 
155     UNREFERENCED(chained);
156     UNREFERENCED(prevcode);
157     UNREFERENCED(ccwseq);
158 
159     /* Unit check with intervention required if no client connected */
160     if (dev->connected == 0 && !IS_CCW_SENSE(code))
161     {
162         dev->sense[0] = SENSE_IR;
163         *unitstat = CSW_UC;
164         return;
165     }
166 
167     /* Process depending on CCW opcode */
168     switch (code) {
169 
170     case 0x01:
171     /*---------------------------------------------------------------*/
172     /* WRITE NO CARRIER RETURN                                       */
173     /*---------------------------------------------------------------*/
174 
175     case 0x09:
176     /*---------------------------------------------------------------*/
177     /* WRITE AUTO CARRIER RETURN                                     */
178     /*---------------------------------------------------------------*/
179 
180         /* Calculate number of bytes to write and set residual count */
181         num = (count < BUFLEN_1052) ? count : BUFLEN_1052;
182         *residual = count - num;
183 
184         /* Translate data in channel buffer to ASCII */
185         for (len = 0; len < num; len++)
186         {
187             c = guest_to_host(iobuf[len]);
188             if (!isprint(c) && c != 0x0a && c != 0x0d) c = SPACE;
189             iobuf[len] = c;
190         } /* end for(len) */
191 
192         /* Perform end of record processing if not data-chaining,
193            and append carriage return and newline if required */
194         if ((flags & CCW_FLAGS_CD) == 0
195           && code == 0x09
196           && len < BUFLEN_1052)
197             iobuf[len++] = '\n';
198 
199         iobuf[len] = '\0';
200 
201         /* Send the data to the console */
202         logmsg("%s",(char *)iobuf);
203 
204         /* Return normal status */
205         *unitstat = CSW_CE | CSW_DE;
206         break;
207 
208     case 0x03:
209     /*---------------------------------------------------------------*/
210     /* CONTROL NO-OPERATION                                          */
211     /*---------------------------------------------------------------*/
212         *unitstat = CSW_CE | CSW_DE;
213         break;
214 
215     case 0x0A:
216     /*---------------------------------------------------------------*/
217     /* READ INQUIRY                                                  */
218     /*---------------------------------------------------------------*/
219 
220         /* Solicit console input if no data in the device buffer */
221         if (!dev->keybdrem)
222         {
223             /* Display prompting message on console if allowed */
224             if (dev->prompt1052)
225                 logmsg (_("HHC1C001A Enter input for console device %4.4X\n"),
226                   dev->devnum);
227 
228             obtain_lock(&dev->lock);
229             dev->iowaiters++;
230             wait_condition(&dev->iocond, &dev->lock);
231             dev->iowaiters--;
232             release_lock(&dev->lock);
233         }
234 
235         /* Calculate number of bytes to move and residual byte count */
236         len = dev->keybdrem;
237         num = (count < len) ? count : len;
238         *residual = count - num;
239         if (count < len) *more = 1;
240 
241         /* Copy data from device buffer to channel buffer */
242         memcpy (iobuf, dev->buf, num);
243 
244         /* If data chaining is specified, save remaining data */
245         if ((flags & CCW_FLAGS_CD) && len > count)
246         {
247             memmove (dev->buf, dev->buf + count, len - count);
248             dev->keybdrem = len - count;
249         }
250         else
251         {
252             dev->keybdrem = 0;
253         }
254 
255         /* Return normal status */
256         *unitstat = CSW_CE | CSW_DE;
257         break;
258 
259     case 0x0B:
260     /*---------------------------------------------------------------*/
261     /* AUDIBLE ALARM                                                 */
262     /*---------------------------------------------------------------*/
263         logmsg("\a");
264     /*
265         *residual = 0;
266     */
267         *unitstat = CSW_CE | CSW_DE;
268         break;
269 
270     case 0x04:
271     /*---------------------------------------------------------------*/
272     /* SENSE                                                         */
273     /*---------------------------------------------------------------*/
274         /* Calculate residual byte count */
275         num = (count < dev->numsense) ? count : dev->numsense;
276         *residual = count - num;
277         if (count < dev->numsense) *more = 1;
278 
279         /* Copy device sense bytes to channel I/O buffer */
280         memcpy (iobuf, dev->sense, num);
281 
282         /* Clear the device sense bytes */
283         memset (dev->sense, 0, sizeof(dev->sense));
284 
285         /* Return unit status */
286         *unitstat = CSW_CE | CSW_DE;
287         break;
288 
289     case 0xE4:
290     /*---------------------------------------------------------------*/
291     /* SENSE ID                                                      */
292     /*---------------------------------------------------------------*/
293         /* Calculate residual byte count */
294         num = (count < dev->numdevid) ? count : dev->numdevid;
295         *residual = count - num;
296         if (count < dev->numdevid) *more = 1;
297 
298         /* Copy device identifier bytes to channel I/O buffer */
299         memcpy (iobuf, dev->devid, num);
300 
301         /* Return unit status */
302         *unitstat = CSW_CE | CSW_DE;
303         break;
304 
305     default:
306     /*---------------------------------------------------------------*/
307     /* INVALID OPERATION                                             */
308     /*---------------------------------------------------------------*/
309         /* Set command reject sense byte, and unit check status */
310         dev->sense[0] = SENSE_CR;
311         *unitstat = CSW_CE | CSW_DE | CSW_UC;
312 
313     } /* end switch(code) */
314 
315 } /* end function con1052_execute_ccw */
316 
317 #if defined(OPTION_DYNAMIC_LOAD)
318 static
319 #endif
320 DEVHND con1052_device_hndinfo = {
321         &con1052_init_handler,         /* Device Initialisation      */
322         &con1052_execute_ccw,          /* Device CCW execute         */
323         &con1052_close_device,         /* Device Close               */
324         &con1052_query_device,         /* Device Query               */
325         NULL,                          /* Device Start channel pgm   */
326         NULL,                          /* Device End channel pgm     */
327         NULL,                          /* Device Resume channel pgm  */
328         NULL,                          /* Device Suspend channel pgm */
329         NULL,                          /* Device Read                */
330         NULL,                          /* Device Write               */
331         NULL,                          /* Device Query used          */
332         NULL,                          /* Device Reserve             */
333         NULL,                          /* Device Release             */
334         NULL,                          /* Device Attention           */
335         con1052_immed,                 /* Immediate CCW Codes        */
336         NULL,                          /* Signal Adapter Input       */
337         NULL,                          /* Signal Adapter Output      */
338         NULL,                          /* Hercules suspend           */
339         NULL                           /* Hercules resume            */
340 };
341 
342 
343 #if defined(OPTION_DYNAMIC_LOAD)
344 static void*
con1052_panel_command(char * cmd)345 con1052_panel_command (char *cmd)
346 {
347 DEVBLK *dev;
348 char *input;
349 int  i;
350 
351     void* (*next_panel_command_handler)(char *cmd);
352 
353     for(dev = sysblk.firstdev; dev; dev = dev->nextdev)
354     {
355         if(dev->allocated
356           && dev->hnd == &con1052_device_hndinfo
357           && !strncasecmp(cmd,dev->filename,strlen(dev->filename)) )
358         {
359             input = cmd + strlen(dev->filename);
360             logmsg("%s(%4.4X) %s\n",dev->filename,dev->devnum,
361                                      cmd+strlen(dev->filename) );
362             for(i = 0; i < dev->bufsize && input[i] != '\0'; i++)
363                 dev->buf[i] = isprint(input[i]) ? host_to_guest(input[i]) : SPACE;
364             dev->keybdrem = dev->buflen = i;
365             obtain_lock(&dev->lock);
366             if(dev->iowaiters)
367             {
368                 signal_condition(&dev->iocond);
369                 release_lock(&dev->lock);
370             }
371             else
372             {
373                 release_lock(&dev->lock);
374                 device_attention (dev, CSW_ATTN);
375             }
376             return NULL;
377         }
378     }
379 
380     next_panel_command_handler = HDL_FINDNXT(con1052_panel_command);
381 
382     if (!next_panel_command_handler)
383         return NULL;
384 
385     return  next_panel_command_handler(cmd);
386 }
387 #endif
388 
389 /* Libtool static name colision resolution */
390 /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
391 #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
392 #define hdl_ddev hdt1052c_LTX_hdl_ddev
393 #define hdl_depc hdt1052c_LTX_hdl_depc
394 #define hdl_reso hdt1052c_LTX_hdl_reso
395 #define hdl_init hdt1052c_LTX_hdl_init
396 #define hdl_fini hdt1052c_LTX_hdl_fini
397 #endif
398 
399 
400 #if defined(OPTION_DYNAMIC_LOAD)
401 HDL_DEPENDENCY_SECTION;
402 {
403      HDL_DEPENDENCY(HERCULES);
404      HDL_DEPENDENCY(DEVBLK);
405      HDL_DEPENDENCY(SYSBLK);
406 }
407 END_DEPENDENCY_SECTION
408 
409 
410 #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
411 #undef sysblk
412 HDL_RESOLVER_SECTION;
413 {
414     HDL_RESOLVE_PTRVAR(psysblk, sysblk);
415     HDL_RESOLVE(panel_command);
416 }
417 END_RESOLVER_SECTION
418 #endif
419 
420 
421 HDL_DEVICE_SECTION;
422 {
423     HDL_DEVICE(1052-C, con1052_device_hndinfo);
424     HDL_DEVICE(3215-C, con1052_device_hndinfo);
425 }
426 END_DEVICE_SECTION
427 
428 
429 HDL_REGISTER_SECTION;
430 {
431    HDL_REGISTER (panel_command, con1052_panel_command);
432 }
433 END_REGISTER_SECTION
434 
435 #endif
436