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