blob: 1ab69df2684c5b7e7a1f60478528e65937109bd7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/s390/char/raw3270.c
3 * IBM/3270 Driver - core functions.
4 *
5 * Author(s):
6 * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
7 * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
8 * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
9 */
10
Linus Torvalds1da177e2005-04-16 15:20:36 -070011#include <linux/bootmem.h>
12#include <linux/module.h>
13#include <linux/err.h>
14#include <linux/init.h>
15#include <linux/interrupt.h>
16#include <linux/list.h>
17#include <linux/slab.h>
18#include <linux/types.h>
19#include <linux/wait.h>
20
21#include <asm/ccwdev.h>
22#include <asm/cio.h>
23#include <asm/ebcdic.h>
Michael Holzheu0a87c5c2007-08-22 13:51:40 +020024#include <asm/diag.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26#include "raw3270.h"
27
Richard Hitted3cb6f2005-10-30 15:00:10 -080028#include <linux/major.h>
29#include <linux/kdev_t.h>
30#include <linux/device.h>
Ingo Molnar14cc3e22006-03-26 01:37:14 -080031#include <linux/mutex.h>
Richard Hitted3cb6f2005-10-30 15:00:10 -080032
Heiko Carstens2b67fc42007-02-05 21:16:47 +010033static struct class *class3270;
Richard Hitted3cb6f2005-10-30 15:00:10 -080034
Linus Torvalds1da177e2005-04-16 15:20:36 -070035/* The main 3270 data structure. */
36struct raw3270 {
37 struct list_head list;
38 struct ccw_device *cdev;
39 int minor;
40
41 short model, rows, cols;
42 unsigned long flags;
43
44 struct list_head req_queue; /* Request queue. */
45 struct list_head view_list; /* List of available views. */
46 struct raw3270_view *view; /* Active view. */
47
48 struct timer_list timer; /* Device timer. */
49
50 unsigned char *ascebc; /* ascii -> ebcdic table */
Cornelia Huck7f021ce2007-10-22 12:52:42 +020051 struct device *clttydev; /* 3270-class tty device ptr */
52 struct device *cltubdev; /* 3270-class tub device ptr */
Martin Schwidefsky132fab12006-06-29 14:57:39 +020053
54 struct raw3270_request init_request;
55 unsigned char init_data[256];
Linus Torvalds1da177e2005-04-16 15:20:36 -070056};
57
58/* raw3270->flags */
59#define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */
60#define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */
61#define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */
62#define RAW3270_FLAGS_READY 4 /* Device is useable by views */
63#define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */
64
65/* Semaphore to protect global data of raw3270 (devices, views, etc). */
Ingo Molnar14cc3e22006-03-26 01:37:14 -080066static DEFINE_MUTEX(raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68/* List of 3270 devices. */
Denis Chengc11ca972008-01-26 14:11:13 +010069static LIST_HEAD(raw3270_devices);
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
71/*
72 * Flag to indicate if the driver has been registered. Some operations
73 * like waiting for the end of i/o need to be done differently as long
74 * as the kernel is still starting up (console support).
75 */
76static int raw3270_registered;
77
78/* Module parameters */
79static int tubxcorrect = 0;
80module_param(tubxcorrect, bool, 0);
81
82/*
83 * Wait queue for device init/delete, view delete.
84 */
85DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
86
87/*
88 * Encode array for 12 bit 3270 addresses.
89 */
Heiko Carstens2b67fc42007-02-05 21:16:47 +010090static unsigned char raw3270_ebcgraf[64] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
92 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
93 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
94 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
95 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
96 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
97 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
98 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
99};
100
101void
102raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
103{
104 if (test_bit(RAW3270_FLAGS_14BITADDR, &rp->flags)) {
105 cp[0] = (addr >> 8) & 0x3f;
106 cp[1] = addr & 0xff;
107 } else {
108 cp[0] = raw3270_ebcgraf[(addr >> 6) & 0x3f];
109 cp[1] = raw3270_ebcgraf[addr & 0x3f];
110 }
111}
112
113/*
114 * Allocate a new 3270 ccw request
115 */
116struct raw3270_request *
117raw3270_request_alloc(size_t size)
118{
119 struct raw3270_request *rq;
120
121 /* Allocate request structure */
Eric Sesterhenn88abaab2006-03-24 03:15:31 -0800122 rq = kzalloc(sizeof(struct raw3270_request), GFP_KERNEL | GFP_DMA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 if (!rq)
124 return ERR_PTR(-ENOMEM);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126 /* alloc output buffer. */
127 if (size > 0) {
128 rq->buffer = kmalloc(size, GFP_KERNEL | GFP_DMA);
129 if (!rq->buffer) {
130 kfree(rq);
131 return ERR_PTR(-ENOMEM);
132 }
133 }
134 rq->size = size;
135 INIT_LIST_HEAD(&rq->list);
136
137 /*
138 * Setup ccw.
139 */
140 rq->ccw.cda = __pa(rq->buffer);
141 rq->ccw.flags = CCW_FLAG_SLI;
142
143 return rq;
144}
145
146#ifdef CONFIG_TN3270_CONSOLE
147/*
148 * Allocate a new 3270 ccw request from bootmem. Only works very
149 * early in the boot process. Only con3270.c should be using this.
150 */
Heiko Carstense62133b2007-07-27 12:29:13 +0200151struct raw3270_request __init *raw3270_request_alloc_bootmem(size_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152{
153 struct raw3270_request *rq;
154
155 rq = alloc_bootmem_low(sizeof(struct raw3270));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157 /* alloc output buffer. */
Julia Lawall3ca1c992008-07-14 09:59:13 +0200158 if (size > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 rq->buffer = alloc_bootmem_low(size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 rq->size = size;
161 INIT_LIST_HEAD(&rq->list);
162
163 /*
164 * Setup ccw.
165 */
166 rq->ccw.cda = __pa(rq->buffer);
167 rq->ccw.flags = CCW_FLAG_SLI;
168
169 return rq;
170}
171#endif
172
173/*
174 * Free 3270 ccw request
175 */
176void
177raw3270_request_free (struct raw3270_request *rq)
178{
Jesper Juhl17fd6822005-11-07 01:01:30 -0800179 kfree(rq->buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 kfree(rq);
181}
182
183/*
184 * Reset request to initial state.
185 */
186void
187raw3270_request_reset(struct raw3270_request *rq)
188{
189 BUG_ON(!list_empty(&rq->list));
190 rq->ccw.cmd_code = 0;
191 rq->ccw.count = 0;
192 rq->ccw.cda = __pa(rq->buffer);
193 rq->ccw.flags = CCW_FLAG_SLI;
194 rq->rescnt = 0;
195 rq->rc = 0;
196}
197
198/*
199 * Set command code to ccw of a request.
200 */
201void
202raw3270_request_set_cmd(struct raw3270_request *rq, u8 cmd)
203{
204 rq->ccw.cmd_code = cmd;
205}
206
207/*
208 * Add data fragment to output buffer.
209 */
210int
211raw3270_request_add_data(struct raw3270_request *rq, void *data, size_t size)
212{
213 if (size + rq->ccw.count > rq->size)
214 return -E2BIG;
215 memcpy(rq->buffer + rq->ccw.count, data, size);
216 rq->ccw.count += size;
217 return 0;
218}
219
220/*
221 * Set address/length pair to ccw of a request.
222 */
223void
224raw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size)
225{
226 rq->ccw.cda = __pa(data);
227 rq->ccw.count = size;
228}
229
230/*
231 * Set idal buffer to ccw of a request.
232 */
233void
234raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
235{
236 rq->ccw.cda = __pa(ib->data);
237 rq->ccw.count = ib->size;
238 rq->ccw.flags |= CCW_FLAG_IDA;
239}
240
241/*
242 * Stop running ccw.
243 */
244static int
245raw3270_halt_io_nolock(struct raw3270 *rp, struct raw3270_request *rq)
246{
247 int retries;
248 int rc;
249
250 if (raw3270_request_final(rq))
251 return 0;
252 /* Check if interrupt has already been processed */
253 for (retries = 0; retries < 5; retries++) {
254 if (retries < 2)
255 rc = ccw_device_halt(rp->cdev, (long) rq);
256 else
257 rc = ccw_device_clear(rp->cdev, (long) rq);
258 if (rc == 0)
259 break; /* termination successful */
260 }
261 return rc;
262}
263
264static int
265raw3270_halt_io(struct raw3270 *rp, struct raw3270_request *rq)
266{
267 unsigned long flags;
268 int rc;
269
270 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
271 rc = raw3270_halt_io_nolock(rp, rq);
272 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
273 return rc;
274}
275
276/*
277 * Add the request to the request queue, try to start it if the
278 * 3270 device is idle. Return without waiting for end of i/o.
279 */
280static int
281__raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
282 struct raw3270_request *rq)
283{
284 rq->view = view;
285 raw3270_get_view(view);
286 if (list_empty(&rp->req_queue) &&
287 !test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {
288 /* No other requests are on the queue. Start this one. */
289 rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
290 (unsigned long) rq, 0, 0);
291 if (rq->rc) {
292 raw3270_put_view(view);
293 return rq->rc;
294 }
295 }
296 list_add_tail(&rq->list, &rp->req_queue);
297 return 0;
298}
299
300int
301raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
302{
303 unsigned long flags;
304 struct raw3270 *rp;
305 int rc;
306
307 spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
308 rp = view->dev;
309 if (!rp || rp->view != view)
310 rc = -EACCES;
311 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
312 rc = -ENODEV;
313 else
314 rc = __raw3270_start(rp, view, rq);
315 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
316 return rc;
317}
318
319int
Richard Hitted3cb6f2005-10-30 15:00:10 -0800320raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
321{
322 struct raw3270 *rp;
323 int rc;
324
325 rp = view->dev;
326 if (!rp || rp->view != view)
327 rc = -EACCES;
328 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
329 rc = -ENODEV;
330 else
331 rc = __raw3270_start(rp, view, rq);
332 return rc;
333}
334
335int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq)
337{
338 struct raw3270 *rp;
339
340 rp = view->dev;
341 rq->view = view;
342 raw3270_get_view(view);
343 list_add_tail(&rq->list, &rp->req_queue);
344 return 0;
345}
346
347/*
348 * 3270 interrupt routine, called from the ccw_device layer
349 */
350static void
351raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
352{
353 struct raw3270 *rp;
354 struct raw3270_view *view;
355 struct raw3270_request *rq;
356 int rc;
357
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -0700358 rp = dev_get_drvdata(&cdev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 if (!rp)
360 return;
361 rq = (struct raw3270_request *) intparm;
362 view = rq ? rq->view : rp->view;
363
364 if (IS_ERR(irb))
365 rc = RAW3270_IO_RETRY;
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200366 else if (irb->scsw.cmd.fctl & SCSW_FCTL_HALT_FUNC) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 rq->rc = -EIO;
368 rc = RAW3270_IO_DONE;
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200369 } else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END |
370 DEV_STAT_UNIT_EXCEP)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 /* Handle CE-DE-UE and subsequent UDE */
372 set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
373 rc = RAW3270_IO_BUSY;
374 } else if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {
375 /* Wait for UDE if busy flag is set. */
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200376 if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377 clear_bit(RAW3270_FLAGS_BUSY, &rp->flags);
378 /* Got it, now retry. */
379 rc = RAW3270_IO_RETRY;
380 } else
381 rc = RAW3270_IO_BUSY;
382 } else if (view)
383 rc = view->fn->intv(view, rq, irb);
384 else
385 rc = RAW3270_IO_DONE;
386
387 switch (rc) {
388 case RAW3270_IO_DONE:
389 break;
390 case RAW3270_IO_BUSY:
391 /*
392 * Intervention required by the operator. We have to wait
393 * for unsolicited device end.
394 */
395 return;
396 case RAW3270_IO_RETRY:
397 if (!rq)
398 break;
399 rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
400 (unsigned long) rq, 0, 0);
401 if (rq->rc == 0)
402 return; /* Sucessfully restarted. */
403 break;
404 case RAW3270_IO_STOP:
405 if (!rq)
406 break;
407 raw3270_halt_io_nolock(rp, rq);
408 rq->rc = -EIO;
409 break;
410 default:
411 BUG();
412 }
413 if (rq) {
414 BUG_ON(list_empty(&rq->list));
415 /* The request completed, remove from queue and do callback. */
416 list_del_init(&rq->list);
417 if (rq->callback)
418 rq->callback(rq, rq->callback_data);
419 /* Do put_device for get_device in raw3270_start. */
420 raw3270_put_view(view);
421 }
422 /*
423 * Try to start each request on request queue until one is
424 * started successful.
425 */
426 while (!list_empty(&rp->req_queue)) {
427 rq = list_entry(rp->req_queue.next,struct raw3270_request,list);
428 rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
429 (unsigned long) rq, 0, 0);
430 if (rq->rc == 0)
431 break;
432 /* Start failed. Remove request and do callback. */
433 list_del_init(&rq->list);
434 if (rq->callback)
435 rq->callback(rq, rq->callback_data);
436 /* Do put_device for get_device in raw3270_start. */
437 raw3270_put_view(view);
438 }
439}
440
441/*
442 * Size sensing.
443 */
444
445struct raw3270_ua { /* Query Reply structure for Usable Area */
446 struct { /* Usable Area Query Reply Base */
447 short l; /* Length of this structured field */
448 char sfid; /* 0x81 if Query Reply */
449 char qcode; /* 0x81 if Usable Area */
450 char flags0;
451 char flags1;
452 short w; /* Width of usable area */
453 short h; /* Heigth of usavle area */
454 char units; /* 0x00:in; 0x01:mm */
455 int xr;
456 int yr;
457 char aw;
458 char ah;
459 short buffsz; /* Character buffer size, bytes */
460 char xmin;
461 char ymin;
462 char xmax;
463 char ymax;
464 } __attribute__ ((packed)) uab;
465 struct { /* Alternate Usable Area Self-Defining Parameter */
466 char l; /* Length of this Self-Defining Parm */
467 char sdpid; /* 0x02 if Alternate Usable Area */
468 char res;
469 char auaid; /* 0x01 is Id for the A U A */
470 short wauai; /* Width of AUAi */
471 short hauai; /* Height of AUAi */
472 char auaunits; /* 0x00:in, 0x01:mm */
473 int auaxr;
474 int auayr;
475 char awauai;
476 char ahauai;
477 } __attribute__ ((packed)) aua;
478} __attribute__ ((packed));
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480static struct diag210 raw3270_init_diag210;
Christoph Hellwigd330f932007-05-31 17:38:04 +0200481static DEFINE_MUTEX(raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
483static int
484raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
485 struct irb *irb)
486{
487 /*
488 * Unit-Check Processing:
489 * Expect Command Reject or Intervention Required.
490 */
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200491 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 /* Request finished abnormally. */
493 if (irb->ecw[0] & SNS0_INTERVENTION_REQ) {
494 set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags);
495 return RAW3270_IO_BUSY;
496 }
497 }
498 if (rq) {
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200499 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 if (irb->ecw[0] & SNS0_CMD_REJECT)
501 rq->rc = -EOPNOTSUPP;
502 else
503 rq->rc = -EIO;
504 } else
505 /* Request finished normally. Copy residual count. */
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200506 rq->rescnt = irb->scsw.cmd.count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 }
Peter Oberparleiter23d805b2008-07-14 09:58:50 +0200508 if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 set_bit(RAW3270_FLAGS_ATTN, &view->dev->flags);
510 wake_up(&raw3270_wait_queue);
511 }
512 return RAW3270_IO_DONE;
513}
514
515static struct raw3270_fn raw3270_init_fn = {
516 .intv = raw3270_init_irq
517};
518
519static struct raw3270_view raw3270_init_view = {
520 .fn = &raw3270_init_fn
521};
522
523/*
524 * raw3270_wait/raw3270_wait_interruptible/__raw3270_wakeup
525 * Wait for end of request. The request must have been started
526 * with raw3270_start, rc = 0. The device lock may NOT have been
527 * released between calling raw3270_start and raw3270_wait.
528 */
529static void
530raw3270_wake_init(struct raw3270_request *rq, void *data)
531{
532 wake_up((wait_queue_head_t *) data);
533}
534
535/*
536 * Special wait function that can cope with console initialization.
537 */
538static int
539raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view,
540 struct raw3270_request *rq)
541{
542 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 int rc;
544
545#ifdef CONFIG_TN3270_CONSOLE
546 if (raw3270_registered == 0) {
547 spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200548 rq->callback = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 rc = __raw3270_start(rp, view, rq);
550 if (rc == 0)
551 while (!raw3270_request_final(rq)) {
552 wait_cons_dev();
553 barrier();
554 }
555 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
556 return rq->rc;
557 }
558#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 rq->callback = raw3270_wake_init;
Martin Schwidefsky54ad6412008-05-30 10:03:32 +0200560 rq->callback_data = &raw3270_wait_queue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
562 rc = __raw3270_start(rp, view, rq);
563 spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
564 if (rc)
565 return rc;
566 /* Now wait for the completion. */
Martin Schwidefsky54ad6412008-05-30 10:03:32 +0200567 rc = wait_event_interruptible(raw3270_wait_queue,
568 raw3270_request_final(rq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 if (rc == -ERESTARTSYS) { /* Interrupted by a signal. */
570 raw3270_halt_io(view->dev, rq);
571 /* No wait for the halt to complete. */
Martin Schwidefsky54ad6412008-05-30 10:03:32 +0200572 wait_event(raw3270_wait_queue, raw3270_request_final(rq));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 return -ERESTARTSYS;
574 }
575 return rq->rc;
576}
577
578static int
579__raw3270_size_device_vm(struct raw3270 *rp)
580{
581 int rc, model;
Cornelia Huck9a92fe42007-05-10 15:45:42 +0200582 struct ccw_dev_id dev_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Cornelia Huck9a92fe42007-05-10 15:45:42 +0200584 ccw_device_get_id(rp->cdev, &dev_id);
585 raw3270_init_diag210.vrdcdvno = dev_id.devno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 raw3270_init_diag210.vrdclen = sizeof(struct diag210);
587 rc = diag210(&raw3270_init_diag210);
588 if (rc)
589 return rc;
590 model = raw3270_init_diag210.vrdccrmd;
591 switch (model) {
592 case 2:
593 rp->model = model;
594 rp->rows = 24;
595 rp->cols = 80;
596 break;
597 case 3:
598 rp->model = model;
599 rp->rows = 32;
600 rp->cols = 80;
601 break;
602 case 4:
603 rp->model = model;
604 rp->rows = 43;
605 rp->cols = 80;
606 break;
607 case 5:
608 rp->model = model;
609 rp->rows = 27;
610 rp->cols = 132;
611 break;
612 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 rc = -EOPNOTSUPP;
614 break;
615 }
616 return rc;
617}
618
619static int
620__raw3270_size_device(struct raw3270 *rp)
621{
622 static const unsigned char wbuf[] =
623 { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
624 struct raw3270_ua *uap;
625 unsigned short count;
626 int rc;
627
628 /*
629 * To determine the size of the 3270 device we need to do:
630 * 1) send a 'read partition' data stream to the device
631 * 2) wait for the attn interrupt that preceeds the query reply
632 * 3) do a read modified to get the query reply
633 * To make things worse we have to cope with intervention
634 * required (3270 device switched to 'stand-by') and command
635 * rejects (old devices that can't do 'read partition').
636 */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200637 memset(&rp->init_request, 0, sizeof(rp->init_request));
638 memset(&rp->init_data, 0, 256);
639 /* Store 'read partition' data stream to init_data */
640 memcpy(&rp->init_data, wbuf, sizeof(wbuf));
641 INIT_LIST_HEAD(&rp->init_request.list);
642 rp->init_request.ccw.cmd_code = TC_WRITESF;
643 rp->init_request.ccw.flags = CCW_FLAG_SLI;
644 rp->init_request.ccw.count = sizeof(wbuf);
645 rp->init_request.ccw.cda = (__u32) __pa(&rp->init_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200647 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
Martin Schwidefsky3863e722005-09-03 15:58:06 -0700648 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 /* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651
652 /* Wait for attention interrupt. */
653#ifdef CONFIG_TN3270_CONSOLE
654 if (raw3270_registered == 0) {
655 unsigned long flags;
656
657 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
658 while (!test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags))
659 wait_cons_dev();
660 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
661 } else
662#endif
663 rc = wait_event_interruptible(raw3270_wait_queue,
664 test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags));
665 if (rc)
666 return rc;
667
668 /*
669 * The device accepted the 'read partition' command. Now
670 * set up a read ccw and issue it.
671 */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200672 rp->init_request.ccw.cmd_code = TC_READMOD;
673 rp->init_request.ccw.flags = CCW_FLAG_SLI;
674 rp->init_request.ccw.count = sizeof(rp->init_data);
675 rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
676 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 if (rc)
678 return rc;
679 /* Got a Query Reply */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200680 count = sizeof(rp->init_data) - rp->init_request.rescnt;
681 uap = (struct raw3270_ua *) (rp->init_data + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 /* Paranoia check. */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200683 if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 return -EOPNOTSUPP;
685 /* Copy rows/columns of default Usable Area */
686 rp->rows = uap->uab.h;
687 rp->cols = uap->uab.w;
688 /* Check for 14 bit addressing */
689 if ((uap->uab.flags0 & 0x0d) == 0x01)
690 set_bit(RAW3270_FLAGS_14BITADDR, &rp->flags);
691 /* Check for Alternate Usable Area */
692 if (uap->uab.l == sizeof(struct raw3270_ua) &&
693 uap->aua.sdpid == 0x02) {
694 rp->rows = uap->aua.hauai;
695 rp->cols = uap->aua.wauai;
696 }
697 return 0;
698}
699
700static int
701raw3270_size_device(struct raw3270 *rp)
702{
703 int rc;
704
Christoph Hellwigd330f932007-05-31 17:38:04 +0200705 mutex_lock(&raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 rp->view = &raw3270_init_view;
707 raw3270_init_view.dev = rp;
Martin Schwidefsky3863e722005-09-03 15:58:06 -0700708 if (MACHINE_IS_VM)
709 rc = __raw3270_size_device_vm(rp);
710 else
711 rc = __raw3270_size_device(rp);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200712 raw3270_init_view.dev = NULL;
713 rp->view = NULL;
Christoph Hellwigd330f932007-05-31 17:38:04 +0200714 mutex_unlock(&raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 if (rc == 0) { /* Found something. */
716 /* Try to find a model. */
717 rp->model = 0;
718 if (rp->rows == 24 && rp->cols == 80)
719 rp->model = 2;
720 if (rp->rows == 32 && rp->cols == 80)
721 rp->model = 3;
722 if (rp->rows == 43 && rp->cols == 80)
723 rp->model = 4;
724 if (rp->rows == 27 && rp->cols == 132)
725 rp->model = 5;
Martin Schwidefsky3863e722005-09-03 15:58:06 -0700726 } else {
727 /* Couldn't detect size. Use default model 2. */
728 rp->model = 2;
729 rp->rows = 24;
730 rp->cols = 80;
731 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 }
733 return rc;
734}
735
736static int
737raw3270_reset_device(struct raw3270 *rp)
738{
739 int rc;
740
Christoph Hellwigd330f932007-05-31 17:38:04 +0200741 mutex_lock(&raw3270_init_mutex);
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200742 memset(&rp->init_request, 0, sizeof(rp->init_request));
743 memset(&rp->init_data, 0, sizeof(rp->init_data));
744 /* Store reset data stream to init_data/init_request */
745 rp->init_data[0] = TW_KR;
746 INIT_LIST_HEAD(&rp->init_request.list);
747 rp->init_request.ccw.cmd_code = TC_EWRITEA;
748 rp->init_request.ccw.flags = CCW_FLAG_SLI;
749 rp->init_request.ccw.count = 1;
750 rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 rp->view = &raw3270_init_view;
752 raw3270_init_view.dev = rp;
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200753 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200754 raw3270_init_view.dev = NULL;
755 rp->view = NULL;
Christoph Hellwigd330f932007-05-31 17:38:04 +0200756 mutex_unlock(&raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757 return rc;
758}
759
Richard Hitted3cb6f2005-10-30 15:00:10 -0800760int
761raw3270_reset(struct raw3270_view *view)
762{
763 struct raw3270 *rp;
764 int rc;
765
766 rp = view->dev;
767 if (!rp || rp->view != view)
768 rc = -EACCES;
769 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
770 rc = -ENODEV;
771 else
772 rc = raw3270_reset_device(view->dev);
773 return rc;
774}
775
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776/*
777 * Setup new 3270 device.
778 */
779static int
780raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
781{
782 struct list_head *l;
783 struct raw3270 *tmp;
784 int minor;
785
786 memset(rp, 0, sizeof(struct raw3270));
787 /* Copy ebcdic -> ascii translation table. */
788 memcpy(ascebc, _ascebc, 256);
789 if (tubxcorrect) {
790 /* correct brackets and circumflex */
791 ascebc['['] = 0xad;
792 ascebc[']'] = 0xbd;
793 ascebc['^'] = 0xb0;
794 }
795 rp->ascebc = ascebc;
796
797 /* Set defaults. */
798 rp->rows = 24;
799 rp->cols = 80;
800
801 INIT_LIST_HEAD(&rp->req_queue);
802 INIT_LIST_HEAD(&rp->view_list);
803
804 /*
805 * Add device to list and find the smallest unused minor
Richard Hitted3cb6f2005-10-30 15:00:10 -0800806 * number for it. Note: there is no device with minor 0,
807 * see special case for fs3270.c:fs3270_open().
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 */
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800809 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 /* Keep the list sorted. */
Richard Hitted3cb6f2005-10-30 15:00:10 -0800811 minor = RAW3270_FIRSTMINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 rp->minor = -1;
813 list_for_each(l, &raw3270_devices) {
814 tmp = list_entry(l, struct raw3270, list);
815 if (tmp->minor > minor) {
816 rp->minor = minor;
817 __list_add(&rp->list, l->prev, l);
818 break;
819 }
820 minor++;
821 }
Richard Hitted3cb6f2005-10-30 15:00:10 -0800822 if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 rp->minor = minor;
824 list_add_tail(&rp->list, &raw3270_devices);
825 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800826 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 /* No free minor number? Then give up. */
828 if (rp->minor == -1)
829 return -EUSERS;
830 rp->cdev = cdev;
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -0700831 dev_set_drvdata(&cdev->dev, rp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 cdev->handler = raw3270_irq;
833 return 0;
834}
835
836#ifdef CONFIG_TN3270_CONSOLE
837/*
838 * Setup 3270 device configured as console.
839 */
Heiko Carstense62133b2007-07-27 12:29:13 +0200840struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841{
842 struct raw3270 *rp;
843 char *ascebc;
844 int rc;
845
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200846 rp = (struct raw3270 *) alloc_bootmem_low(sizeof(struct raw3270));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 ascebc = (char *) alloc_bootmem(256);
848 rc = raw3270_setup_device(cdev, rp, ascebc);
849 if (rc)
850 return ERR_PTR(rc);
851 set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
852 rc = raw3270_reset_device(rp);
853 if (rc)
854 return ERR_PTR(rc);
855 rc = raw3270_size_device(rp);
856 if (rc)
857 return ERR_PTR(rc);
858 rc = raw3270_reset_device(rp);
859 if (rc)
860 return ERR_PTR(rc);
861 set_bit(RAW3270_FLAGS_READY, &rp->flags);
862 return rp;
863}
864
865void
866raw3270_wait_cons_dev(struct raw3270 *rp)
867{
868 unsigned long flags;
869
870 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
871 wait_cons_dev();
872 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
873}
874
875#endif
876
877/*
878 * Create a 3270 device structure.
879 */
880static struct raw3270 *
881raw3270_create_device(struct ccw_device *cdev)
882{
883 struct raw3270 *rp;
884 char *ascebc;
885 int rc;
886
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200887 rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 if (!rp)
889 return ERR_PTR(-ENOMEM);
890 ascebc = kmalloc(256, GFP_KERNEL);
891 if (!ascebc) {
892 kfree(rp);
893 return ERR_PTR(-ENOMEM);
894 }
895 rc = raw3270_setup_device(cdev, rp, ascebc);
896 if (rc) {
897 kfree(rp->ascebc);
898 kfree(rp);
899 rp = ERR_PTR(rc);
900 }
901 /* Get reference to ccw_device structure. */
902 get_device(&cdev->dev);
903 return rp;
904}
905
906/*
907 * Activate a view.
908 */
909int
910raw3270_activate_view(struct raw3270_view *view)
911{
912 struct raw3270 *rp;
913 struct raw3270_view *oldview, *nv;
914 unsigned long flags;
915 int rc;
916
917 rp = view->dev;
918 if (!rp)
919 return -ENODEV;
920 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
921 if (rp->view == view)
922 rc = 0;
923 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
924 rc = -ENODEV;
925 else {
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200926 oldview = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 if (rp->view) {
928 oldview = rp->view;
929 oldview->fn->deactivate(oldview);
930 }
931 rp->view = view;
932 rc = view->fn->activate(view);
933 if (rc) {
934 /* Didn't work. Try to reactivate the old view. */
935 rp->view = oldview;
936 if (!oldview || oldview->fn->activate(oldview) != 0) {
937 /* Didn't work as well. Try any other view. */
938 list_for_each_entry(nv, &rp->view_list, list)
939 if (nv != view && nv != oldview) {
940 rp->view = nv;
941 if (nv->fn->activate(nv) == 0)
942 break;
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200943 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 }
945 }
946 }
947 }
948 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
949 return rc;
950}
951
952/*
953 * Deactivate current view.
954 */
955void
956raw3270_deactivate_view(struct raw3270_view *view)
957{
958 unsigned long flags;
959 struct raw3270 *rp;
960
961 rp = view->dev;
962 if (!rp)
963 return;
964 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
965 if (rp->view == view) {
966 view->fn->deactivate(view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200967 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968 /* Move deactivated view to end of list. */
969 list_del_init(&view->list);
970 list_add_tail(&view->list, &rp->view_list);
971 /* Try to activate another view. */
972 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
Richard Hitted3cb6f2005-10-30 15:00:10 -0800973 list_for_each_entry(view, &rp->view_list, list) {
974 rp->view = view;
975 if (view->fn->activate(view) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 break;
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200977 rp->view = NULL;
Richard Hitted3cb6f2005-10-30 15:00:10 -0800978 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 }
980 }
981 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
982}
983
984/*
985 * Add view to device with minor "minor".
986 */
987int
988raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
989{
990 unsigned long flags;
991 struct raw3270 *rp;
992 int rc;
993
Richard Hitted3cb6f2005-10-30 15:00:10 -0800994 if (minor <= 0)
995 return -ENODEV;
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800996 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997 rc = -ENODEV;
998 list_for_each_entry(rp, &raw3270_devices, list) {
999 if (rp->minor != minor)
1000 continue;
1001 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1002 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
1003 atomic_set(&view->ref_count, 2);
1004 view->dev = rp;
1005 view->fn = fn;
1006 view->model = rp->model;
1007 view->rows = rp->rows;
1008 view->cols = rp->cols;
1009 view->ascebc = rp->ascebc;
1010 spin_lock_init(&view->lock);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001011 list_add(&view->list, &rp->view_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 rc = 0;
1013 }
1014 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1015 break;
1016 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001017 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 return rc;
1019}
1020
1021/*
1022 * Find specific view of device with minor "minor".
1023 */
1024struct raw3270_view *
1025raw3270_find_view(struct raw3270_fn *fn, int minor)
1026{
1027 struct raw3270 *rp;
1028 struct raw3270_view *view, *tmp;
1029 unsigned long flags;
1030
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001031 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 view = ERR_PTR(-ENODEV);
1033 list_for_each_entry(rp, &raw3270_devices, list) {
1034 if (rp->minor != minor)
1035 continue;
1036 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1037 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
1038 view = ERR_PTR(-ENOENT);
1039 list_for_each_entry(tmp, &rp->view_list, list) {
1040 if (tmp->fn == fn) {
1041 raw3270_get_view(tmp);
1042 view = tmp;
1043 break;
1044 }
1045 }
1046 }
1047 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1048 break;
1049 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001050 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 return view;
1052}
1053
1054/*
1055 * Remove view from device and free view structure via call to view->fn->free.
1056 */
1057void
1058raw3270_del_view(struct raw3270_view *view)
1059{
1060 unsigned long flags;
1061 struct raw3270 *rp;
1062 struct raw3270_view *nv;
1063
1064 rp = view->dev;
1065 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1066 if (rp->view == view) {
1067 view->fn->deactivate(view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001068 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 }
1070 list_del_init(&view->list);
1071 if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
1072 /* Try to activate another view. */
1073 list_for_each_entry(nv, &rp->view_list, list) {
Richard Hitted3cb6f2005-10-30 15:00:10 -08001074 if (nv->fn->activate(nv) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 rp->view = nv;
1076 break;
1077 }
1078 }
1079 }
1080 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1081 /* Wait for reference counter to drop to zero. */
1082 atomic_dec(&view->ref_count);
1083 wait_event(raw3270_wait_queue, atomic_read(&view->ref_count) == 0);
1084 if (view->fn->free)
1085 view->fn->free(view);
1086}
1087
1088/*
1089 * Remove a 3270 device structure.
1090 */
1091static void
1092raw3270_delete_device(struct raw3270 *rp)
1093{
1094 struct ccw_device *cdev;
1095
1096 /* Remove from device chain. */
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001097 mutex_lock(&raw3270_mutex);
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001098 if (rp->clttydev && !IS_ERR(rp->clttydev))
Cornelia Huck7f021ce2007-10-22 12:52:42 +02001099 device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001100 if (rp->cltubdev && !IS_ERR(rp->cltubdev))
Cornelia Huck7f021ce2007-10-22 12:52:42 +02001101 device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, rp->minor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 list_del_init(&rp->list);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001103 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 /* Disconnect from ccw_device. */
1106 cdev = rp->cdev;
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001107 rp->cdev = NULL;
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001108 dev_set_drvdata(&cdev->dev, NULL);
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001109 cdev->handler = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
1111 /* Put ccw_device structure. */
1112 put_device(&cdev->dev);
1113
1114 /* Now free raw3270 structure. */
1115 kfree(rp->ascebc);
1116 kfree(rp);
1117}
1118
1119static int
1120raw3270_probe (struct ccw_device *cdev)
1121{
1122 return 0;
1123}
1124
1125/*
1126 * Additional attributes for a 3270 device
1127 */
1128static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001129raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130{
1131 return snprintf(buf, PAGE_SIZE, "%i\n",
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001132 ((struct raw3270 *) dev_get_drvdata(dev))->model);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001134static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001137raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138{
1139 return snprintf(buf, PAGE_SIZE, "%i\n",
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001140 ((struct raw3270 *) dev_get_drvdata(dev))->rows);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001142static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143
1144static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001145raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146{
1147 return snprintf(buf, PAGE_SIZE, "%i\n",
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001148 ((struct raw3270 *) dev_get_drvdata(dev))->cols);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001150static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
1152static struct attribute * raw3270_attrs[] = {
1153 &dev_attr_model.attr,
1154 &dev_attr_rows.attr,
1155 &dev_attr_columns.attr,
1156 NULL,
1157};
1158
1159static struct attribute_group raw3270_attr_group = {
1160 .attrs = raw3270_attrs,
1161};
1162
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001163static int raw3270_create_attributes(struct raw3270 *rp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164{
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001165 int rc;
1166
1167 rc = sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
1168 if (rc)
1169 goto out;
1170
Greg Kroah-Hartmanea9e42f2008-07-21 20:03:34 -07001171 rp->clttydev = device_create(class3270, &rp->cdev->dev,
1172 MKDEV(IBM_TTY3270_MAJOR, rp->minor), NULL,
1173 "tty%s", dev_name(&rp->cdev->dev));
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001174 if (IS_ERR(rp->clttydev)) {
1175 rc = PTR_ERR(rp->clttydev);
1176 goto out_ttydev;
1177 }
1178
Greg Kroah-Hartmanea9e42f2008-07-21 20:03:34 -07001179 rp->cltubdev = device_create(class3270, &rp->cdev->dev,
1180 MKDEV(IBM_FS3270_MAJOR, rp->minor), NULL,
1181 "tub%s", dev_name(&rp->cdev->dev));
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001182 if (!IS_ERR(rp->cltubdev))
1183 goto out;
1184
1185 rc = PTR_ERR(rp->cltubdev);
Cornelia Huck7f021ce2007-10-22 12:52:42 +02001186 device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001187
1188out_ttydev:
1189 sysfs_remove_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
1190out:
1191 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192}
1193
1194/*
1195 * Notifier for device addition/removal
1196 */
1197struct raw3270_notifier {
1198 struct list_head list;
1199 void (*notifier)(int, int);
1200};
1201
Denis Chengc11ca972008-01-26 14:11:13 +01001202static LIST_HEAD(raw3270_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204int raw3270_register_notifier(void (*notifier)(int, int))
1205{
1206 struct raw3270_notifier *np;
1207 struct raw3270 *rp;
1208
1209 np = kmalloc(sizeof(struct raw3270_notifier), GFP_KERNEL);
1210 if (!np)
1211 return -ENOMEM;
1212 np->notifier = notifier;
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001213 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 list_add_tail(&np->list, &raw3270_notifier);
1215 list_for_each_entry(rp, &raw3270_devices, list) {
1216 get_device(&rp->cdev->dev);
1217 notifier(rp->minor, 1);
1218 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001219 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 return 0;
1221}
1222
1223void raw3270_unregister_notifier(void (*notifier)(int, int))
1224{
1225 struct raw3270_notifier *np;
1226
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001227 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 list_for_each_entry(np, &raw3270_notifier, list)
1229 if (np->notifier == notifier) {
1230 list_del(&np->list);
1231 kfree(np);
1232 break;
1233 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001234 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235}
1236
1237/*
1238 * Set 3270 device online.
1239 */
1240static int
1241raw3270_set_online (struct ccw_device *cdev)
1242{
1243 struct raw3270 *rp;
1244 struct raw3270_notifier *np;
1245 int rc;
1246
1247 rp = raw3270_create_device(cdev);
1248 if (IS_ERR(rp))
1249 return PTR_ERR(rp);
1250 rc = raw3270_reset_device(rp);
1251 if (rc)
Richard Hitted3cb6f2005-10-30 15:00:10 -08001252 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 rc = raw3270_size_device(rp);
1254 if (rc)
Richard Hitted3cb6f2005-10-30 15:00:10 -08001255 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 rc = raw3270_reset_device(rp);
1257 if (rc)
Richard Hitted3cb6f2005-10-30 15:00:10 -08001258 goto failure;
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001259 rc = raw3270_create_attributes(rp);
1260 if (rc)
1261 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262 set_bit(RAW3270_FLAGS_READY, &rp->flags);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001263 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 list_for_each_entry(np, &raw3270_notifier, list)
1265 np->notifier(rp->minor, 1);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001266 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 return 0;
Richard Hitted3cb6f2005-10-30 15:00:10 -08001268
1269failure:
1270 raw3270_delete_device(rp);
1271 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272}
1273
1274/*
1275 * Remove 3270 device structure.
1276 */
1277static void
1278raw3270_remove (struct ccw_device *cdev)
1279{
1280 unsigned long flags;
1281 struct raw3270 *rp;
1282 struct raw3270_view *v;
1283 struct raw3270_notifier *np;
1284
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001285 rp = dev_get_drvdata(&cdev->dev);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001286 /*
1287 * _remove is the opposite of _probe; it's probe that
1288 * should set up rp. raw3270_remove gets entered for
1289 * devices even if they haven't been varied online.
1290 * Thus, rp may validly be NULL here.
1291 */
1292 if (rp == NULL)
1293 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001294 clear_bit(RAW3270_FLAGS_READY, &rp->flags);
1295
1296 sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
1297
1298 /* Deactivate current view and remove all views. */
1299 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1300 if (rp->view) {
1301 rp->view->fn->deactivate(rp->view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001302 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 }
1304 while (!list_empty(&rp->view_list)) {
1305 v = list_entry(rp->view_list.next, struct raw3270_view, list);
1306 if (v->fn->release)
1307 v->fn->release(v);
1308 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
1309 raw3270_del_view(v);
1310 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1311 }
1312 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
1313
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001314 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315 list_for_each_entry(np, &raw3270_notifier, list)
1316 np->notifier(rp->minor, 0);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001317 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
1319 /* Reset 3270 device. */
1320 raw3270_reset_device(rp);
1321 /* And finally remove it. */
1322 raw3270_delete_device(rp);
1323}
1324
1325/*
1326 * Set 3270 device offline.
1327 */
1328static int
1329raw3270_set_offline (struct ccw_device *cdev)
1330{
1331 struct raw3270 *rp;
1332
Greg Kroah-Hartmandff59b62009-05-04 12:40:54 -07001333 rp = dev_get_drvdata(&cdev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags))
1335 return -EBUSY;
1336 raw3270_remove(cdev);
1337 return 0;
1338}
1339
1340static struct ccw_device_id raw3270_id[] = {
1341 { CCW_DEVICE(0x3270, 0) },
1342 { CCW_DEVICE(0x3271, 0) },
1343 { CCW_DEVICE(0x3272, 0) },
1344 { CCW_DEVICE(0x3273, 0) },
1345 { CCW_DEVICE(0x3274, 0) },
1346 { CCW_DEVICE(0x3275, 0) },
1347 { CCW_DEVICE(0x3276, 0) },
1348 { CCW_DEVICE(0x3277, 0) },
1349 { CCW_DEVICE(0x3278, 0) },
1350 { CCW_DEVICE(0x3279, 0) },
1351 { CCW_DEVICE(0x3174, 0) },
1352 { /* end of list */ },
1353};
1354
1355static struct ccw_driver raw3270_ccw_driver = {
1356 .name = "3270",
1357 .owner = THIS_MODULE,
1358 .ids = raw3270_id,
1359 .probe = &raw3270_probe,
1360 .remove = &raw3270_remove,
1361 .set_online = &raw3270_set_online,
1362 .set_offline = &raw3270_set_offline,
1363};
1364
1365static int
1366raw3270_init(void)
1367{
1368 struct raw3270 *rp;
1369 int rc;
1370
1371 if (raw3270_registered)
1372 return 0;
1373 raw3270_registered = 1;
1374 rc = ccw_driver_register(&raw3270_ccw_driver);
1375 if (rc == 0) {
1376 /* Create attributes for early (= console) device. */
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001377 mutex_lock(&raw3270_mutex);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001378 class3270 = class_create(THIS_MODULE, "3270");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 list_for_each_entry(rp, &raw3270_devices, list) {
1380 get_device(&rp->cdev->dev);
1381 raw3270_create_attributes(rp);
1382 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001383 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 }
1385 return rc;
1386}
1387
1388static void
1389raw3270_exit(void)
1390{
1391 ccw_driver_unregister(&raw3270_ccw_driver);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001392 class_destroy(class3270);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393}
1394
1395MODULE_LICENSE("GPL");
1396
1397module_init(raw3270_init);
1398module_exit(raw3270_exit);
1399
1400EXPORT_SYMBOL(raw3270_request_alloc);
1401EXPORT_SYMBOL(raw3270_request_free);
1402EXPORT_SYMBOL(raw3270_request_reset);
1403EXPORT_SYMBOL(raw3270_request_set_cmd);
1404EXPORT_SYMBOL(raw3270_request_add_data);
1405EXPORT_SYMBOL(raw3270_request_set_data);
1406EXPORT_SYMBOL(raw3270_request_set_idal);
1407EXPORT_SYMBOL(raw3270_buffer_address);
1408EXPORT_SYMBOL(raw3270_add_view);
1409EXPORT_SYMBOL(raw3270_del_view);
1410EXPORT_SYMBOL(raw3270_find_view);
1411EXPORT_SYMBOL(raw3270_activate_view);
1412EXPORT_SYMBOL(raw3270_deactivate_view);
1413EXPORT_SYMBOL(raw3270_start);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001414EXPORT_SYMBOL(raw3270_start_locked);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415EXPORT_SYMBOL(raw3270_start_irq);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001416EXPORT_SYMBOL(raw3270_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417EXPORT_SYMBOL(raw3270_register_notifier);
1418EXPORT_SYMBOL(raw3270_unregister_notifier);
1419EXPORT_SYMBOL(raw3270_wait_queue);