2 * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
4 * tubttysiz.c -- Linemode screen-size determiner
10 * Author: Richard Hitt
13 static int tty3270_size_io(tub_t *tubp);
14 static void tty3270_size_int(tub_t *tubp, devstat_t *dsp);
15 static int tty3270_size_wait(tub_t *tubp, long *flags, int stat);
18 * Structure representing Usable Area Query Reply Base
21 short l; /* Length of this structured field */
22 char sfid; /* 0x81 if Query Reply */
23 char qcode; /* 0x81 if Usable Area */
26 #define FLAGS0_ADDR 0x0f
27 #define FLAGS0_ADDR_12_14 1 /* 12/14-bit adrs ok */
28 #define FLAGS0_ADDR_12_14_16 3 /* 12/14/16-bit adrs ok */
30 short w; /* Width of usable area */
31 short h; /* Heigth of usavle area */
32 char units; /* 0x00:in; 0x01:mm */
37 short buffsz; /* Character buffer size, bytes */
42 } __attribute__ ((packed)) uab_t;
45 * Structure representing Alternate Usable Area Self-Defining Parameter
48 char l; /* Length of this Self-Defining Parm */
49 char sdpid; /* 0x02 if Alternate Usable Area */
50 #define SDPID_AUA 0x02
52 char auaid; /* 0x01 is Id for the A U A */
53 short wauai; /* Width of AUAi */
54 short hauai; /* Height of AUAi */
55 char auaunits; /* 0x00:in, 0x01:mm */
60 } __attribute__ ((packed)) aua_t;
63 * Structure representing one followed by the other
68 } __attribute__ ((packed)) ua_t;
71 * Try to determine screen size using Read Partition (Query)
74 tty3270_size(tub_t *tubp, long *flags)
76 char wbuf[7] = { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
84 int geom_rows, geom_cols, fourteenbitadr;
85 void (*oldint)(struct tub_s *, devstat_t *);
87 if (tubp->flags & TUB_SIZED)
90 geom_rows = tubp->geom_rows;
91 geom_cols = tubp->geom_cols;
94 tubp->intv = tty3270_size_int;
96 if (tubp->cmd == TBC_CONOPEN) {
97 tubp->ttyccw.cmd_code = TC_EWRITEA;
101 tubp->ttyccw.flags = CCW_FLAG_SLI;
102 tubp->ttyccw.cda = virt_to_phys(miniscreen);
103 tubp->ttyccw.count = (char *)cp - miniscreen;
104 rc = tty3270_size_io(tubp);
105 rc = tty3270_size_wait(tubp, flags, 0);
108 tubp->ttyccw.cmd_code = TC_WRITESF;
109 tubp->ttyccw.flags = CCW_FLAG_SLI;
110 tubp->ttyccw.cda = virt_to_phys(wbuf);
111 tubp->ttyccw.count = sizeof wbuf;
114 rc = tty3270_size_io(tubp);
116 printk("tty3270_size_io returned %d\n", rc);
118 rc = tty3270_size_wait(tubp, flags, 0);
124 * Unit-Check Processing:
125 * Expect Command Reject or Intervention Required.
126 * For Command Reject assume old hdwe/software and
127 * set a default size of 80x24.
128 * For Intervention Required, wait for signal pending
129 * or Unsolicited Device End; if the latter, retry.
131 if (tubp->dstat & DEV_STAT_UNIT_CHECK) {
132 if (tubp->sense.data[0] & SNS0_CMD_REJECT) {
133 goto use_diag210; /* perhaps it's tn3270 */
134 } else if (tubp->sense.data[0] & SNS0_INTERVENTION_REQ) {
135 if ((rc = tty3270_size_wait(tubp, flags,
140 printk("tty3270_size(): unkn sense %.2x\n",
141 tubp->sense.data[0]);
145 if ((rc = tty3270_size_wait(tubp, flags, DEV_STAT_ATTENTION)))
148 /* Set up a read ccw and issue it */
149 tubp->ttyccw.cmd_code = TC_READMOD;
150 tubp->ttyccw.flags = CCW_FLAG_SLI;
151 tubp->ttyccw.cda = virt_to_phys(miniscreen);
152 tubp->ttyccw.count = sizeof miniscreen;
153 tty3270_size_io(tubp);
154 rc = tty3270_size_wait(tubp, flags, 0);
158 count = sizeof miniscreen - tubp->cswl;
163 if (uap->uab.qcode != QCODE_UA)
165 geom_rows = uap->uab.h;
166 geom_cols = uap->uab.w;
167 if ((uap->uab.flags0 & FLAGS0_ADDR) == FLAGS0_ADDR_12_14 ||
168 (uap->uab.flags0 & FLAGS0_ADDR) == FLAGS0_ADDR_12_14_16)
170 if (uap->uab.l <= sizeof uap->uab)
172 if (uap->aua.sdpid != SDPID_AUA) {
173 printk("AUA sdpid was 0x%.2x, expecting 0x%.2x\n",
174 uap->aua.sdpid, SDPID_AUA);
177 geom_rows = uap->aua.hauai;
178 geom_cols = uap->aua.wauai;
185 d210.vrdcdvno = tubp->devno;
186 d210.vrdclen = sizeof d210;
189 printk("tty3270_size: diag210 for 0x%.4x "
190 "returned %d\n", tubp->devno, rc);
193 switch(d210.vrdccrmd) {
211 printk("vrdccrmd is 0x%.8x\n", d210.vrdccrmd);
216 if (geom_rows == 0) {
217 geom_rows = _GEOM_ROWS;
218 geom_cols = _GEOM_COLS;
220 tubp->tubiocb.pf_cnt = 24;
221 tubp->tubiocb.re_cnt = 20;
222 tubp->tubiocb.map = 0;
224 screenl = geom_rows * geom_cols + 100;
225 screen = (char (*)[])kmalloc(screenl, GFP_KERNEL);
226 if (screen == NULL) {
227 printk("ttyscreen size %d unavailable\n", screenl);
230 kfree(tubp->ttyscreen);
231 tubp->tubiocb.line_cnt = tubp->geom_rows = geom_rows;
232 tubp->tubiocb.col_cnt = tubp->geom_cols = geom_cols;
233 tubp->tty_14bitadr = fourteenbitadr;
234 tubp->ttyscreen = screen;
235 tubp->ttyscreenl = screenl;
236 if (geom_rows == 24 && geom_cols == 80)
237 tubp->tubiocb.model = 2;
238 else if (geom_rows == 32 && geom_cols == 80)
239 tubp->tubiocb.model = 3;
240 else if (geom_rows == 43 && geom_cols == 80)
241 tubp->tubiocb.model = 4;
242 else if (geom_rows == 27 && geom_cols == 132)
243 tubp->tubiocb.model = 5;
245 tubp->tubiocb.model = 0;
246 tubp->flags |= TUB_SIZED;
248 if (rc == 0 && tubp->ttyscreen == NULL)
255 tty3270_size_io(tub_t *tubp)
257 tubp->flags |= TUB_WORKING;
260 return do_IO(tubp->irq, &tubp->ttyccw, tubp->irq, 0, 0);
264 tty3270_size_int(tub_t *tubp, devstat_t *dsp)
266 #define DEV_NOT_WORKING \
267 (DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_CHECK)
269 tubp->dstat = dsp->dstat;
270 if (dsp->dstat & DEV_STAT_CHN_END)
271 tubp->cswl = dsp->rescnt;
272 if (dsp->dstat & DEV_NOT_WORKING)
273 tubp->flags &= ~TUB_WORKING;
274 if (dsp->dstat & DEV_STAT_UNIT_CHECK)
275 tubp->sense = dsp->ii.sense;
277 wake_up_interruptible(&tubp->waitq);
281 * Wait for something. If the third arg is zero, wait until
282 * tty3270_size_int() turns off TUB_WORKING. If the third arg
283 * is not zero, it is a device-status bit; wait until dstat
284 * has the bit turned on. Never wait if signal is pending.
285 * Return 0 unless signal pending, in which case -ERESTARTSYS.
288 tty3270_size_wait(tub_t *tubp, long *flags, int stat)
290 DECLARE_WAITQUEUE(wait, current);
292 add_wait_queue(&tubp->waitq, &wait);
293 while (!signal_pending(current) &&
294 (stat? (tubp->dstat & stat) == 0:
295 (tubp->flags & TUB_WORKING) != 0)) {
296 current->state = TASK_INTERRUPTIBLE;
297 TUBUNLOCK(tubp->irq, *flags);
299 current->state = TASK_RUNNING;
300 TUBLOCK(tubp->irq, *flags);
302 remove_wait_queue(&tubp->waitq, &wait);
303 return signal_pending(current)? -ERESTARTSYS: 0;