1 /* CARDPCH.C (c) Copyright Roger Bowler, 1999-2009 */
2 /* ESA/390 Card Punch Device Handler */
3
4 /*-------------------------------------------------------------------*/
5 /* This module contains device handling functions for emulated */
6 /* System/370 card punch devices. */
7 /*-------------------------------------------------------------------*/
8
9 #include "hstdinc.h"
10 #include "hercules.h"
11
12 #include "devtype.h"
13
14 /*-------------------------------------------------------------------*/
15 /* Internal macro definitions */
16 /*-------------------------------------------------------------------*/
17 #define CARD_LENGTH 80
18 #define HEX40 ((BYTE)0x40)
19
20 /*-------------------------------------------------------------------*/
21 /* Subroutine to write data to the card punch */
22 /*-------------------------------------------------------------------*/
23 static void
write_buffer(DEVBLK * dev,BYTE * buf,int len,BYTE * unitstat)24 write_buffer (DEVBLK *dev, BYTE *buf, int len, BYTE *unitstat)
25 {
26 int rc; /* Return code */
27
28 /* Write data to the output file */
29 rc = write (dev->fd, buf, len);
30
31 /* Equipment check if error writing to output file */
32 if (rc < len)
33 {
34 logmsg (_("HHCPU004E Error writing to %s: %s\n"),
35 dev->filename,
36 (errno == 0 ? "incomplete": strerror(errno)));
37 dev->sense[0] = SENSE_EC;
38 *unitstat = CSW_CE | CSW_DE | CSW_UC;
39 return;
40 }
41
42 } /* end function write_buffer */
43
44 /*-------------------------------------------------------------------*/
45 /* Initialize the device handler */
46 /*-------------------------------------------------------------------*/
cardpch_init_handler(DEVBLK * dev,int argc,char * argv[])47 static int cardpch_init_handler (DEVBLK *dev, int argc, char *argv[])
48 {
49 int i; /* Array subscript */
50
51 /* The first argument is the file name */
52 if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1)
53 {
54 logmsg (_("HHCPU001E File name missing or invalid\n"));
55 return -1;
56 }
57
58 /* Save the file name in the device block */
59 strcpy (dev->filename, argv[0]);
60
61 /* Initialize device dependent fields */
62 dev->fd = -1;
63 dev->ascii = 0;
64 dev->crlf = 0;
65 dev->cardpos = 0;
66 dev->cardrem = CARD_LENGTH;
67 dev->notrunc = 0;
68
69 if(!sscanf(dev->typname,"%hx",&(dev->devtype)))
70 dev->devtype = 0x3525;
71
72 /* Process the driver arguments */
73 for (i = 1; i < argc; i++)
74 {
75 if (strcasecmp(argv[i], "ascii") == 0)
76 {
77 dev->ascii = 1;
78 continue;
79 }
80
81 if (strcasecmp(argv[i], "ebcdic") == 0)
82 {
83 dev->ascii = 0;
84 continue;
85 }
86
87 if (strcasecmp(argv[i], "crlf") == 0)
88 {
89 dev->crlf = 1;
90 continue;
91 }
92
93 if (strcasecmp(argv[i], "noclear") == 0)
94 {
95 dev->notrunc = 1;
96 continue;
97 }
98
99 logmsg (_("HHCPU002E Invalid argument: %s\n"),
100 argv[i]);
101 return -1;
102 }
103
104 /* Set length of buffer */
105 dev->bufsize = CARD_LENGTH + 2;
106
107 /* Set number of sense bytes */
108 dev->numsense = 1;
109
110 /* Initialize the device identifier bytes */
111 dev->devid[0] = 0xFF;
112 dev->devid[1] = 0x28; /* Control unit type is 2821-1 */
113 dev->devid[2] = 0x21;
114 dev->devid[3] = 0x01;
115 dev->devid[4] = dev->devtype >> 8;
116 dev->devid[5] = dev->devtype & 0xFF;
117 dev->devid[6] = 0x01;
118 dev->numdevid = 7;
119
120 /* Activate I/O tracing */
121 // dev->ccwtrace = 1;
122
123 return 0;
124 } /* end function cardpch_init_handler */
125
126 /*-------------------------------------------------------------------*/
127 /* Query the device definition */
128 /*-------------------------------------------------------------------*/
cardpch_query_device(DEVBLK * dev,char ** class,int buflen,char * buffer)129 static void cardpch_query_device (DEVBLK *dev, char **class,
130 int buflen, char *buffer)
131 {
132
133 BEGIN_DEVICE_CLASS_QUERY( "PCH", dev, class, buflen, buffer );
134
135 snprintf (buffer, buflen, "%s%s%s%s",
136 dev->filename,
137 (dev->ascii ? " ascii" : " ebcdic"),
138 ((dev->ascii && dev->crlf) ? " crlf" : ""),
139 (dev->notrunc ? " notrunc" : ""));
140
141 } /* end function cardpch_query_device */
142
143 /*-------------------------------------------------------------------*/
144 /* Close the device */
145 /*-------------------------------------------------------------------*/
cardpch_close_device(DEVBLK * dev)146 static int cardpch_close_device ( DEVBLK *dev )
147 {
148 /* Close the device file */
149 if (dev->fd >= 0)
150 close (dev->fd);
151 dev->fd = -1;
152
153 return 0;
154 } /* end function cardpch_close_device */
155
156 /*-------------------------------------------------------------------*/
157 /* Execute a Channel Command Word */
158 /*-------------------------------------------------------------------*/
cardpch_execute_ccw(DEVBLK * dev,BYTE code,BYTE flags,BYTE chained,U16 count,BYTE prevcode,int ccwseq,BYTE * iobuf,BYTE * more,BYTE * unitstat,U16 * residual)159 static void cardpch_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags,
160 BYTE chained, U16 count, BYTE prevcode, int ccwseq,
161 BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual)
162 {
163 int rc; /* Return code */
164 int i; /* Loop counter */
165 int num; /* Number of bytes to move */
166 int open_flags; /* File open flags */
167 BYTE c; /* Output character */
168 char pathname[MAX_PATH]; /* file path in host format */
169
170 UNREFERENCED(prevcode);
171 UNREFERENCED(ccwseq);
172
173 /* Open the device file if necessary */
174 if (dev->fd < 0 && !IS_CCW_SENSE(code))
175 {
176 hostpath(pathname, dev->filename, sizeof(pathname));
177 open_flags = O_WRONLY | O_CREAT /* | O_SYNC */ | O_BINARY;
178 if (dev->notrunc != 1)
179 {
180 open_flags |= O_TRUNC;
181 }
182 rc = hopen(pathname, open_flags,
183 S_IRUSR | S_IWUSR | S_IRGRP);
184 if (rc < 0)
185 {
186 /* Handle open failure */
187 logmsg (_("HHCPU003E Error opening file %s: %s\n"),
188 dev->filename, strerror(errno));
189
190 /* Set unit check with intervention required */
191 dev->sense[0] = SENSE_IR;
192 *unitstat = CSW_CE | CSW_DE | CSW_UC;
193 return;
194 }
195 dev->fd = rc;
196 }
197
198 /* Process depending on CCW opcode */
199 switch (code) {
200
201 case 0x01:
202 case 0x41:
203 case 0x81:
204 /*---------------------------------------------------------------*/
205 /* WRITE, FEED, SELECT STACKER */
206 /*---------------------------------------------------------------*/
207 /* Start a new record if not data-chained from previous CCW */
208 if ((chained & CCW_FLAGS_CD) == 0)
209 {
210 dev->cardpos = 0;
211 dev->cardrem = CARD_LENGTH;
212
213 } /* end if(!data-chained) */
214
215 /* Calculate number of bytes to write and set residual count */
216 num = (count < dev->cardrem) ? count : dev->cardrem;
217 *residual = count - num;
218
219 /* Copy data from channel buffer to card buffer */
220 for (i = 0; i < num; i++)
221 {
222 c = iobuf[i];
223
224 if (dev->ascii)
225 {
226 c = guest_to_host(c);
227 if (!isprint(c)) c = SPACE;
228 }
229
230 dev->buf[dev->cardpos] = c;
231 dev->cardpos++;
232 dev->cardrem--;
233 } /* end for(i) */
234
235 /* Perform end of record processing if not data-chaining */
236 if ((flags & CCW_FLAGS_CD) == 0)
237 {
238 if (dev->ascii)
239 {
240 /* Truncate trailing blanks from card buffer */
241 for (i = dev->cardpos; i > 0; i--)
242 if (dev->buf[i-1] != SPACE) break;
243
244 /* Append carriage return and line feed */
245 if (dev->crlf) dev->buf[i++] = '\r';
246 dev->buf[i++] = '\n';
247 }
248 else
249 {
250 /* Pad card image with blanks */
251 for (i = dev->cardpos; i < CARD_LENGTH; i++)
252 dev->buf[i] = HEX40;
253 }
254
255 /* Write card image */
256 write_buffer (dev, dev->buf, i, unitstat);
257 if (*unitstat != 0) break;
258
259 } /* end if(!data-chaining) */
260
261 /* Return normal status */
262 *unitstat = CSW_CE | CSW_DE;
263 break;
264
265 case 0x03:
266 /*---------------------------------------------------------------*/
267 /* CONTROL NO-OPERATION */
268 /*---------------------------------------------------------------*/
269 *unitstat = CSW_CE | CSW_DE;
270 break;
271
272 case 0x04:
273 /*---------------------------------------------------------------*/
274 /* SENSE */
275 /*---------------------------------------------------------------*/
276 /* Calculate residual byte count */
277 num = (count < dev->numsense) ? count : dev->numsense;
278 *residual = count - num;
279 if (count < dev->numsense) *more = 1;
280
281 /* Copy device sense bytes to channel I/O buffer */
282 memcpy (iobuf, dev->sense, num);
283
284 /* Clear the device sense bytes */
285 memset (dev->sense, 0, sizeof(dev->sense));
286
287 /* Return unit status */
288 *unitstat = CSW_CE | CSW_DE;
289 break;
290
291 case 0xE4:
292 /*---------------------------------------------------------------*/
293 /* SENSE ID */
294 /*---------------------------------------------------------------*/
295 /* Calculate residual byte count */
296 num = (count < dev->numdevid) ? count : dev->numdevid;
297 *residual = count - num;
298 if (count < dev->numdevid) *more = 1;
299
300 /* Copy device identifier bytes to channel I/O buffer */
301 memcpy (iobuf, dev->devid, num);
302
303 /* Return unit status */
304 *unitstat = CSW_CE | CSW_DE;
305 break;
306
307 default:
308 /*---------------------------------------------------------------*/
309 /* INVALID OPERATION */
310 /*---------------------------------------------------------------*/
311 /* Set command reject sense byte, and unit check status */
312 dev->sense[0] = SENSE_CR;
313 *unitstat = CSW_CE | CSW_DE | CSW_UC;
314
315 } /* end switch(code) */
316
317 } /* end function cardpch_execute_ccw */
318
319
320 #if defined(OPTION_DYNAMIC_LOAD)
321 static
322 #endif
323 DEVHND cardpch_device_hndinfo = {
324 &cardpch_init_handler, /* Device Initialisation */
325 &cardpch_execute_ccw, /* Device CCW execute */
326 &cardpch_close_device, /* Device Close */
327 &cardpch_query_device, /* Device Query */
328 NULL, /* Device Start channel pgm */
329 NULL, /* Device End channel pgm */
330 NULL, /* Device Resume channel pgm */
331 NULL, /* Device Suspend channel pgm */
332 NULL, /* Device Read */
333 NULL, /* Device Write */
334 NULL, /* Device Query used */
335 NULL, /* Device Reserve */
336 NULL, /* Device Release */
337 NULL, /* Device Attention */
338 NULL, /* Immediate CCW Codes */
339 NULL, /* Signal Adapter Input */
340 NULL, /* Signal Adapter Output */
341 NULL, /* Hercules suspend */
342 NULL /* Hercules resume */
343 };
344
345 /* Libtool static name colision resolution */
346 /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
347 #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
348 #define hdl_ddev hdt3525_LTX_hdl_ddev
349 #define hdl_depc hdt3525_LTX_hdl_depc
350 #define hdl_reso hdt3525_LTX_hdl_reso
351 #define hdl_init hdt3525_LTX_hdl_init
352 #define hdl_fini hdt3525_LTX_hdl_fini
353 #endif
354
355
356 #if defined(OPTION_DYNAMIC_LOAD)
357 HDL_DEPENDENCY_SECTION;
358 {
359 HDL_DEPENDENCY(HERCULES);
360 HDL_DEPENDENCY(DEVBLK);
361 }
362 END_DEPENDENCY_SECTION
363
364
365 HDL_DEVICE_SECTION;
366 {
367 HDL_DEVICE(3525, cardpch_device_hndinfo );
368 }
369 END_DEVICE_SECTION
370 #endif
371