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