blob: 72f69fda9d01a7a25e27c33b7c0031427538c692 [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;
40 unsigned long flags;
41
42 struct list_head req_queue; /* Request queue. */
43 struct list_head view_list; /* List of available views. */
44 struct raw3270_view *view; /* Active view. */
45
46 struct timer_list timer; /* Device timer. */
47
48 unsigned char *ascebc; /* ascii -> ebcdic table */
Martin Schwidefsky132fab12006-06-29 14:57:39 +020049
50 struct raw3270_request init_request;
51 unsigned char init_data[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -070052};
53
54/* raw3270->flags */
55#define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */
56#define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */
57#define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */
58#define RAW3270_FLAGS_READY 4 /* Device is useable by views */
59#define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */
Martin Schwidefsky4b214a02009-06-16 10:30:47 +020060#define RAW3270_FLAGS_FROZEN 16 /* set if 3270 is frozen for suspend */
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62/* Semaphore to protect global data of raw3270 (devices, views, etc). */
Ingo Molnar14cc3e22006-03-26 01:37:14 -080063static DEFINE_MUTEX(raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65/* List of 3270 devices. */
Denis Chengc11ca972008-01-26 14:11:13 +010066static LIST_HEAD(raw3270_devices);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68/*
69 * Flag to indicate if the driver has been registered. Some operations
70 * like waiting for the end of i/o need to be done differently as long
71 * as the kernel is still starting up (console support).
72 */
73static int raw3270_registered;
74
75/* Module parameters */
Rusty Russell90ab5ee2012-01-13 09:32:20 +103076static bool tubxcorrect = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077module_param(tubxcorrect, bool, 0);
78
79/*
80 * Wait queue for device init/delete, view delete.
81 */
82DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
83
84/*
85 * Encode array for 12 bit 3270 addresses.
86 */
Heiko Carstens2b67fc42007-02-05 21:16:47 +010087static unsigned char raw3270_ebcgraf[64] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
89 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
90 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
91 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
92 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
93 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
94 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
95 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
96};
97
98void
99raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
100{
101 if (test_bit(RAW3270_FLAGS_14BITADDR, &rp->flags)) {
102 cp[0] = (addr >> 8) & 0x3f;
103 cp[1] = addr & 0xff;
104 } else {
105 cp[0] = raw3270_ebcgraf[(addr >> 6) & 0x3f];
106 cp[1] = raw3270_ebcgraf[addr & 0x3f];
107 }
108}
109
110/*
111 * Allocate a new 3270 ccw request
112 */
113struct raw3270_request *
114raw3270_request_alloc(size_t size)
115{
116 struct raw3270_request *rq;
117
118 /* Allocate request structure */
Eric Sesterhenn88abaab2006-03-24 03:15:31 -0800119 rq = kzalloc(sizeof(struct raw3270_request), GFP_KERNEL | GFP_DMA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 if (!rq)
121 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122
123 /* alloc output buffer. */
124 if (size > 0) {
125 rq->buffer = kmalloc(size, GFP_KERNEL | GFP_DMA);
126 if (!rq->buffer) {
127 kfree(rq);
128 return ERR_PTR(-ENOMEM);
129 }
130 }
131 rq->size = size;
132 INIT_LIST_HEAD(&rq->list);
133
134 /*
135 * Setup ccw.
136 */
137 rq->ccw.cda = __pa(rq->buffer);
138 rq->ccw.flags = CCW_FLAG_SLI;
139
140 return rq;
141}
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143/*
144 * Free 3270 ccw request
145 */
146void
147raw3270_request_free (struct raw3270_request *rq)
148{
Jesper Juhl17fd6822005-11-07 01:01:30 -0800149 kfree(rq->buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 kfree(rq);
151}
152
153/*
154 * Reset request to initial state.
155 */
156void
157raw3270_request_reset(struct raw3270_request *rq)
158{
159 BUG_ON(!list_empty(&rq->list));
160 rq->ccw.cmd_code = 0;
161 rq->ccw.count = 0;
162 rq->ccw.cda = __pa(rq->buffer);
163 rq->ccw.flags = CCW_FLAG_SLI;
164 rq->rescnt = 0;
165 rq->rc = 0;
166}
167
168/*
169 * Set command code to ccw of a request.
170 */
171void
172raw3270_request_set_cmd(struct raw3270_request *rq, u8 cmd)
173{
174 rq->ccw.cmd_code = cmd;
175}
176
177/*
178 * Add data fragment to output buffer.
179 */
180int
181raw3270_request_add_data(struct raw3270_request *rq, void *data, size_t size)
182{
183 if (size + rq->ccw.count > rq->size)
184 return -E2BIG;
185 memcpy(rq->buffer + rq->ccw.count, data, size);
186 rq->ccw.count += size;
187 return 0;
188}
189
190/*
191 * Set address/length pair to ccw of a request.
192 */
193void
194raw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size)
195{
196 rq->ccw.cda = __pa(data);
197 rq->ccw.count = size;
198}
199
200/*
201 * Set idal buffer to ccw of a request.
202 */
203void
204raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
205{
206 rq->ccw.cda = __pa(ib->data);
207 rq->ccw.count = ib->size;
208 rq->ccw.flags |= CCW_FLAG_IDA;
209}
210
211/*
212 * Stop running ccw.
213 */
214static int
215raw3270_halt_io_nolock(struct raw3270 *rp, struct raw3270_request *rq)
216{
217 int retries;
218 int rc;
219
220 if (raw3270_request_final(rq))
221 return 0;
222 /* Check if interrupt has already been processed */
223 for (retries = 0; retries < 5; retries++) {
224 if (retries < 2)
225 rc = ccw_device_halt(rp->cdev, (long) rq);
226 else
227 rc = ccw_device_clear(rp->cdev, (long) rq);
228 if (rc == 0)
229 break; /* termination successful */
230 }
231 return rc;
232}
233
234static int
235raw3270_halt_io(struct raw3270 *rp, struct raw3270_request *rq)
236{
237 unsigned long flags;
238 int rc;
239
240 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
241 rc = raw3270_halt_io_nolock(rp, rq);
242 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
243 return rc;
244}
245
246/*
247 * Add the request to the request queue, try to start it if the
248 * 3270 device is idle. Return without waiting for end of i/o.
249 */
250static int
251__raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
252 struct raw3270_request *rq)
253{
254 rq->view = view;
255 raw3270_get_view(view);
256 if (list_empty(&rp->req_queue) &&
257 !test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {
258 /* No other requests are on the queue. Start this one. */
259 rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
260 (unsigned long) rq, 0, 0);
261 if (rq->rc) {
262 raw3270_put_view(view);
263 return rq->rc;
264 }
265 }
266 list_add_tail(&rq->list, &rp->req_queue);
267 return 0;
268}
269
270int
271raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
272{
273 unsigned long flags;
274 struct raw3270 *rp;
275 int rc;
276
277 spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
278 rp = view->dev;
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200279 if (!rp || rp->view != view ||
280 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 rc = -EACCES;
282 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
283 rc = -ENODEV;
284 else
285 rc = __raw3270_start(rp, view, rq);
286 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
287 return rc;
288}
289
290int
Richard Hitted3cb6f2005-10-30 15:00:10 -0800291raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
292{
293 struct raw3270 *rp;
294 int rc;
295
296 rp = view->dev;
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200297 if (!rp || rp->view != view ||
298 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
Richard Hitted3cb6f2005-10-30 15:00:10 -0800299 rc = -EACCES;
300 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
301 rc = -ENODEV;
302 else
303 rc = __raw3270_start(rp, view, rq);
304 return rc;
305}
306
307int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq)
309{
310 struct raw3270 *rp;
311
312 rp = view->dev;
313 rq->view = view;
314 raw3270_get_view(view);
315 list_add_tail(&rq->list, &rp->req_queue);
316 return 0;
317}
318
319/*
320 * 3270 interrupt routine, called from the ccw_device layer
321 */
322static void
323raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
324{
325 struct raw3270 *rp;
326 struct raw3270_view *view;
327 struct raw3270_request *rq;
328 int rc;
329
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -0700330 rp = dev_get_drvdata(&cdev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 if (!rp)
332 return;
333 rq = (struct raw3270_request *) intparm;
334 view = rq ? rq->view : rp->view;
335
336 if (IS_ERR(irb))
337 rc = RAW3270_IO_RETRY;
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200338 else if (irb->scsw.cmd.fctl & SCSW_FCTL_HALT_FUNC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 rq->rc = -EIO;
340 rc = RAW3270_IO_DONE;
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200341 } else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END |
342 DEV_STAT_UNIT_EXCEP)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 /* Handle CE-DE-UE and subsequent UDE */
344 set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
345 rc = RAW3270_IO_BUSY;
346 } else if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {
347 /* Wait for UDE if busy flag is set. */
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200348 if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 clear_bit(RAW3270_FLAGS_BUSY, &rp->flags);
350 /* Got it, now retry. */
351 rc = RAW3270_IO_RETRY;
352 } else
353 rc = RAW3270_IO_BUSY;
354 } else if (view)
355 rc = view->fn->intv(view, rq, irb);
356 else
357 rc = RAW3270_IO_DONE;
358
359 switch (rc) {
360 case RAW3270_IO_DONE:
361 break;
362 case RAW3270_IO_BUSY:
363 /*
364 * Intervention required by the operator. We have to wait
365 * for unsolicited device end.
366 */
367 return;
368 case RAW3270_IO_RETRY:
369 if (!rq)
370 break;
371 rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
372 (unsigned long) rq, 0, 0);
373 if (rq->rc == 0)
Daniel Mack3ad2f3f2010-02-03 08:01:28 +0800374 return; /* Successfully restarted. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 break;
376 case RAW3270_IO_STOP:
377 if (!rq)
378 break;
379 raw3270_halt_io_nolock(rp, rq);
380 rq->rc = -EIO;
381 break;
382 default:
383 BUG();
384 }
385 if (rq) {
386 BUG_ON(list_empty(&rq->list));
387 /* The request completed, remove from queue and do callback. */
388 list_del_init(&rq->list);
389 if (rq->callback)
390 rq->callback(rq, rq->callback_data);
391 /* Do put_device for get_device in raw3270_start. */
392 raw3270_put_view(view);
393 }
394 /*
395 * Try to start each request on request queue until one is
396 * started successful.
397 */
398 while (!list_empty(&rp->req_queue)) {
399 rq = list_entry(rp->req_queue.next,struct raw3270_request,list);
400 rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
401 (unsigned long) rq, 0, 0);
402 if (rq->rc == 0)
403 break;
404 /* Start failed. Remove request and do callback. */
405 list_del_init(&rq->list);
406 if (rq->callback)
407 rq->callback(rq, rq->callback_data);
408 /* Do put_device for get_device in raw3270_start. */
409 raw3270_put_view(view);
410 }
411}
412
413/*
414 * Size sensing.
415 */
416
417struct raw3270_ua { /* Query Reply structure for Usable Area */
418 struct { /* Usable Area Query Reply Base */
419 short l; /* Length of this structured field */
420 char sfid; /* 0x81 if Query Reply */
421 char qcode; /* 0x81 if Usable Area */
422 char flags0;
423 char flags1;
424 short w; /* Width of usable area */
425 short h; /* Heigth of usavle area */
426 char units; /* 0x00:in; 0x01:mm */
427 int xr;
428 int yr;
429 char aw;
430 char ah;
431 short buffsz; /* Character buffer size, bytes */
432 char xmin;
433 char ymin;
434 char xmax;
435 char ymax;
436 } __attribute__ ((packed)) uab;
437 struct { /* Alternate Usable Area Self-Defining Parameter */
438 char l; /* Length of this Self-Defining Parm */
439 char sdpid; /* 0x02 if Alternate Usable Area */
440 char res;
441 char auaid; /* 0x01 is Id for the A U A */
442 short wauai; /* Width of AUAi */
443 short hauai; /* Height of AUAi */
444 char auaunits; /* 0x00:in, 0x01:mm */
445 int auaxr;
446 int auayr;
447 char awauai;
448 char ahauai;
449 } __attribute__ ((packed)) aua;
450} __attribute__ ((packed));
451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452static struct diag210 raw3270_init_diag210;
Christoph Hellwigd330f932007-05-31 17:38:04 +0200453static DEFINE_MUTEX(raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455static int
456raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
457 struct irb *irb)
458{
459 /*
460 * Unit-Check Processing:
461 * Expect Command Reject or Intervention Required.
462 */
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200463 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 /* Request finished abnormally. */
465 if (irb->ecw[0] & SNS0_INTERVENTION_REQ) {
466 set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags);
467 return RAW3270_IO_BUSY;
468 }
469 }
470 if (rq) {
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200471 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 if (irb->ecw[0] & SNS0_CMD_REJECT)
473 rq->rc = -EOPNOTSUPP;
474 else
475 rq->rc = -EIO;
476 } else
477 /* Request finished normally. Copy residual count. */
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200478 rq->rescnt = irb->scsw.cmd.count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 }
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200480 if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 set_bit(RAW3270_FLAGS_ATTN, &view->dev->flags);
482 wake_up(&raw3270_wait_queue);
483 }
484 return RAW3270_IO_DONE;
485}
486
487static struct raw3270_fn raw3270_init_fn = {
488 .intv = raw3270_init_irq
489};
490
491static struct raw3270_view raw3270_init_view = {
492 .fn = &raw3270_init_fn
493};
494
495/*
496 * raw3270_wait/raw3270_wait_interruptible/__raw3270_wakeup
497 * Wait for end of request. The request must have been started
498 * with raw3270_start, rc = 0. The device lock may NOT have been
499 * released between calling raw3270_start and raw3270_wait.
500 */
501static void
502raw3270_wake_init(struct raw3270_request *rq, void *data)
503{
504 wake_up((wait_queue_head_t *) data);
505}
506
507/*
508 * Special wait function that can cope with console initialization.
509 */
510static int
511raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view,
512 struct raw3270_request *rq)
513{
514 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 int rc;
516
517#ifdef CONFIG_TN3270_CONSOLE
518 if (raw3270_registered == 0) {
519 spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200520 rq->callback = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 rc = __raw3270_start(rp, view, rq);
522 if (rc == 0)
523 while (!raw3270_request_final(rq)) {
524 wait_cons_dev();
525 barrier();
526 }
527 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
528 return rq->rc;
529 }
530#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 rq->callback = raw3270_wake_init;
Martin Schwidefsky54ad6412008-05-30 10:03:32 +0200532 rq->callback_data = &raw3270_wait_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
534 rc = __raw3270_start(rp, view, rq);
535 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
536 if (rc)
537 return rc;
538 /* Now wait for the completion. */
Martin Schwidefsky54ad6412008-05-30 10:03:32 +0200539 rc = wait_event_interruptible(raw3270_wait_queue,
540 raw3270_request_final(rq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 if (rc == -ERESTARTSYS) { /* Interrupted by a signal. */
542 raw3270_halt_io(view->dev, rq);
543 /* No wait for the halt to complete. */
Martin Schwidefsky54ad6412008-05-30 10:03:32 +0200544 wait_event(raw3270_wait_queue, raw3270_request_final(rq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 return -ERESTARTSYS;
546 }
547 return rq->rc;
548}
549
550static int
551__raw3270_size_device_vm(struct raw3270 *rp)
552{
553 int rc, model;
Cornelia Huck9a92fe42007-05-10 15:45:42 +0200554 struct ccw_dev_id dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Cornelia Huck9a92fe42007-05-10 15:45:42 +0200556 ccw_device_get_id(rp->cdev, &dev_id);
557 raw3270_init_diag210.vrdcdvno = dev_id.devno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 raw3270_init_diag210.vrdclen = sizeof(struct diag210);
559 rc = diag210(&raw3270_init_diag210);
560 if (rc)
561 return rc;
562 model = raw3270_init_diag210.vrdccrmd;
563 switch (model) {
564 case 2:
565 rp->model = model;
566 rp->rows = 24;
567 rp->cols = 80;
568 break;
569 case 3:
570 rp->model = model;
571 rp->rows = 32;
572 rp->cols = 80;
573 break;
574 case 4:
575 rp->model = model;
576 rp->rows = 43;
577 rp->cols = 80;
578 break;
579 case 5:
580 rp->model = model;
581 rp->rows = 27;
582 rp->cols = 132;
583 break;
584 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 rc = -EOPNOTSUPP;
586 break;
587 }
588 return rc;
589}
590
591static int
592__raw3270_size_device(struct raw3270 *rp)
593{
594 static const unsigned char wbuf[] =
595 { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
596 struct raw3270_ua *uap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 int rc;
598
599 /*
600 * To determine the size of the 3270 device we need to do:
601 * 1) send a 'read partition' data stream to the device
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300602 * 2) wait for the attn interrupt that precedes the query reply
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 * 3) do a read modified to get the query reply
604 * To make things worse we have to cope with intervention
605 * required (3270 device switched to 'stand-by') and command
606 * rejects (old devices that can't do 'read partition').
607 */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200608 memset(&rp->init_request, 0, sizeof(rp->init_request));
609 memset(&rp->init_data, 0, 256);
610 /* Store 'read partition' data stream to init_data */
611 memcpy(&rp->init_data, wbuf, sizeof(wbuf));
612 INIT_LIST_HEAD(&rp->init_request.list);
613 rp->init_request.ccw.cmd_code = TC_WRITESF;
614 rp->init_request.ccw.flags = CCW_FLAG_SLI;
615 rp->init_request.ccw.count = sizeof(wbuf);
616 rp->init_request.ccw.cda = (__u32) __pa(&rp->init_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200618 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
Martin Schwidefsky3863e722005-09-03 15:58:06 -0700619 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620 /* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622
623 /* Wait for attention interrupt. */
624#ifdef CONFIG_TN3270_CONSOLE
625 if (raw3270_registered == 0) {
626 unsigned long flags;
627
628 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
629 while (!test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags))
630 wait_cons_dev();
631 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
632 } else
633#endif
634 rc = wait_event_interruptible(raw3270_wait_queue,
635 test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags));
636 if (rc)
637 return rc;
638
639 /*
640 * The device accepted the 'read partition' command. Now
641 * set up a read ccw and issue it.
642 */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200643 rp->init_request.ccw.cmd_code = TC_READMOD;
644 rp->init_request.ccw.flags = CCW_FLAG_SLI;
645 rp->init_request.ccw.count = sizeof(rp->init_data);
646 rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
647 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 if (rc)
649 return rc;
650 /* Got a Query Reply */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200651 uap = (struct raw3270_ua *) (rp->init_data + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 /* Paranoia check. */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200653 if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 return -EOPNOTSUPP;
655 /* Copy rows/columns of default Usable Area */
656 rp->rows = uap->uab.h;
657 rp->cols = uap->uab.w;
658 /* Check for 14 bit addressing */
659 if ((uap->uab.flags0 & 0x0d) == 0x01)
660 set_bit(RAW3270_FLAGS_14BITADDR, &rp->flags);
661 /* Check for Alternate Usable Area */
662 if (uap->uab.l == sizeof(struct raw3270_ua) &&
663 uap->aua.sdpid == 0x02) {
664 rp->rows = uap->aua.hauai;
665 rp->cols = uap->aua.wauai;
666 }
667 return 0;
668}
669
670static int
671raw3270_size_device(struct raw3270 *rp)
672{
673 int rc;
674
Christoph Hellwigd330f932007-05-31 17:38:04 +0200675 mutex_lock(&raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 rp->view = &raw3270_init_view;
677 raw3270_init_view.dev = rp;
Martin Schwidefsky3863e722005-09-03 15:58:06 -0700678 if (MACHINE_IS_VM)
679 rc = __raw3270_size_device_vm(rp);
680 else
681 rc = __raw3270_size_device(rp);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200682 raw3270_init_view.dev = NULL;
683 rp->view = NULL;
Christoph Hellwigd330f932007-05-31 17:38:04 +0200684 mutex_unlock(&raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (rc == 0) { /* Found something. */
686 /* Try to find a model. */
687 rp->model = 0;
688 if (rp->rows == 24 && rp->cols == 80)
689 rp->model = 2;
690 if (rp->rows == 32 && rp->cols == 80)
691 rp->model = 3;
692 if (rp->rows == 43 && rp->cols == 80)
693 rp->model = 4;
694 if (rp->rows == 27 && rp->cols == 132)
695 rp->model = 5;
Martin Schwidefsky3863e722005-09-03 15:58:06 -0700696 } else {
697 /* Couldn't detect size. Use default model 2. */
698 rp->model = 2;
699 rp->rows = 24;
700 rp->cols = 80;
701 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 }
703 return rc;
704}
705
706static int
707raw3270_reset_device(struct raw3270 *rp)
708{
709 int rc;
710
Christoph Hellwigd330f932007-05-31 17:38:04 +0200711 mutex_lock(&raw3270_init_mutex);
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200712 memset(&rp->init_request, 0, sizeof(rp->init_request));
713 memset(&rp->init_data, 0, sizeof(rp->init_data));
714 /* Store reset data stream to init_data/init_request */
715 rp->init_data[0] = TW_KR;
716 INIT_LIST_HEAD(&rp->init_request.list);
717 rp->init_request.ccw.cmd_code = TC_EWRITEA;
718 rp->init_request.ccw.flags = CCW_FLAG_SLI;
719 rp->init_request.ccw.count = 1;
720 rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 rp->view = &raw3270_init_view;
722 raw3270_init_view.dev = rp;
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200723 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200724 raw3270_init_view.dev = NULL;
725 rp->view = NULL;
Christoph Hellwigd330f932007-05-31 17:38:04 +0200726 mutex_unlock(&raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 return rc;
728}
729
Richard Hitted3cb6f2005-10-30 15:00:10 -0800730int
731raw3270_reset(struct raw3270_view *view)
732{
733 struct raw3270 *rp;
734 int rc;
735
736 rp = view->dev;
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200737 if (!rp || rp->view != view ||
738 test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
Richard Hitted3cb6f2005-10-30 15:00:10 -0800739 rc = -EACCES;
740 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
741 rc = -ENODEV;
742 else
743 rc = raw3270_reset_device(view->dev);
744 return rc;
745}
746
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747/*
748 * Setup new 3270 device.
749 */
750static int
751raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
752{
753 struct list_head *l;
754 struct raw3270 *tmp;
755 int minor;
756
757 memset(rp, 0, sizeof(struct raw3270));
758 /* Copy ebcdic -> ascii translation table. */
759 memcpy(ascebc, _ascebc, 256);
760 if (tubxcorrect) {
761 /* correct brackets and circumflex */
762 ascebc['['] = 0xad;
763 ascebc[']'] = 0xbd;
764 ascebc['^'] = 0xb0;
765 }
766 rp->ascebc = ascebc;
767
768 /* Set defaults. */
769 rp->rows = 24;
770 rp->cols = 80;
771
772 INIT_LIST_HEAD(&rp->req_queue);
773 INIT_LIST_HEAD(&rp->view_list);
774
775 /*
776 * Add device to list and find the smallest unused minor
Richard Hitted3cb6f2005-10-30 15:00:10 -0800777 * number for it. Note: there is no device with minor 0,
778 * see special case for fs3270.c:fs3270_open().
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 */
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800780 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 /* Keep the list sorted. */
Richard Hitted3cb6f2005-10-30 15:00:10 -0800782 minor = RAW3270_FIRSTMINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 rp->minor = -1;
784 list_for_each(l, &raw3270_devices) {
785 tmp = list_entry(l, struct raw3270, list);
786 if (tmp->minor > minor) {
787 rp->minor = minor;
788 __list_add(&rp->list, l->prev, l);
789 break;
790 }
791 minor++;
792 }
Richard Hitted3cb6f2005-10-30 15:00:10 -0800793 if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794 rp->minor = minor;
795 list_add_tail(&rp->list, &raw3270_devices);
796 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800797 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 /* No free minor number? Then give up. */
799 if (rp->minor == -1)
800 return -EUSERS;
801 rp->cdev = cdev;
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -0700802 dev_set_drvdata(&cdev->dev, rp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 cdev->handler = raw3270_irq;
804 return 0;
805}
806
807#ifdef CONFIG_TN3270_CONSOLE
808/*
809 * Setup 3270 device configured as console.
810 */
Heiko Carstense62133b2007-07-27 12:29:13 +0200811struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
813 struct raw3270 *rp;
814 char *ascebc;
815 int rc;
816
Heiko Carstens33403dc2009-06-22 12:08:05 +0200817 rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
818 ascebc = kzalloc(256, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 rc = raw3270_setup_device(cdev, rp, ascebc);
820 if (rc)
821 return ERR_PTR(rc);
822 set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
823 rc = raw3270_reset_device(rp);
824 if (rc)
825 return ERR_PTR(rc);
826 rc = raw3270_size_device(rp);
827 if (rc)
828 return ERR_PTR(rc);
829 rc = raw3270_reset_device(rp);
830 if (rc)
831 return ERR_PTR(rc);
832 set_bit(RAW3270_FLAGS_READY, &rp->flags);
833 return rp;
834}
835
836void
837raw3270_wait_cons_dev(struct raw3270 *rp)
838{
839 unsigned long flags;
840
841 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
842 wait_cons_dev();
843 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
844}
845
846#endif
847
848/*
849 * Create a 3270 device structure.
850 */
851static struct raw3270 *
852raw3270_create_device(struct ccw_device *cdev)
853{
854 struct raw3270 *rp;
855 char *ascebc;
856 int rc;
857
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200858 rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 if (!rp)
860 return ERR_PTR(-ENOMEM);
861 ascebc = kmalloc(256, GFP_KERNEL);
862 if (!ascebc) {
863 kfree(rp);
864 return ERR_PTR(-ENOMEM);
865 }
866 rc = raw3270_setup_device(cdev, rp, ascebc);
867 if (rc) {
868 kfree(rp->ascebc);
869 kfree(rp);
870 rp = ERR_PTR(rc);
871 }
872 /* Get reference to ccw_device structure. */
873 get_device(&cdev->dev);
874 return rp;
875}
876
877/*
878 * Activate a view.
879 */
880int
881raw3270_activate_view(struct raw3270_view *view)
882{
883 struct raw3270 *rp;
884 struct raw3270_view *oldview, *nv;
885 unsigned long flags;
886 int rc;
887
888 rp = view->dev;
889 if (!rp)
890 return -ENODEV;
891 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
892 if (rp->view == view)
893 rc = 0;
894 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
895 rc = -ENODEV;
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200896 else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
897 rc = -EACCES;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898 else {
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200899 oldview = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 if (rp->view) {
901 oldview = rp->view;
902 oldview->fn->deactivate(oldview);
903 }
904 rp->view = view;
905 rc = view->fn->activate(view);
906 if (rc) {
907 /* Didn't work. Try to reactivate the old view. */
908 rp->view = oldview;
909 if (!oldview || oldview->fn->activate(oldview) != 0) {
910 /* Didn't work as well. Try any other view. */
911 list_for_each_entry(nv, &rp->view_list, list)
912 if (nv != view && nv != oldview) {
913 rp->view = nv;
914 if (nv->fn->activate(nv) == 0)
915 break;
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200916 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 }
918 }
919 }
920 }
921 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
922 return rc;
923}
924
925/*
926 * Deactivate current view.
927 */
928void
929raw3270_deactivate_view(struct raw3270_view *view)
930{
931 unsigned long flags;
932 struct raw3270 *rp;
933
934 rp = view->dev;
935 if (!rp)
936 return;
937 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
938 if (rp->view == view) {
939 view->fn->deactivate(view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200940 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 /* Move deactivated view to end of list. */
942 list_del_init(&view->list);
943 list_add_tail(&view->list, &rp->view_list);
944 /* Try to activate another view. */
Martin Schwidefsky4b214a02009-06-16 10:30:47 +0200945 if (test_bit(RAW3270_FLAGS_READY, &rp->flags) &&
946 !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
Richard Hitted3cb6f2005-10-30 15:00:10 -0800947 list_for_each_entry(view, &rp->view_list, list) {
948 rp->view = view;
949 if (view->fn->activate(view) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 break;
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200951 rp->view = NULL;
Richard Hitted3cb6f2005-10-30 15:00:10 -0800952 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 }
954 }
955 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
956}
957
958/*
959 * Add view to device with minor "minor".
960 */
961int
962raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
963{
964 unsigned long flags;
965 struct raw3270 *rp;
966 int rc;
967
Richard Hitted3cb6f2005-10-30 15:00:10 -0800968 if (minor <= 0)
969 return -ENODEV;
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800970 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971 rc = -ENODEV;
972 list_for_each_entry(rp, &raw3270_devices, list) {
973 if (rp->minor != minor)
974 continue;
975 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
976 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
977 atomic_set(&view->ref_count, 2);
978 view->dev = rp;
979 view->fn = fn;
980 view->model = rp->model;
981 view->rows = rp->rows;
982 view->cols = rp->cols;
983 view->ascebc = rp->ascebc;
984 spin_lock_init(&view->lock);
Richard Hitted3cb6f2005-10-30 15:00:10 -0800985 list_add(&view->list, &rp->view_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 rc = 0;
987 }
988 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
989 break;
990 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800991 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 return rc;
993}
994
995/*
996 * Find specific view of device with minor "minor".
997 */
998struct raw3270_view *
999raw3270_find_view(struct raw3270_fn *fn, int minor)
1000{
1001 struct raw3270 *rp;
1002 struct raw3270_view *view, *tmp;
1003 unsigned long flags;
1004
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001005 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 view = ERR_PTR(-ENODEV);
1007 list_for_each_entry(rp, &raw3270_devices, list) {
1008 if (rp->minor != minor)
1009 continue;
1010 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1011 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
1012 view = ERR_PTR(-ENOENT);
1013 list_for_each_entry(tmp, &rp->view_list, list) {
1014 if (tmp->fn == fn) {
1015 raw3270_get_view(tmp);
1016 view = tmp;
1017 break;
1018 }
1019 }
1020 }
1021 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1022 break;
1023 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001024 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return view;
1026}
1027
1028/*
1029 * Remove view from device and free view structure via call to view->fn->free.
1030 */
1031void
1032raw3270_del_view(struct raw3270_view *view)
1033{
1034 unsigned long flags;
1035 struct raw3270 *rp;
1036 struct raw3270_view *nv;
1037
1038 rp = view->dev;
1039 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1040 if (rp->view == view) {
1041 view->fn->deactivate(view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001042 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 }
1044 list_del_init(&view->list);
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001045 if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags) &&
1046 !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 /* Try to activate another view. */
1048 list_for_each_entry(nv, &rp->view_list, list) {
Richard Hitted3cb6f2005-10-30 15:00:10 -08001049 if (nv->fn->activate(nv) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 rp->view = nv;
1051 break;
1052 }
1053 }
1054 }
1055 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1056 /* Wait for reference counter to drop to zero. */
1057 atomic_dec(&view->ref_count);
1058 wait_event(raw3270_wait_queue, atomic_read(&view->ref_count) == 0);
1059 if (view->fn->free)
1060 view->fn->free(view);
1061}
1062
1063/*
1064 * Remove a 3270 device structure.
1065 */
1066static void
1067raw3270_delete_device(struct raw3270 *rp)
1068{
1069 struct ccw_device *cdev;
1070
1071 /* Remove from device chain. */
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001072 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 list_del_init(&rp->list);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001074 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075
1076 /* Disconnect from ccw_device. */
1077 cdev = rp->cdev;
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001078 rp->cdev = NULL;
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001079 dev_set_drvdata(&cdev->dev, NULL);
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001080 cdev->handler = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
1082 /* Put ccw_device structure. */
1083 put_device(&cdev->dev);
1084
1085 /* Now free raw3270 structure. */
1086 kfree(rp->ascebc);
1087 kfree(rp);
1088}
1089
1090static int
1091raw3270_probe (struct ccw_device *cdev)
1092{
1093 return 0;
1094}
1095
1096/*
1097 * Additional attributes for a 3270 device
1098 */
1099static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001100raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101{
1102 return snprintf(buf, PAGE_SIZE, "%i\n",
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001103 ((struct raw3270 *) dev_get_drvdata(dev))->model);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001105static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
1107static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001108raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109{
1110 return snprintf(buf, PAGE_SIZE, "%i\n",
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001111 ((struct raw3270 *) dev_get_drvdata(dev))->rows);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001113static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
1115static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001116raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117{
1118 return snprintf(buf, PAGE_SIZE, "%i\n",
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001119 ((struct raw3270 *) dev_get_drvdata(dev))->cols);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001121static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
1123static struct attribute * raw3270_attrs[] = {
1124 &dev_attr_model.attr,
1125 &dev_attr_rows.attr,
1126 &dev_attr_columns.attr,
1127 NULL,
1128};
1129
1130static struct attribute_group raw3270_attr_group = {
1131 .attrs = raw3270_attrs,
1132};
1133
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001134static int raw3270_create_attributes(struct raw3270 *rp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135{
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001136 return sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137}
1138
1139/*
1140 * Notifier for device addition/removal
1141 */
Denis Chengc11ca972008-01-26 14:11:13 +01001142static LIST_HEAD(raw3270_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001144int raw3270_register_notifier(struct raw3270_notifier *notifier)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146 struct raw3270 *rp;
1147
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001148 mutex_lock(&raw3270_mutex);
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001149 list_add_tail(&notifier->list, &raw3270_notifier);
1150 list_for_each_entry(rp, &raw3270_devices, list)
1151 notifier->create(rp->minor);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001152 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 return 0;
1154}
1155
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001156void raw3270_unregister_notifier(struct raw3270_notifier *notifier)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157{
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001158 struct raw3270 *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001160 mutex_lock(&raw3270_mutex);
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001161 list_for_each_entry(rp, &raw3270_devices, list)
1162 notifier->destroy(rp->minor);
1163 list_del(&notifier->list);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001164 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165}
1166
1167/*
1168 * Set 3270 device online.
1169 */
1170static int
1171raw3270_set_online (struct ccw_device *cdev)
1172{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 struct raw3270_notifier *np;
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001174 struct raw3270 *rp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 int rc;
1176
1177 rp = raw3270_create_device(cdev);
1178 if (IS_ERR(rp))
1179 return PTR_ERR(rp);
1180 rc = raw3270_reset_device(rp);
1181 if (rc)
Richard Hitted3cb6f2005-10-30 15:00:10 -08001182 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 rc = raw3270_size_device(rp);
1184 if (rc)
Richard Hitted3cb6f2005-10-30 15:00:10 -08001185 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 rc = raw3270_reset_device(rp);
1187 if (rc)
Richard Hitted3cb6f2005-10-30 15:00:10 -08001188 goto failure;
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001189 rc = raw3270_create_attributes(rp);
1190 if (rc)
1191 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 set_bit(RAW3270_FLAGS_READY, &rp->flags);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001193 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 list_for_each_entry(np, &raw3270_notifier, list)
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001195 np->create(rp->minor);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001196 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 return 0;
Richard Hitted3cb6f2005-10-30 15:00:10 -08001198
1199failure:
1200 raw3270_delete_device(rp);
1201 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202}
1203
1204/*
1205 * Remove 3270 device structure.
1206 */
1207static void
1208raw3270_remove (struct ccw_device *cdev)
1209{
1210 unsigned long flags;
1211 struct raw3270 *rp;
1212 struct raw3270_view *v;
1213 struct raw3270_notifier *np;
1214
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001215 rp = dev_get_drvdata(&cdev->dev);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001216 /*
1217 * _remove is the opposite of _probe; it's probe that
1218 * should set up rp. raw3270_remove gets entered for
1219 * devices even if they haven't been varied online.
1220 * Thus, rp may validly be NULL here.
1221 */
1222 if (rp == NULL)
1223 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 clear_bit(RAW3270_FLAGS_READY, &rp->flags);
1225
1226 sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
1227
1228 /* Deactivate current view and remove all views. */
1229 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1230 if (rp->view) {
1231 rp->view->fn->deactivate(rp->view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001232 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 }
1234 while (!list_empty(&rp->view_list)) {
1235 v = list_entry(rp->view_list.next, struct raw3270_view, list);
1236 if (v->fn->release)
1237 v->fn->release(v);
1238 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
1239 raw3270_del_view(v);
1240 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1241 }
1242 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
1243
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001244 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 list_for_each_entry(np, &raw3270_notifier, list)
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001246 np->destroy(rp->minor);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001247 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249 /* Reset 3270 device. */
1250 raw3270_reset_device(rp);
1251 /* And finally remove it. */
1252 raw3270_delete_device(rp);
1253}
1254
1255/*
1256 * Set 3270 device offline.
1257 */
1258static int
1259raw3270_set_offline (struct ccw_device *cdev)
1260{
1261 struct raw3270 *rp;
1262
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001263 rp = dev_get_drvdata(&cdev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags))
1265 return -EBUSY;
1266 raw3270_remove(cdev);
1267 return 0;
1268}
1269
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001270static int raw3270_pm_stop(struct ccw_device *cdev)
1271{
1272 struct raw3270 *rp;
1273 struct raw3270_view *view;
1274 unsigned long flags;
1275
Martin Schwidefsky4f0076f2009-06-22 12:08:19 +02001276 rp = dev_get_drvdata(&cdev->dev);
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001277 if (!rp)
1278 return 0;
1279 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1280 if (rp->view)
1281 rp->view->fn->deactivate(rp->view);
1282 if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) {
1283 /*
1284 * Release tty and fullscreen for all non-console
1285 * devices.
1286 */
1287 list_for_each_entry(view, &rp->view_list, list) {
1288 if (view->fn->release)
1289 view->fn->release(view);
1290 }
1291 }
1292 set_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
1293 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1294 return 0;
1295}
1296
1297static int raw3270_pm_start(struct ccw_device *cdev)
1298{
1299 struct raw3270 *rp;
1300 unsigned long flags;
1301
Martin Schwidefsky4f0076f2009-06-22 12:08:19 +02001302 rp = dev_get_drvdata(&cdev->dev);
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001303 if (!rp)
1304 return 0;
1305 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1306 clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
1307 if (rp->view)
1308 rp->view->fn->activate(rp->view);
1309 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1310 return 0;
1311}
1312
1313void raw3270_pm_unfreeze(struct raw3270_view *view)
1314{
Sebastian Ott34483ca2009-10-06 10:33:56 +02001315#ifdef CONFIG_TN3270_CONSOLE
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001316 struct raw3270 *rp;
1317
1318 rp = view->dev;
1319 if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
1320 ccw_device_force_console();
Sebastian Ott34483ca2009-10-06 10:33:56 +02001321#endif
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001322}
1323
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324static struct ccw_device_id raw3270_id[] = {
1325 { CCW_DEVICE(0x3270, 0) },
1326 { CCW_DEVICE(0x3271, 0) },
1327 { CCW_DEVICE(0x3272, 0) },
1328 { CCW_DEVICE(0x3273, 0) },
1329 { CCW_DEVICE(0x3274, 0) },
1330 { CCW_DEVICE(0x3275, 0) },
1331 { CCW_DEVICE(0x3276, 0) },
1332 { CCW_DEVICE(0x3277, 0) },
1333 { CCW_DEVICE(0x3278, 0) },
1334 { CCW_DEVICE(0x3279, 0) },
1335 { CCW_DEVICE(0x3174, 0) },
1336 { /* end of list */ },
1337};
1338
1339static struct ccw_driver raw3270_ccw_driver = {
Sebastian Ott3bda0582011-03-23 10:16:02 +01001340 .driver = {
1341 .name = "3270",
1342 .owner = THIS_MODULE,
1343 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 .ids = raw3270_id,
1345 .probe = &raw3270_probe,
1346 .remove = &raw3270_remove,
1347 .set_online = &raw3270_set_online,
1348 .set_offline = &raw3270_set_offline,
Martin Schwidefsky4b214a02009-06-16 10:30:47 +02001349 .freeze = &raw3270_pm_stop,
1350 .thaw = &raw3270_pm_start,
1351 .restore = &raw3270_pm_start,
Heiko Carstens420f42e2013-01-02 15:18:18 +01001352 .int_class = IRQIO_C70,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353};
1354
1355static int
1356raw3270_init(void)
1357{
1358 struct raw3270 *rp;
1359 int rc;
1360
1361 if (raw3270_registered)
1362 return 0;
1363 raw3270_registered = 1;
1364 rc = ccw_driver_register(&raw3270_ccw_driver);
1365 if (rc == 0) {
1366 /* Create attributes for early (= console) device. */
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001367 mutex_lock(&raw3270_mutex);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001368 class3270 = class_create(THIS_MODULE, "3270");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369 list_for_each_entry(rp, &raw3270_devices, list) {
1370 get_device(&rp->cdev->dev);
1371 raw3270_create_attributes(rp);
1372 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001373 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 }
1375 return rc;
1376}
1377
1378static void
1379raw3270_exit(void)
1380{
1381 ccw_driver_unregister(&raw3270_ccw_driver);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001382 class_destroy(class3270);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383}
1384
1385MODULE_LICENSE("GPL");
1386
1387module_init(raw3270_init);
1388module_exit(raw3270_exit);
1389
Martin Schwidefskyc95571e2013-01-08 15:31:11 +01001390EXPORT_SYMBOL(class3270);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391EXPORT_SYMBOL(raw3270_request_alloc);
1392EXPORT_SYMBOL(raw3270_request_free);
1393EXPORT_SYMBOL(raw3270_request_reset);
1394EXPORT_SYMBOL(raw3270_request_set_cmd);
1395EXPORT_SYMBOL(raw3270_request_add_data);
1396EXPORT_SYMBOL(raw3270_request_set_data);
1397EXPORT_SYMBOL(raw3270_request_set_idal);
1398EXPORT_SYMBOL(raw3270_buffer_address);
1399EXPORT_SYMBOL(raw3270_add_view);
1400EXPORT_SYMBOL(raw3270_del_view);
1401EXPORT_SYMBOL(raw3270_find_view);
1402EXPORT_SYMBOL(raw3270_activate_view);
1403EXPORT_SYMBOL(raw3270_deactivate_view);
1404EXPORT_SYMBOL(raw3270_start);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001405EXPORT_SYMBOL(raw3270_start_locked);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406EXPORT_SYMBOL(raw3270_start_irq);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001407EXPORT_SYMBOL(raw3270_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408EXPORT_SYMBOL(raw3270_register_notifier);
1409EXPORT_SYMBOL(raw3270_unregister_notifier);
1410EXPORT_SYMBOL(raw3270_wait_queue);