blob: 0743f13101eedfec3eb5b6c1656bcb2b379fc785 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02002 * IBM/3270 Driver - core functions.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02004 * Author(s):
5 * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
6 * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
7 * Copyright IBM Corp. 2003, 2009
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
9
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/module.h>
11#include <linux/err.h>
12#include <linux/init.h>
13#include <linux/interrupt.h>
14#include <linux/list.h>
15#include <linux/slab.h>
16#include <linux/types.h>
17#include <linux/wait.h>
18
19#include <asm/ccwdev.h>
20#include <asm/cio.h>
21#include <asm/ebcdic.h>
Michael Holzheu0a87c5c2007-08-22 13:51:40 +020022#include <asm/diag.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023
24#include "raw3270.h"
25
Richard Hitted3cb6f2005-10-30 15:00:10 -080026#include <linux/major.h>
27#include <linux/kdev_t.h>
28#include <linux/device.h>
Ingo Molnar14cc3e22006-03-26 01:37:14 -080029#include <linux/mutex.h>
Richard Hitted3cb6f2005-10-30 15:00:10 -080030
Martin Schwidefskyc95571e2013-01-08 15:31:11 +010031struct class *class3270;
Richard Hitted3cb6f2005-10-30 15:00:10 -080032
Linus Torvalds1da177e2005-04-16 15:20:36 -070033/* The main 3270 data structure. */
34struct raw3270 {
35 struct list_head list;
36 struct ccw_device *cdev;
37 int minor;
38
39 short model, rows, cols;
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +010040 unsigned int state;
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 unsigned long flags;
42
43 struct list_head req_queue; /* Request queue. */
44 struct list_head view_list; /* List of available views. */
45 struct raw3270_view *view; /* Active view. */
46
47 struct timer_list timer; /* Device timer. */
48
49 unsigned char *ascebc; /* ascii -> ebcdic table */
Martin Schwidefsky132fab12006-06-29 14:57:39 +020050
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +010051 struct raw3270_view init_view;
52 struct raw3270_request init_reset;
53 struct raw3270_request init_readpart;
54 struct raw3270_request init_readmod;
Martin Schwidefsky132fab12006-06-29 14:57:39 +020055 unsigned char init_data[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -070056};
57
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +010058/* raw3270->state */
59#define RAW3270_STATE_INIT 0 /* Initial state */
60#define RAW3270_STATE_RESET 1 /* Reset command is pending */
61#define RAW3270_STATE_W4ATTN 2 /* Wait for attention interrupt */
62#define RAW3270_STATE_READMOD 3 /* Read partition is pending */
63#define RAW3270_STATE_READY 4 /* Device is usable by views */
64
Linus Torvalds1da177e2005-04-16 15:20:36 -070065/* raw3270->flags */
66#define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */
67#define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +010068#define RAW3270_FLAGS_CONSOLE 2 /* Device is the console. */
69#define RAW3270_FLAGS_FROZEN 3 /* set if 3270 is frozen for suspend */
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71/* Semaphore to protect global data of raw3270 (devices, views, etc). */
Ingo Molnar14cc3e22006-03-26 01:37:14 -080072static DEFINE_MUTEX(raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74/* List of 3270 devices. */
Denis Chengc11ca972008-01-26 14:11:13 +010075static LIST_HEAD(raw3270_devices);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
77/*
78 * Flag to indicate if the driver has been registered. Some operations
79 * like waiting for the end of i/o need to be done differently as long
80 * as the kernel is still starting up (console support).
81 */
82static int raw3270_registered;
83
84/* Module parameters */
Rusty Russell90ab5ee2012-01-13 09:32:20 +103085static bool tubxcorrect = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086module_param(tubxcorrect, bool, 0);
87
88/*
89 * Wait queue for device init/delete, view delete.
90 */
91DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
92
93/*
94 * Encode array for 12 bit 3270 addresses.
95 */
Heiko Carstens2b67fc42007-02-05 21:16:47 +010096static unsigned char raw3270_ebcgraf[64] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
98 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
99 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
100 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
101 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
102 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
103 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
104 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
105};
106
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100107static inline int raw3270_state_ready(struct raw3270 *rp)
108{
109 return rp->state == RAW3270_STATE_READY;
110}
111
112static inline int raw3270_state_final(struct raw3270 *rp)
113{
114 return rp->state == RAW3270_STATE_INIT ||
115 rp->state == RAW3270_STATE_READY;
116}
117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118void
119raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
120{
121 if (test_bit(RAW3270_FLAGS_14BITADDR, &rp->flags)) {
122 cp[0] = (addr >> 8) & 0x3f;
123 cp[1] = addr & 0xff;
124 } else {
125 cp[0] = raw3270_ebcgraf[(addr >> 6) & 0x3f];
126 cp[1] = raw3270_ebcgraf[addr & 0x3f];
127 }
128}
129
130/*
131 * Allocate a new 3270 ccw request
132 */
133struct raw3270_request *
134raw3270_request_alloc(size_t size)
135{
136 struct raw3270_request *rq;
137
138 /* Allocate request structure */
Eric Sesterhenn88abaab2006-03-24 03:15:31 -0800139 rq = kzalloc(sizeof(struct raw3270_request), GFP_KERNEL | GFP_DMA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 if (!rq)
141 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 /* alloc output buffer. */
144 if (size > 0) {
145 rq->buffer = kmalloc(size, GFP_KERNEL | GFP_DMA);
146 if (!rq->buffer) {
147 kfree(rq);
148 return ERR_PTR(-ENOMEM);
149 }
150 }
151 rq->size = size;
152 INIT_LIST_HEAD(&rq->list);
153
154 /*
155 * Setup ccw.
156 */
157 rq->ccw.cda = __pa(rq->buffer);
158 rq->ccw.flags = CCW_FLAG_SLI;
159
160 return rq;
161}
162
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163/*
164 * Free 3270 ccw request
165 */
166void
167raw3270_request_free (struct raw3270_request *rq)
168{
Jesper Juhl17fd6822005-11-07 01:01:30 -0800169 kfree(rq->buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170 kfree(rq);
171}
172
173/*
174 * Reset request to initial state.
175 */
176void
177raw3270_request_reset(struct raw3270_request *rq)
178{
179 BUG_ON(!list_empty(&rq->list));
180 rq->ccw.cmd_code = 0;
181 rq->ccw.count = 0;
182 rq->ccw.cda = __pa(rq->buffer);
183 rq->ccw.flags = CCW_FLAG_SLI;
184 rq->rescnt = 0;
185 rq->rc = 0;
186}
187
188/*
189 * Set command code to ccw of a request.
190 */
191void
192raw3270_request_set_cmd(struct raw3270_request *rq, u8 cmd)
193{
194 rq->ccw.cmd_code = cmd;
195}
196
197/*
198 * Add data fragment to output buffer.
199 */
200int
201raw3270_request_add_data(struct raw3270_request *rq, void *data, size_t size)
202{
203 if (size + rq->ccw.count > rq->size)
204 return -E2BIG;
205 memcpy(rq->buffer + rq->ccw.count, data, size);
206 rq->ccw.count += size;
207 return 0;
208}
209
210/*
211 * Set address/length pair to ccw of a request.
212 */
213void
214raw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size)
215{
216 rq->ccw.cda = __pa(data);
217 rq->ccw.count = size;
218}
219
220/*
221 * Set idal buffer to ccw of a request.
222 */
223void
224raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
225{
226 rq->ccw.cda = __pa(ib->data);
227 rq->ccw.count = ib->size;
228 rq->ccw.flags |= CCW_FLAG_IDA;
229}
230
231/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 * Add the request to the request queue, try to start it if the
233 * 3270 device is idle. Return without waiting for end of i/o.
234 */
235static int
236__raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
237 struct raw3270_request *rq)
238{
239 rq->view = view;
240 raw3270_get_view(view);
241 if (list_empty(&rp->req_queue) &&
242 !test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {
243 /* No other requests are on the queue. Start this one. */
244 rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
245 (unsigned long) rq, 0, 0);
246 if (rq->rc) {
247 raw3270_put_view(view);
248 return rq->rc;
249 }
250 }
251 list_add_tail(&rq->list, &rp->req_queue);
252 return 0;
253}
254
255int
Martin Schwidefsky233faec2014-03-21 09:25:24 +0100256raw3270_view_active(struct raw3270_view *view)
257{
258 struct raw3270 *rp = view->dev;
259
260 return rp && rp->view == view &&
261 !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
262}
263
264int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
266{
267 unsigned long flags;
268 struct raw3270 *rp;
269 int rc;
270
271 spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
272 rp = view->dev;
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200273 if (!rp || rp->view != view ||
274 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 rc = -EACCES;
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100276 else if (!raw3270_state_ready(rp))
277 rc = -EBUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 else
279 rc = __raw3270_start(rp, view, rq);
280 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
281 return rc;
282}
283
284int
Richard Hitted3cb6f2005-10-30 15:00:10 -0800285raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
286{
287 struct raw3270 *rp;
288 int rc;
289
290 rp = view->dev;
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200291 if (!rp || rp->view != view ||
292 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
Richard Hitted3cb6f2005-10-30 15:00:10 -0800293 rc = -EACCES;
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100294 else if (!raw3270_state_ready(rp))
295 rc = -EBUSY;
Richard Hitted3cb6f2005-10-30 15:00:10 -0800296 else
297 rc = __raw3270_start(rp, view, rq);
298 return rc;
299}
300
301int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq)
303{
304 struct raw3270 *rp;
305
306 rp = view->dev;
307 rq->view = view;
308 raw3270_get_view(view);
309 list_add_tail(&rq->list, &rp->req_queue);
310 return 0;
311}
312
313/*
314 * 3270 interrupt routine, called from the ccw_device layer
315 */
316static void
317raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
318{
319 struct raw3270 *rp;
320 struct raw3270_view *view;
321 struct raw3270_request *rq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -0700323 rp = dev_get_drvdata(&cdev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 if (!rp)
325 return;
326 rq = (struct raw3270_request *) intparm;
327 view = rq ? rq->view : rp->view;
328
Martin Schwidefsky8340ab62016-05-02 14:53:29 +0200329 if (!IS_ERR(irb)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 /* Handle CE-DE-UE and subsequent UDE */
Martin Schwidefsky8340ab62016-05-02 14:53:29 +0200331 if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 clear_bit(RAW3270_FLAGS_BUSY, &rp->flags);
Martin Schwidefsky8340ab62016-05-02 14:53:29 +0200333 if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END |
334 DEV_STAT_DEV_END |
335 DEV_STAT_UNIT_EXCEP))
336 set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
337 /* Handle disconnected devices */
338 if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
339 (irb->ecw[0] & SNS0_INTERVENTION_REQ))
340 set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
341 /* Call interrupt handler of the view */
342 if (view)
343 view->fn->intv(view, rq, irb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 }
Martin Schwidefsky8340ab62016-05-02 14:53:29 +0200345
346 if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags))
347 /* Device busy, do not start I/O */
348 return;
349
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 if (rq) {
351 BUG_ON(list_empty(&rq->list));
352 /* The request completed, remove from queue and do callback. */
353 list_del_init(&rq->list);
354 if (rq->callback)
355 rq->callback(rq, rq->callback_data);
356 /* Do put_device for get_device in raw3270_start. */
357 raw3270_put_view(view);
358 }
Martin Schwidefsky8340ab62016-05-02 14:53:29 +0200359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 /*
361 * Try to start each request on request queue until one is
362 * started successful.
363 */
364 while (!list_empty(&rp->req_queue)) {
365 rq = list_entry(rp->req_queue.next,struct raw3270_request,list);
366 rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
367 (unsigned long) rq, 0, 0);
368 if (rq->rc == 0)
369 break;
370 /* Start failed. Remove request and do callback. */
371 list_del_init(&rq->list);
372 if (rq->callback)
373 rq->callback(rq, rq->callback_data);
374 /* Do put_device for get_device in raw3270_start. */
375 raw3270_put_view(view);
376 }
377}
378
379/*
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100380 * To determine the size of the 3270 device we need to do:
381 * 1) send a 'read partition' data stream to the device
382 * 2) wait for the attn interrupt that precedes the query reply
383 * 3) do a read modified to get the query reply
384 * To make things worse we have to cope with intervention
385 * required (3270 device switched to 'stand-by') and command
386 * rejects (old devices that can't do 'read partition').
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388struct raw3270_ua { /* Query Reply structure for Usable Area */
389 struct { /* Usable Area Query Reply Base */
390 short l; /* Length of this structured field */
391 char sfid; /* 0x81 if Query Reply */
392 char qcode; /* 0x81 if Usable Area */
393 char flags0;
394 char flags1;
395 short w; /* Width of usable area */
396 short h; /* Heigth of usavle area */
397 char units; /* 0x00:in; 0x01:mm */
398 int xr;
399 int yr;
400 char aw;
401 char ah;
402 short buffsz; /* Character buffer size, bytes */
403 char xmin;
404 char ymin;
405 char xmax;
406 char ymax;
407 } __attribute__ ((packed)) uab;
408 struct { /* Alternate Usable Area Self-Defining Parameter */
409 char l; /* Length of this Self-Defining Parm */
410 char sdpid; /* 0x02 if Alternate Usable Area */
411 char res;
412 char auaid; /* 0x01 is Id for the A U A */
413 short wauai; /* Width of AUAi */
414 short hauai; /* Height of AUAi */
415 char auaunits; /* 0x00:in, 0x01:mm */
416 int auaxr;
417 int auayr;
418 char awauai;
419 char ahauai;
420 } __attribute__ ((packed)) aua;
421} __attribute__ ((packed));
422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423static void
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100424raw3270_size_device_vm(struct raw3270 *rp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425{
426 int rc, model;
Cornelia Huck9a92fe42007-05-10 15:45:42 +0200427 struct ccw_dev_id dev_id;
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100428 struct diag210 diag_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Cornelia Huck9a92fe42007-05-10 15:45:42 +0200430 ccw_device_get_id(rp->cdev, &dev_id);
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100431 diag_data.vrdcdvno = dev_id.devno;
432 diag_data.vrdclen = sizeof(struct diag210);
433 rc = diag210(&diag_data);
434 model = diag_data.vrdccrmd;
435 /* Use default model 2 if the size could not be detected */
436 if (rc || model < 2 || model > 5)
437 model = 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 switch (model) {
439 case 2:
440 rp->model = model;
441 rp->rows = 24;
442 rp->cols = 80;
443 break;
444 case 3:
445 rp->model = model;
446 rp->rows = 32;
447 rp->cols = 80;
448 break;
449 case 4:
450 rp->model = model;
451 rp->rows = 43;
452 rp->cols = 80;
453 break;
454 case 5:
455 rp->model = model;
456 rp->rows = 27;
457 rp->cols = 132;
458 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460}
461
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100462static void
463raw3270_size_device(struct raw3270 *rp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 struct raw3270_ua *uap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 /* Got a Query Reply */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200468 uap = (struct raw3270_ua *) (rp->init_data + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 /* Paranoia check. */
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100470 if (rp->init_readmod.rc || rp->init_data[0] != 0x88 ||
471 uap->uab.qcode != 0x81) {
472 /* Couldn't detect size. Use default model 2. */
473 rp->model = 2;
474 rp->rows = 24;
475 rp->cols = 80;
476 return;
477 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 /* Copy rows/columns of default Usable Area */
479 rp->rows = uap->uab.h;
480 rp->cols = uap->uab.w;
481 /* Check for 14 bit addressing */
482 if ((uap->uab.flags0 & 0x0d) == 0x01)
483 set_bit(RAW3270_FLAGS_14BITADDR, &rp->flags);
484 /* Check for Alternate Usable Area */
485 if (uap->uab.l == sizeof(struct raw3270_ua) &&
486 uap->aua.sdpid == 0x02) {
487 rp->rows = uap->aua.hauai;
488 rp->cols = uap->aua.wauai;
489 }
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100490 /* Try to find a model. */
491 rp->model = 0;
492 if (rp->rows == 24 && rp->cols == 80)
493 rp->model = 2;
494 if (rp->rows == 32 && rp->cols == 80)
495 rp->model = 3;
496 if (rp->rows == 43 && rp->cols == 80)
497 rp->model = 4;
498 if (rp->rows == 27 && rp->cols == 132)
499 rp->model = 5;
500}
501
502static void
503raw3270_size_device_done(struct raw3270 *rp)
504{
505 struct raw3270_view *view;
506
507 rp->view = NULL;
508 rp->state = RAW3270_STATE_READY;
509 /* Notify views about new size */
510 list_for_each_entry(view, &rp->view_list, list)
511 if (view->fn->resize)
512 view->fn->resize(view, rp->model, rp->rows, rp->cols);
513 /* Setup processing done, now activate a view */
514 list_for_each_entry(view, &rp->view_list, list) {
515 rp->view = view;
516 if (view->fn->activate(view) == 0)
517 break;
518 rp->view = NULL;
519 }
520}
521
522static void
523raw3270_read_modified_cb(struct raw3270_request *rq, void *data)
524{
525 struct raw3270 *rp = rq->view->dev;
526
527 raw3270_size_device(rp);
528 raw3270_size_device_done(rp);
529}
530
531static void
532raw3270_read_modified(struct raw3270 *rp)
533{
534 if (rp->state != RAW3270_STATE_W4ATTN)
535 return;
536 /* Use 'read modified' to get the result of a read partition. */
537 memset(&rp->init_readmod, 0, sizeof(rp->init_readmod));
538 memset(&rp->init_data, 0, sizeof(rp->init_data));
539 rp->init_readmod.ccw.cmd_code = TC_READMOD;
540 rp->init_readmod.ccw.flags = CCW_FLAG_SLI;
541 rp->init_readmod.ccw.count = sizeof(rp->init_data);
542 rp->init_readmod.ccw.cda = (__u32) __pa(rp->init_data);
543 rp->init_readmod.callback = raw3270_read_modified_cb;
544 rp->state = RAW3270_STATE_READMOD;
545 raw3270_start_irq(&rp->init_view, &rp->init_readmod);
546}
547
548static void
549raw3270_writesf_readpart(struct raw3270 *rp)
550{
551 static const unsigned char wbuf[] =
552 { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
553
554 /* Store 'read partition' data stream to init_data */
555 memset(&rp->init_readpart, 0, sizeof(rp->init_readpart));
556 memset(&rp->init_data, 0, sizeof(rp->init_data));
557 memcpy(&rp->init_data, wbuf, sizeof(wbuf));
558 rp->init_readpart.ccw.cmd_code = TC_WRITESF;
559 rp->init_readpart.ccw.flags = CCW_FLAG_SLI;
560 rp->init_readpart.ccw.count = sizeof(wbuf);
561 rp->init_readpart.ccw.cda = (__u32) __pa(&rp->init_data);
562 rp->state = RAW3270_STATE_W4ATTN;
563 raw3270_start_irq(&rp->init_view, &rp->init_readpart);
564}
565
566/*
567 * Device reset
568 */
569static void
570raw3270_reset_device_cb(struct raw3270_request *rq, void *data)
571{
572 struct raw3270 *rp = rq->view->dev;
573
574 if (rp->state != RAW3270_STATE_RESET)
575 return;
Martin Schwidefskydc3ac5f2013-10-14 16:48:29 +0200576 if (rq->rc) {
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100577 /* Reset command failed. */
578 rp->state = RAW3270_STATE_INIT;
Martin Schwidefsky01a7cfa2013-10-15 13:41:05 +0200579 } else if (MACHINE_IS_VM) {
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100580 raw3270_size_device_vm(rp);
581 raw3270_size_device_done(rp);
582 } else
583 raw3270_writesf_readpart(rp);
Martin Schwidefskybd1cb5d2014-03-21 15:24:27 +0100584 memset(&rp->init_reset, 0, sizeof(rp->init_reset));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585}
586
587static int
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100588__raw3270_reset_device(struct raw3270 *rp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
590 int rc;
591
Martin Schwidefskybd1cb5d2014-03-21 15:24:27 +0100592 /* Check if reset is already pending */
593 if (rp->init_reset.view)
594 return -EBUSY;
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100595 /* Store reset data stream to init_data/init_reset */
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100596 rp->init_data[0] = TW_KR;
597 rp->init_reset.ccw.cmd_code = TC_EWRITEA;
598 rp->init_reset.ccw.flags = CCW_FLAG_SLI;
599 rp->init_reset.ccw.count = 1;
600 rp->init_reset.ccw.cda = (__u32) __pa(rp->init_data);
601 rp->init_reset.callback = raw3270_reset_device_cb;
602 rc = __raw3270_start(rp, &rp->init_view, &rp->init_reset);
603 if (rc == 0 && rp->state == RAW3270_STATE_INIT)
604 rp->state = RAW3270_STATE_RESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 return rc;
606}
607
608static int
609raw3270_reset_device(struct raw3270 *rp)
610{
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100611 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 int rc;
613
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100614 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
615 rc = __raw3270_reset_device(rp);
616 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 return rc;
618}
619
Richard Hitted3cb6f2005-10-30 15:00:10 -0800620int
621raw3270_reset(struct raw3270_view *view)
622{
623 struct raw3270 *rp;
624 int rc;
625
626 rp = view->dev;
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200627 if (!rp || rp->view != view ||
628 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
Richard Hitted3cb6f2005-10-30 15:00:10 -0800629 rc = -EACCES;
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100630 else if (!raw3270_state_ready(rp))
631 rc = -EBUSY;
Richard Hitted3cb6f2005-10-30 15:00:10 -0800632 else
633 rc = raw3270_reset_device(view->dev);
634 return rc;
635}
636
Martin Schwidefsky8340ab62016-05-02 14:53:29 +0200637static void
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100638raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
639 struct irb *irb)
640{
641 struct raw3270 *rp;
642
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100643 if (rq) {
644 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
645 if (irb->ecw[0] & SNS0_CMD_REJECT)
646 rq->rc = -EOPNOTSUPP;
647 else
648 rq->rc = -EIO;
649 }
650 }
651 if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
652 /* Queue read modified after attention interrupt */
653 rp = view->dev;
654 raw3270_read_modified(rp);
655 }
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100656}
657
658static struct raw3270_fn raw3270_init_fn = {
659 .intv = raw3270_init_irq
660};
661
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662/*
663 * Setup new 3270 device.
664 */
665static int
666raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
667{
668 struct list_head *l;
669 struct raw3270 *tmp;
670 int minor;
671
672 memset(rp, 0, sizeof(struct raw3270));
673 /* Copy ebcdic -> ascii translation table. */
674 memcpy(ascebc, _ascebc, 256);
675 if (tubxcorrect) {
676 /* correct brackets and circumflex */
677 ascebc['['] = 0xad;
678 ascebc[']'] = 0xbd;
679 ascebc['^'] = 0xb0;
680 }
681 rp->ascebc = ascebc;
682
683 /* Set defaults. */
684 rp->rows = 24;
685 rp->cols = 80;
686
687 INIT_LIST_HEAD(&rp->req_queue);
688 INIT_LIST_HEAD(&rp->view_list);
689
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100690 rp->init_view.dev = rp;
691 rp->init_view.fn = &raw3270_init_fn;
692 rp->view = &rp->init_view;
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 /*
695 * Add device to list and find the smallest unused minor
Richard Hitted3cb6f2005-10-30 15:00:10 -0800696 * number for it. Note: there is no device with minor 0,
697 * see special case for fs3270.c:fs3270_open().
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 */
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800699 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 /* Keep the list sorted. */
Richard Hitted3cb6f2005-10-30 15:00:10 -0800701 minor = RAW3270_FIRSTMINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 rp->minor = -1;
703 list_for_each(l, &raw3270_devices) {
704 tmp = list_entry(l, struct raw3270, list);
705 if (tmp->minor > minor) {
706 rp->minor = minor;
707 __list_add(&rp->list, l->prev, l);
708 break;
709 }
710 minor++;
711 }
Richard Hitted3cb6f2005-10-30 15:00:10 -0800712 if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 rp->minor = minor;
714 list_add_tail(&rp->list, &raw3270_devices);
715 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800716 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 /* No free minor number? Then give up. */
718 if (rp->minor == -1)
719 return -EUSERS;
720 rp->cdev = cdev;
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -0700721 dev_set_drvdata(&cdev->dev, rp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 cdev->handler = raw3270_irq;
723 return 0;
724}
725
726#ifdef CONFIG_TN3270_CONSOLE
Sebastian Ott2253e8d2014-01-27 13:26:10 +0100727/* Tentative definition - see below for actual definition. */
728static struct ccw_driver raw3270_ccw_driver;
729
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730/*
731 * Setup 3270 device configured as console.
732 */
Sebastian Ott2253e8d2014-01-27 13:26:10 +0100733struct raw3270 __init *raw3270_setup_console(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734{
Sebastian Ott2253e8d2014-01-27 13:26:10 +0100735 struct ccw_device *cdev;
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100736 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 struct raw3270 *rp;
738 char *ascebc;
739 int rc;
740
Sebastian Ott1e532092014-01-27 13:28:10 +0100741 cdev = ccw_device_create_console(&raw3270_ccw_driver);
Sebastian Ott2253e8d2014-01-27 13:26:10 +0100742 if (IS_ERR(cdev))
743 return ERR_CAST(cdev);
744
Heiko Carstens33403dc2009-06-22 12:08:05 +0200745 rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
746 ascebc = kzalloc(256, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 rc = raw3270_setup_device(cdev, rp, ascebc);
748 if (rc)
749 return ERR_PTR(rc);
750 set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
Sebastian Ott1e532092014-01-27 13:28:10 +0100751
752 rc = ccw_device_enable_console(cdev);
753 if (rc) {
754 ccw_device_destroy_console(cdev);
755 return ERR_PTR(rc);
756 }
757
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100758 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
759 do {
760 __raw3270_reset_device(rp);
761 while (!raw3270_state_final(rp)) {
Sebastian Ott188561a2013-04-13 12:53:21 +0200762 ccw_device_wait_idle(rp->cdev);
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100763 barrier();
764 }
765 } while (rp->state != RAW3270_STATE_READY);
766 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 return rp;
768}
769
770void
771raw3270_wait_cons_dev(struct raw3270 *rp)
772{
773 unsigned long flags;
774
775 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
Sebastian Ott188561a2013-04-13 12:53:21 +0200776 ccw_device_wait_idle(rp->cdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
778}
779
780#endif
781
782/*
783 * Create a 3270 device structure.
784 */
785static struct raw3270 *
786raw3270_create_device(struct ccw_device *cdev)
787{
788 struct raw3270 *rp;
789 char *ascebc;
790 int rc;
791
Martin Schwidefskybd1cb5d2014-03-21 15:24:27 +0100792 rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 if (!rp)
794 return ERR_PTR(-ENOMEM);
795 ascebc = kmalloc(256, GFP_KERNEL);
796 if (!ascebc) {
797 kfree(rp);
798 return ERR_PTR(-ENOMEM);
799 }
800 rc = raw3270_setup_device(cdev, rp, ascebc);
801 if (rc) {
802 kfree(rp->ascebc);
803 kfree(rp);
804 rp = ERR_PTR(rc);
805 }
806 /* Get reference to ccw_device structure. */
807 get_device(&cdev->dev);
808 return rp;
809}
810
811/*
812 * Activate a view.
813 */
814int
815raw3270_activate_view(struct raw3270_view *view)
816{
817 struct raw3270 *rp;
818 struct raw3270_view *oldview, *nv;
819 unsigned long flags;
820 int rc;
821
822 rp = view->dev;
823 if (!rp)
824 return -ENODEV;
825 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
826 if (rp->view == view)
827 rc = 0;
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100828 else if (!raw3270_state_ready(rp))
829 rc = -EBUSY;
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200830 else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
831 rc = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 else {
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200833 oldview = NULL;
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100834 if (rp->view && rp->view->fn->deactivate) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 oldview = rp->view;
836 oldview->fn->deactivate(oldview);
837 }
838 rp->view = view;
839 rc = view->fn->activate(view);
840 if (rc) {
841 /* Didn't work. Try to reactivate the old view. */
842 rp->view = oldview;
843 if (!oldview || oldview->fn->activate(oldview) != 0) {
844 /* Didn't work as well. Try any other view. */
845 list_for_each_entry(nv, &rp->view_list, list)
846 if (nv != view && nv != oldview) {
847 rp->view = nv;
848 if (nv->fn->activate(nv) == 0)
849 break;
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200850 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 }
852 }
853 }
854 }
855 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
856 return rc;
857}
858
859/*
860 * Deactivate current view.
861 */
862void
863raw3270_deactivate_view(struct raw3270_view *view)
864{
865 unsigned long flags;
866 struct raw3270 *rp;
867
868 rp = view->dev;
869 if (!rp)
870 return;
871 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
872 if (rp->view == view) {
873 view->fn->deactivate(view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200874 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 /* Move deactivated view to end of list. */
876 list_del_init(&view->list);
877 list_add_tail(&view->list, &rp->view_list);
878 /* Try to activate another view. */
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100879 if (raw3270_state_ready(rp) &&
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200880 !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
Richard Hitted3cb6f2005-10-30 15:00:10 -0800881 list_for_each_entry(view, &rp->view_list, list) {
882 rp->view = view;
883 if (view->fn->activate(view) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884 break;
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200885 rp->view = NULL;
Richard Hitted3cb6f2005-10-30 15:00:10 -0800886 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 }
888 }
889 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
890}
891
892/*
893 * Add view to device with minor "minor".
894 */
895int
896raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
897{
898 unsigned long flags;
899 struct raw3270 *rp;
900 int rc;
901
Richard Hitted3cb6f2005-10-30 15:00:10 -0800902 if (minor <= 0)
903 return -ENODEV;
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800904 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 rc = -ENODEV;
906 list_for_each_entry(rp, &raw3270_devices, list) {
907 if (rp->minor != minor)
908 continue;
909 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100910 atomic_set(&view->ref_count, 2);
911 view->dev = rp;
912 view->fn = fn;
913 view->model = rp->model;
914 view->rows = rp->rows;
915 view->cols = rp->cols;
916 view->ascebc = rp->ascebc;
917 spin_lock_init(&view->lock);
918 list_add(&view->list, &rp->view_list);
919 rc = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
921 break;
922 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800923 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 return rc;
925}
926
927/*
928 * Find specific view of device with minor "minor".
929 */
930struct raw3270_view *
931raw3270_find_view(struct raw3270_fn *fn, int minor)
932{
933 struct raw3270 *rp;
934 struct raw3270_view *view, *tmp;
935 unsigned long flags;
936
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800937 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938 view = ERR_PTR(-ENODEV);
939 list_for_each_entry(rp, &raw3270_devices, list) {
940 if (rp->minor != minor)
941 continue;
942 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100943 list_for_each_entry(tmp, &rp->view_list, list) {
944 if (tmp->fn == fn) {
945 raw3270_get_view(tmp);
946 view = tmp;
947 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 }
949 }
950 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
951 break;
952 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800953 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 return view;
955}
956
957/*
958 * Remove view from device and free view structure via call to view->fn->free.
959 */
960void
961raw3270_del_view(struct raw3270_view *view)
962{
963 unsigned long flags;
964 struct raw3270 *rp;
965 struct raw3270_view *nv;
966
967 rp = view->dev;
968 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
969 if (rp->view == view) {
970 view->fn->deactivate(view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200971 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 }
973 list_del_init(&view->list);
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +0100974 if (!rp->view && raw3270_state_ready(rp) &&
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200975 !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 /* Try to activate another view. */
977 list_for_each_entry(nv, &rp->view_list, list) {
Richard Hitted3cb6f2005-10-30 15:00:10 -0800978 if (nv->fn->activate(nv) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 rp->view = nv;
980 break;
981 }
982 }
983 }
984 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
985 /* Wait for reference counter to drop to zero. */
986 atomic_dec(&view->ref_count);
987 wait_event(raw3270_wait_queue, atomic_read(&view->ref_count) == 0);
988 if (view->fn->free)
989 view->fn->free(view);
990}
991
992/*
993 * Remove a 3270 device structure.
994 */
995static void
996raw3270_delete_device(struct raw3270 *rp)
997{
998 struct ccw_device *cdev;
999
1000 /* Remove from device chain. */
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001001 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 list_del_init(&rp->list);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001003 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005 /* Disconnect from ccw_device. */
1006 cdev = rp->cdev;
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001007 rp->cdev = NULL;
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001008 dev_set_drvdata(&cdev->dev, NULL);
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001009 cdev->handler = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
1011 /* Put ccw_device structure. */
1012 put_device(&cdev->dev);
1013
1014 /* Now free raw3270 structure. */
1015 kfree(rp->ascebc);
1016 kfree(rp);
1017}
1018
1019static int
1020raw3270_probe (struct ccw_device *cdev)
1021{
1022 return 0;
1023}
1024
1025/*
1026 * Additional attributes for a 3270 device
1027 */
1028static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001029raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030{
1031 return snprintf(buf, PAGE_SIZE, "%i\n",
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001032 ((struct raw3270 *) dev_get_drvdata(dev))->model);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001034static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035
1036static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001037raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038{
1039 return snprintf(buf, PAGE_SIZE, "%i\n",
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001040 ((struct raw3270 *) dev_get_drvdata(dev))->rows);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001042static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
1044static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001045raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046{
1047 return snprintf(buf, PAGE_SIZE, "%i\n",
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001048 ((struct raw3270 *) dev_get_drvdata(dev))->cols);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001050static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
1052static struct attribute * raw3270_attrs[] = {
1053 &dev_attr_model.attr,
1054 &dev_attr_rows.attr,
1055 &dev_attr_columns.attr,
1056 NULL,
1057};
1058
1059static struct attribute_group raw3270_attr_group = {
1060 .attrs = raw3270_attrs,
1061};
1062
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001063static int raw3270_create_attributes(struct raw3270 *rp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001065 return sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066}
1067
1068/*
1069 * Notifier for device addition/removal
1070 */
Denis Chengc11ca972008-01-26 14:11:13 +01001071static LIST_HEAD(raw3270_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001073int raw3270_register_notifier(struct raw3270_notifier *notifier)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 struct raw3270 *rp;
1076
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001077 mutex_lock(&raw3270_mutex);
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001078 list_add_tail(&notifier->list, &raw3270_notifier);
1079 list_for_each_entry(rp, &raw3270_devices, list)
1080 notifier->create(rp->minor);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001081 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 return 0;
1083}
1084
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001085void raw3270_unregister_notifier(struct raw3270_notifier *notifier)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086{
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001087 struct raw3270 *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001089 mutex_lock(&raw3270_mutex);
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001090 list_for_each_entry(rp, &raw3270_devices, list)
1091 notifier->destroy(rp->minor);
1092 list_del(&notifier->list);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001093 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094}
1095
1096/*
1097 * Set 3270 device online.
1098 */
1099static int
1100raw3270_set_online (struct ccw_device *cdev)
1101{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 struct raw3270_notifier *np;
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001103 struct raw3270 *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 int rc;
1105
1106 rp = raw3270_create_device(cdev);
1107 if (IS_ERR(rp))
1108 return PTR_ERR(rp);
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001109 rc = raw3270_create_attributes(rp);
1110 if (rc)
1111 goto failure;
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +01001112 raw3270_reset_device(rp);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001113 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 list_for_each_entry(np, &raw3270_notifier, list)
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001115 np->create(rp->minor);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001116 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 return 0;
Richard Hitted3cb6f2005-10-30 15:00:10 -08001118
1119failure:
1120 raw3270_delete_device(rp);
1121 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122}
1123
1124/*
1125 * Remove 3270 device structure.
1126 */
1127static void
1128raw3270_remove (struct ccw_device *cdev)
1129{
1130 unsigned long flags;
1131 struct raw3270 *rp;
1132 struct raw3270_view *v;
1133 struct raw3270_notifier *np;
1134
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001135 rp = dev_get_drvdata(&cdev->dev);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001136 /*
1137 * _remove is the opposite of _probe; it's probe that
1138 * should set up rp. raw3270_remove gets entered for
1139 * devices even if they haven't been varied online.
1140 * Thus, rp may validly be NULL here.
1141 */
1142 if (rp == NULL)
1143 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
1145 sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
1146
1147 /* Deactivate current view and remove all views. */
1148 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1149 if (rp->view) {
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +01001150 if (rp->view->fn->deactivate)
1151 rp->view->fn->deactivate(rp->view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001152 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 }
1154 while (!list_empty(&rp->view_list)) {
1155 v = list_entry(rp->view_list.next, struct raw3270_view, list);
1156 if (v->fn->release)
1157 v->fn->release(v);
1158 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
1159 raw3270_del_view(v);
1160 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1161 }
1162 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
1163
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001164 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 list_for_each_entry(np, &raw3270_notifier, list)
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001166 np->destroy(rp->minor);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001167 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168
1169 /* Reset 3270 device. */
1170 raw3270_reset_device(rp);
1171 /* And finally remove it. */
1172 raw3270_delete_device(rp);
1173}
1174
1175/*
1176 * Set 3270 device offline.
1177 */
1178static int
1179raw3270_set_offline (struct ccw_device *cdev)
1180{
1181 struct raw3270 *rp;
1182
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001183 rp = dev_get_drvdata(&cdev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags))
1185 return -EBUSY;
1186 raw3270_remove(cdev);
1187 return 0;
1188}
1189
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001190static int raw3270_pm_stop(struct ccw_device *cdev)
1191{
1192 struct raw3270 *rp;
1193 struct raw3270_view *view;
1194 unsigned long flags;
1195
Martin Schwidefsky4f0076f2009-06-22 12:08:19 +02001196 rp = dev_get_drvdata(&cdev->dev);
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001197 if (!rp)
1198 return 0;
1199 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +01001200 if (rp->view && rp->view->fn->deactivate)
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001201 rp->view->fn->deactivate(rp->view);
1202 if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) {
1203 /*
1204 * Release tty and fullscreen for all non-console
1205 * devices.
1206 */
1207 list_for_each_entry(view, &rp->view_list, list) {
1208 if (view->fn->release)
1209 view->fn->release(view);
1210 }
1211 }
1212 set_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
1213 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1214 return 0;
1215}
1216
1217static int raw3270_pm_start(struct ccw_device *cdev)
1218{
1219 struct raw3270 *rp;
1220 unsigned long flags;
1221
Martin Schwidefsky4f0076f2009-06-22 12:08:19 +02001222 rp = dev_get_drvdata(&cdev->dev);
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001223 if (!rp)
1224 return 0;
1225 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1226 clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
Martin Schwidefsky4d334fd2013-01-04 14:55:13 +01001227 if (rp->view && rp->view->fn->activate)
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001228 rp->view->fn->activate(rp->view);
1229 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1230 return 0;
1231}
1232
1233void raw3270_pm_unfreeze(struct raw3270_view *view)
1234{
Sebastian Ott34483ca2009-10-06 10:33:56 +02001235#ifdef CONFIG_TN3270_CONSOLE
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001236 struct raw3270 *rp;
1237
1238 rp = view->dev;
1239 if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
Sebastian Ottf10ccca2013-04-13 12:56:51 +02001240 ccw_device_force_console(rp->cdev);
Sebastian Ott34483ca2009-10-06 10:33:56 +02001241#endif
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001242}
1243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244static struct ccw_device_id raw3270_id[] = {
1245 { CCW_DEVICE(0x3270, 0) },
1246 { CCW_DEVICE(0x3271, 0) },
1247 { CCW_DEVICE(0x3272, 0) },
1248 { CCW_DEVICE(0x3273, 0) },
1249 { CCW_DEVICE(0x3274, 0) },
1250 { CCW_DEVICE(0x3275, 0) },
1251 { CCW_DEVICE(0x3276, 0) },
1252 { CCW_DEVICE(0x3277, 0) },
1253 { CCW_DEVICE(0x3278, 0) },
1254 { CCW_DEVICE(0x3279, 0) },
1255 { CCW_DEVICE(0x3174, 0) },
1256 { /* end of list */ },
1257};
1258
1259static struct ccw_driver raw3270_ccw_driver = {
Sebastian Ott3bda0582011-03-23 10:16:02 +01001260 .driver = {
1261 .name = "3270",
1262 .owner = THIS_MODULE,
1263 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 .ids = raw3270_id,
1265 .probe = &raw3270_probe,
1266 .remove = &raw3270_remove,
1267 .set_online = &raw3270_set_online,
1268 .set_offline = &raw3270_set_offline,
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001269 .freeze = &raw3270_pm_stop,
1270 .thaw = &raw3270_pm_start,
1271 .restore = &raw3270_pm_start,
Heiko Carstens420f42e2013-01-02 15:18:18 +01001272 .int_class = IRQIO_C70,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273};
1274
1275static int
1276raw3270_init(void)
1277{
1278 struct raw3270 *rp;
1279 int rc;
1280
1281 if (raw3270_registered)
1282 return 0;
1283 raw3270_registered = 1;
1284 rc = ccw_driver_register(&raw3270_ccw_driver);
1285 if (rc == 0) {
1286 /* Create attributes for early (= console) device. */
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001287 mutex_lock(&raw3270_mutex);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001288 class3270 = class_create(THIS_MODULE, "3270");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 list_for_each_entry(rp, &raw3270_devices, list) {
1290 get_device(&rp->cdev->dev);
1291 raw3270_create_attributes(rp);
1292 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001293 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 }
1295 return rc;
1296}
1297
1298static void
1299raw3270_exit(void)
1300{
1301 ccw_driver_unregister(&raw3270_ccw_driver);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001302 class_destroy(class3270);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303}
1304
1305MODULE_LICENSE("GPL");
1306
1307module_init(raw3270_init);
1308module_exit(raw3270_exit);
1309
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001310EXPORT_SYMBOL(class3270);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311EXPORT_SYMBOL(raw3270_request_alloc);
1312EXPORT_SYMBOL(raw3270_request_free);
1313EXPORT_SYMBOL(raw3270_request_reset);
1314EXPORT_SYMBOL(raw3270_request_set_cmd);
1315EXPORT_SYMBOL(raw3270_request_add_data);
1316EXPORT_SYMBOL(raw3270_request_set_data);
1317EXPORT_SYMBOL(raw3270_request_set_idal);
1318EXPORT_SYMBOL(raw3270_buffer_address);
1319EXPORT_SYMBOL(raw3270_add_view);
1320EXPORT_SYMBOL(raw3270_del_view);
1321EXPORT_SYMBOL(raw3270_find_view);
1322EXPORT_SYMBOL(raw3270_activate_view);
1323EXPORT_SYMBOL(raw3270_deactivate_view);
1324EXPORT_SYMBOL(raw3270_start);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001325EXPORT_SYMBOL(raw3270_start_locked);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326EXPORT_SYMBOL(raw3270_start_irq);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001327EXPORT_SYMBOL(raw3270_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001328EXPORT_SYMBOL(raw3270_register_notifier);
1329EXPORT_SYMBOL(raw3270_unregister_notifier);
1330EXPORT_SYMBOL(raw3270_wait_queue);