blob: e2767e3b8cfd0e2989bb628344924d81999b0dea [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
358 rp = (struct raw3270 *) cdev->dev.driver_data;
359 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:
613 printk(KERN_WARNING "vrdccrmd is 0x%.8x\n", model);
614 rc = -EOPNOTSUPP;
615 break;
616 }
617 return rc;
618}
619
620static int
621__raw3270_size_device(struct raw3270 *rp)
622{
623 static const unsigned char wbuf[] =
624 { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
625 struct raw3270_ua *uap;
626 unsigned short count;
627 int rc;
628
629 /*
630 * To determine the size of the 3270 device we need to do:
631 * 1) send a 'read partition' data stream to the device
632 * 2) wait for the attn interrupt that preceeds the query reply
633 * 3) do a read modified to get the query reply
634 * To make things worse we have to cope with intervention
635 * required (3270 device switched to 'stand-by') and command
636 * rejects (old devices that can't do 'read partition').
637 */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200638 memset(&rp->init_request, 0, sizeof(rp->init_request));
639 memset(&rp->init_data, 0, 256);
640 /* Store 'read partition' data stream to init_data */
641 memcpy(&rp->init_data, wbuf, sizeof(wbuf));
642 INIT_LIST_HEAD(&rp->init_request.list);
643 rp->init_request.ccw.cmd_code = TC_WRITESF;
644 rp->init_request.ccw.flags = CCW_FLAG_SLI;
645 rp->init_request.ccw.count = sizeof(wbuf);
646 rp->init_request.ccw.cda = (__u32) __pa(&rp->init_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200648 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
Martin Schwidefsky3863e722005-09-03 15:58:06 -0700649 if (rc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650 /* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 /* Wait for attention interrupt. */
654#ifdef CONFIG_TN3270_CONSOLE
655 if (raw3270_registered == 0) {
656 unsigned long flags;
657
658 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
659 while (!test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags))
660 wait_cons_dev();
661 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
662 } else
663#endif
664 rc = wait_event_interruptible(raw3270_wait_queue,
665 test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags));
666 if (rc)
667 return rc;
668
669 /*
670 * The device accepted the 'read partition' command. Now
671 * set up a read ccw and issue it.
672 */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200673 rp->init_request.ccw.cmd_code = TC_READMOD;
674 rp->init_request.ccw.flags = CCW_FLAG_SLI;
675 rp->init_request.ccw.count = sizeof(rp->init_data);
676 rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
677 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 if (rc)
679 return rc;
680 /* Got a Query Reply */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200681 count = sizeof(rp->init_data) - rp->init_request.rescnt;
682 uap = (struct raw3270_ua *) (rp->init_data + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 /* Paranoia check. */
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200684 if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 return -EOPNOTSUPP;
686 /* Copy rows/columns of default Usable Area */
687 rp->rows = uap->uab.h;
688 rp->cols = uap->uab.w;
689 /* Check for 14 bit addressing */
690 if ((uap->uab.flags0 & 0x0d) == 0x01)
691 set_bit(RAW3270_FLAGS_14BITADDR, &rp->flags);
692 /* Check for Alternate Usable Area */
693 if (uap->uab.l == sizeof(struct raw3270_ua) &&
694 uap->aua.sdpid == 0x02) {
695 rp->rows = uap->aua.hauai;
696 rp->cols = uap->aua.wauai;
697 }
698 return 0;
699}
700
701static int
702raw3270_size_device(struct raw3270 *rp)
703{
704 int rc;
705
Christoph Hellwigd330f932007-05-31 17:38:04 +0200706 mutex_lock(&raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 rp->view = &raw3270_init_view;
708 raw3270_init_view.dev = rp;
Martin Schwidefsky3863e722005-09-03 15:58:06 -0700709 if (MACHINE_IS_VM)
710 rc = __raw3270_size_device_vm(rp);
711 else
712 rc = __raw3270_size_device(rp);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200713 raw3270_init_view.dev = NULL;
714 rp->view = NULL;
Christoph Hellwigd330f932007-05-31 17:38:04 +0200715 mutex_unlock(&raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 if (rc == 0) { /* Found something. */
717 /* Try to find a model. */
718 rp->model = 0;
719 if (rp->rows == 24 && rp->cols == 80)
720 rp->model = 2;
721 if (rp->rows == 32 && rp->cols == 80)
722 rp->model = 3;
723 if (rp->rows == 43 && rp->cols == 80)
724 rp->model = 4;
725 if (rp->rows == 27 && rp->cols == 132)
726 rp->model = 5;
Martin Schwidefsky3863e722005-09-03 15:58:06 -0700727 } else {
728 /* Couldn't detect size. Use default model 2. */
729 rp->model = 2;
730 rp->rows = 24;
731 rp->cols = 80;
732 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 }
734 return rc;
735}
736
737static int
738raw3270_reset_device(struct raw3270 *rp)
739{
740 int rc;
741
Christoph Hellwigd330f932007-05-31 17:38:04 +0200742 mutex_lock(&raw3270_init_mutex);
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200743 memset(&rp->init_request, 0, sizeof(rp->init_request));
744 memset(&rp->init_data, 0, sizeof(rp->init_data));
745 /* Store reset data stream to init_data/init_request */
746 rp->init_data[0] = TW_KR;
747 INIT_LIST_HEAD(&rp->init_request.list);
748 rp->init_request.ccw.cmd_code = TC_EWRITEA;
749 rp->init_request.ccw.flags = CCW_FLAG_SLI;
750 rp->init_request.ccw.count = 1;
751 rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 rp->view = &raw3270_init_view;
753 raw3270_init_view.dev = rp;
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200754 rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200755 raw3270_init_view.dev = NULL;
756 rp->view = NULL;
Christoph Hellwigd330f932007-05-31 17:38:04 +0200757 mutex_unlock(&raw3270_init_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 return rc;
759}
760
Richard Hitted3cb6f2005-10-30 15:00:10 -0800761int
762raw3270_reset(struct raw3270_view *view)
763{
764 struct raw3270 *rp;
765 int rc;
766
767 rp = view->dev;
768 if (!rp || rp->view != view)
769 rc = -EACCES;
770 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
771 rc = -ENODEV;
772 else
773 rc = raw3270_reset_device(view->dev);
774 return rc;
775}
776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777/*
778 * Setup new 3270 device.
779 */
780static int
781raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
782{
783 struct list_head *l;
784 struct raw3270 *tmp;
785 int minor;
786
787 memset(rp, 0, sizeof(struct raw3270));
788 /* Copy ebcdic -> ascii translation table. */
789 memcpy(ascebc, _ascebc, 256);
790 if (tubxcorrect) {
791 /* correct brackets and circumflex */
792 ascebc['['] = 0xad;
793 ascebc[']'] = 0xbd;
794 ascebc['^'] = 0xb0;
795 }
796 rp->ascebc = ascebc;
797
798 /* Set defaults. */
799 rp->rows = 24;
800 rp->cols = 80;
801
802 INIT_LIST_HEAD(&rp->req_queue);
803 INIT_LIST_HEAD(&rp->view_list);
804
805 /*
806 * Add device to list and find the smallest unused minor
Richard Hitted3cb6f2005-10-30 15:00:10 -0800807 * number for it. Note: there is no device with minor 0,
808 * see special case for fs3270.c:fs3270_open().
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 */
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800810 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 /* Keep the list sorted. */
Richard Hitted3cb6f2005-10-30 15:00:10 -0800812 minor = RAW3270_FIRSTMINOR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 rp->minor = -1;
814 list_for_each(l, &raw3270_devices) {
815 tmp = list_entry(l, struct raw3270, list);
816 if (tmp->minor > minor) {
817 rp->minor = minor;
818 __list_add(&rp->list, l->prev, l);
819 break;
820 }
821 minor++;
822 }
Richard Hitted3cb6f2005-10-30 15:00:10 -0800823 if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 rp->minor = minor;
825 list_add_tail(&rp->list, &raw3270_devices);
826 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800827 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 /* No free minor number? Then give up. */
829 if (rp->minor == -1)
830 return -EUSERS;
831 rp->cdev = cdev;
832 cdev->dev.driver_data = rp;
833 cdev->handler = raw3270_irq;
834 return 0;
835}
836
837#ifdef CONFIG_TN3270_CONSOLE
838/*
839 * Setup 3270 device configured as console.
840 */
Heiko Carstense62133b2007-07-27 12:29:13 +0200841struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842{
843 struct raw3270 *rp;
844 char *ascebc;
845 int rc;
846
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200847 rp = (struct raw3270 *) alloc_bootmem_low(sizeof(struct raw3270));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 ascebc = (char *) alloc_bootmem(256);
849 rc = raw3270_setup_device(cdev, rp, ascebc);
850 if (rc)
851 return ERR_PTR(rc);
852 set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
853 rc = raw3270_reset_device(rp);
854 if (rc)
855 return ERR_PTR(rc);
856 rc = raw3270_size_device(rp);
857 if (rc)
858 return ERR_PTR(rc);
859 rc = raw3270_reset_device(rp);
860 if (rc)
861 return ERR_PTR(rc);
862 set_bit(RAW3270_FLAGS_READY, &rp->flags);
863 return rp;
864}
865
866void
867raw3270_wait_cons_dev(struct raw3270 *rp)
868{
869 unsigned long flags;
870
871 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
872 wait_cons_dev();
873 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
874}
875
876#endif
877
878/*
879 * Create a 3270 device structure.
880 */
881static struct raw3270 *
882raw3270_create_device(struct ccw_device *cdev)
883{
884 struct raw3270 *rp;
885 char *ascebc;
886 int rc;
887
Martin Schwidefsky132fab12006-06-29 14:57:39 +0200888 rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 if (!rp)
890 return ERR_PTR(-ENOMEM);
891 ascebc = kmalloc(256, GFP_KERNEL);
892 if (!ascebc) {
893 kfree(rp);
894 return ERR_PTR(-ENOMEM);
895 }
896 rc = raw3270_setup_device(cdev, rp, ascebc);
897 if (rc) {
898 kfree(rp->ascebc);
899 kfree(rp);
900 rp = ERR_PTR(rc);
901 }
902 /* Get reference to ccw_device structure. */
903 get_device(&cdev->dev);
904 return rp;
905}
906
907/*
908 * Activate a view.
909 */
910int
911raw3270_activate_view(struct raw3270_view *view)
912{
913 struct raw3270 *rp;
914 struct raw3270_view *oldview, *nv;
915 unsigned long flags;
916 int rc;
917
918 rp = view->dev;
919 if (!rp)
920 return -ENODEV;
921 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
922 if (rp->view == view)
923 rc = 0;
924 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
925 rc = -ENODEV;
926 else {
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200927 oldview = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928 if (rp->view) {
929 oldview = rp->view;
930 oldview->fn->deactivate(oldview);
931 }
932 rp->view = view;
933 rc = view->fn->activate(view);
934 if (rc) {
935 /* Didn't work. Try to reactivate the old view. */
936 rp->view = oldview;
937 if (!oldview || oldview->fn->activate(oldview) != 0) {
938 /* Didn't work as well. Try any other view. */
939 list_for_each_entry(nv, &rp->view_list, list)
940 if (nv != view && nv != oldview) {
941 rp->view = nv;
942 if (nv->fn->activate(nv) == 0)
943 break;
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200944 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 }
946 }
947 }
948 }
949 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
950 return rc;
951}
952
953/*
954 * Deactivate current view.
955 */
956void
957raw3270_deactivate_view(struct raw3270_view *view)
958{
959 unsigned long flags;
960 struct raw3270 *rp;
961
962 rp = view->dev;
963 if (!rp)
964 return;
965 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
966 if (rp->view == view) {
967 view->fn->deactivate(view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200968 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 /* Move deactivated view to end of list. */
970 list_del_init(&view->list);
971 list_add_tail(&view->list, &rp->view_list);
972 /* Try to activate another view. */
973 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
Richard Hitted3cb6f2005-10-30 15:00:10 -0800974 list_for_each_entry(view, &rp->view_list, list) {
975 rp->view = view;
976 if (view->fn->activate(view) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 break;
Heiko Carstensd2c993d2006-07-12 16:41:55 +0200978 rp->view = NULL;
Richard Hitted3cb6f2005-10-30 15:00:10 -0800979 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 }
981 }
982 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
983}
984
985/*
986 * Add view to device with minor "minor".
987 */
988int
989raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
990{
991 unsigned long flags;
992 struct raw3270 *rp;
993 int rc;
994
Richard Hitted3cb6f2005-10-30 15:00:10 -0800995 if (minor <= 0)
996 return -ENODEV;
Ingo Molnar14cc3e22006-03-26 01:37:14 -0800997 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 rc = -ENODEV;
999 list_for_each_entry(rp, &raw3270_devices, list) {
1000 if (rp->minor != minor)
1001 continue;
1002 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1003 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
1004 atomic_set(&view->ref_count, 2);
1005 view->dev = rp;
1006 view->fn = fn;
1007 view->model = rp->model;
1008 view->rows = rp->rows;
1009 view->cols = rp->cols;
1010 view->ascebc = rp->ascebc;
1011 spin_lock_init(&view->lock);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001012 list_add(&view->list, &rp->view_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 rc = 0;
1014 }
1015 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1016 break;
1017 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001018 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return rc;
1020}
1021
1022/*
1023 * Find specific view of device with minor "minor".
1024 */
1025struct raw3270_view *
1026raw3270_find_view(struct raw3270_fn *fn, int minor)
1027{
1028 struct raw3270 *rp;
1029 struct raw3270_view *view, *tmp;
1030 unsigned long flags;
1031
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001032 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 view = ERR_PTR(-ENODEV);
1034 list_for_each_entry(rp, &raw3270_devices, list) {
1035 if (rp->minor != minor)
1036 continue;
1037 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1038 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
1039 view = ERR_PTR(-ENOENT);
1040 list_for_each_entry(tmp, &rp->view_list, list) {
1041 if (tmp->fn == fn) {
1042 raw3270_get_view(tmp);
1043 view = tmp;
1044 break;
1045 }
1046 }
1047 }
1048 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1049 break;
1050 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001051 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 return view;
1053}
1054
1055/*
1056 * Remove view from device and free view structure via call to view->fn->free.
1057 */
1058void
1059raw3270_del_view(struct raw3270_view *view)
1060{
1061 unsigned long flags;
1062 struct raw3270 *rp;
1063 struct raw3270_view *nv;
1064
1065 rp = view->dev;
1066 spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1067 if (rp->view == view) {
1068 view->fn->deactivate(view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001069 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 }
1071 list_del_init(&view->list);
1072 if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
1073 /* Try to activate another view. */
1074 list_for_each_entry(nv, &rp->view_list, list) {
Richard Hitted3cb6f2005-10-30 15:00:10 -08001075 if (nv->fn->activate(nv) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 rp->view = nv;
1077 break;
1078 }
1079 }
1080 }
1081 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1082 /* Wait for reference counter to drop to zero. */
1083 atomic_dec(&view->ref_count);
1084 wait_event(raw3270_wait_queue, atomic_read(&view->ref_count) == 0);
1085 if (view->fn->free)
1086 view->fn->free(view);
1087}
1088
1089/*
1090 * Remove a 3270 device structure.
1091 */
1092static void
1093raw3270_delete_device(struct raw3270 *rp)
1094{
1095 struct ccw_device *cdev;
1096
1097 /* Remove from device chain. */
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001098 mutex_lock(&raw3270_mutex);
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001099 if (rp->clttydev && !IS_ERR(rp->clttydev))
Cornelia Huck7f021ce2007-10-22 12:52:42 +02001100 device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001101 if (rp->cltubdev && !IS_ERR(rp->cltubdev))
Cornelia Huck7f021ce2007-10-22 12:52:42 +02001102 device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, rp->minor));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 list_del_init(&rp->list);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001104 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
1106 /* Disconnect from ccw_device. */
1107 cdev = rp->cdev;
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001108 rp->cdev = NULL;
1109 cdev->dev.driver_data = NULL;
1110 cdev->handler = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112 /* Put ccw_device structure. */
1113 put_device(&cdev->dev);
1114
1115 /* Now free raw3270 structure. */
1116 kfree(rp->ascebc);
1117 kfree(rp);
1118}
1119
1120static int
1121raw3270_probe (struct ccw_device *cdev)
1122{
1123 return 0;
1124}
1125
1126/*
1127 * Additional attributes for a 3270 device
1128 */
1129static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001130raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131{
1132 return snprintf(buf, PAGE_SIZE, "%i\n",
1133 ((struct raw3270 *) dev->driver_data)->model);
1134}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001135static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136
1137static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001138raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139{
1140 return snprintf(buf, PAGE_SIZE, "%i\n",
1141 ((struct raw3270 *) dev->driver_data)->rows);
1142}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001143static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
1145static ssize_t
Yani Ioannou3fd3c0a2005-05-17 06:43:27 -04001146raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147{
1148 return snprintf(buf, PAGE_SIZE, "%i\n",
1149 ((struct raw3270 *) dev->driver_data)->cols);
1150}
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001151static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
1153static struct attribute * raw3270_attrs[] = {
1154 &dev_attr_model.attr,
1155 &dev_attr_rows.attr,
1156 &dev_attr_columns.attr,
1157 NULL,
1158};
1159
1160static struct attribute_group raw3270_attr_group = {
1161 .attrs = raw3270_attrs,
1162};
1163
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001164static int raw3270_create_attributes(struct raw3270 *rp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165{
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001166 int rc;
1167
1168 rc = sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
1169 if (rc)
1170 goto out;
1171
Cornelia Huck7f021ce2007-10-22 12:52:42 +02001172 rp->clttydev = device_create(class3270, &rp->cdev->dev,
1173 MKDEV(IBM_TTY3270_MAJOR, rp->minor),
1174 "tty%s", rp->cdev->dev.bus_id);
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001175 if (IS_ERR(rp->clttydev)) {
1176 rc = PTR_ERR(rp->clttydev);
1177 goto out_ttydev;
1178 }
1179
Cornelia Huck7f021ce2007-10-22 12:52:42 +02001180 rp->cltubdev = device_create(class3270, &rp->cdev->dev,
1181 MKDEV(IBM_FS3270_MAJOR, rp->minor),
1182 "tub%s", rp->cdev->dev.bus_id);
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001183 if (!IS_ERR(rp->cltubdev))
1184 goto out;
1185
1186 rc = PTR_ERR(rp->cltubdev);
Cornelia Huck7f021ce2007-10-22 12:52:42 +02001187 device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001188
1189out_ttydev:
1190 sysfs_remove_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
1191out:
1192 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193}
1194
1195/*
1196 * Notifier for device addition/removal
1197 */
1198struct raw3270_notifier {
1199 struct list_head list;
1200 void (*notifier)(int, int);
1201};
1202
Denis Chengc11ca972008-01-26 14:11:13 +01001203static LIST_HEAD(raw3270_notifier);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
1205int raw3270_register_notifier(void (*notifier)(int, int))
1206{
1207 struct raw3270_notifier *np;
1208 struct raw3270 *rp;
1209
1210 np = kmalloc(sizeof(struct raw3270_notifier), GFP_KERNEL);
1211 if (!np)
1212 return -ENOMEM;
1213 np->notifier = notifier;
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001214 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 list_add_tail(&np->list, &raw3270_notifier);
1216 list_for_each_entry(rp, &raw3270_devices, list) {
1217 get_device(&rp->cdev->dev);
1218 notifier(rp->minor, 1);
1219 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001220 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 return 0;
1222}
1223
1224void raw3270_unregister_notifier(void (*notifier)(int, int))
1225{
1226 struct raw3270_notifier *np;
1227
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001228 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 list_for_each_entry(np, &raw3270_notifier, list)
1230 if (np->notifier == notifier) {
1231 list_del(&np->list);
1232 kfree(np);
1233 break;
1234 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001235 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236}
1237
1238/*
1239 * Set 3270 device online.
1240 */
1241static int
1242raw3270_set_online (struct ccw_device *cdev)
1243{
1244 struct raw3270 *rp;
1245 struct raw3270_notifier *np;
1246 int rc;
1247
1248 rp = raw3270_create_device(cdev);
1249 if (IS_ERR(rp))
1250 return PTR_ERR(rp);
1251 rc = raw3270_reset_device(rp);
1252 if (rc)
Richard Hitted3cb6f2005-10-30 15:00:10 -08001253 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 rc = raw3270_size_device(rp);
1255 if (rc)
Richard Hitted3cb6f2005-10-30 15:00:10 -08001256 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 rc = raw3270_reset_device(rp);
1258 if (rc)
Richard Hitted3cb6f2005-10-30 15:00:10 -08001259 goto failure;
Heiko Carstensd7cf0d52006-07-18 13:46:58 +02001260 rc = raw3270_create_attributes(rp);
1261 if (rc)
1262 goto failure;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 set_bit(RAW3270_FLAGS_READY, &rp->flags);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001264 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 list_for_each_entry(np, &raw3270_notifier, list)
1266 np->notifier(rp->minor, 1);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001267 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268 return 0;
Richard Hitted3cb6f2005-10-30 15:00:10 -08001269
1270failure:
1271 raw3270_delete_device(rp);
1272 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273}
1274
1275/*
1276 * Remove 3270 device structure.
1277 */
1278static void
1279raw3270_remove (struct ccw_device *cdev)
1280{
1281 unsigned long flags;
1282 struct raw3270 *rp;
1283 struct raw3270_view *v;
1284 struct raw3270_notifier *np;
1285
1286 rp = cdev->dev.driver_data;
Richard Hitted3cb6f2005-10-30 15:00:10 -08001287 /*
1288 * _remove is the opposite of _probe; it's probe that
1289 * should set up rp. raw3270_remove gets entered for
1290 * devices even if they haven't been varied online.
1291 * Thus, rp may validly be NULL here.
1292 */
1293 if (rp == NULL)
1294 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 clear_bit(RAW3270_FLAGS_READY, &rp->flags);
1296
1297 sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
1298
1299 /* Deactivate current view and remove all views. */
1300 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1301 if (rp->view) {
1302 rp->view->fn->deactivate(rp->view);
Heiko Carstensd2c993d2006-07-12 16:41:55 +02001303 rp->view = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 }
1305 while (!list_empty(&rp->view_list)) {
1306 v = list_entry(rp->view_list.next, struct raw3270_view, list);
1307 if (v->fn->release)
1308 v->fn->release(v);
1309 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
1310 raw3270_del_view(v);
1311 spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1312 }
1313 spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
1314
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001315 mutex_lock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 list_for_each_entry(np, &raw3270_notifier, list)
1317 np->notifier(rp->minor, 0);
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001318 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319
1320 /* Reset 3270 device. */
1321 raw3270_reset_device(rp);
1322 /* And finally remove it. */
1323 raw3270_delete_device(rp);
1324}
1325
1326/*
1327 * Set 3270 device offline.
1328 */
1329static int
1330raw3270_set_offline (struct ccw_device *cdev)
1331{
1332 struct raw3270 *rp;
1333
1334 rp = cdev->dev.driver_data;
1335 if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags))
1336 return -EBUSY;
1337 raw3270_remove(cdev);
1338 return 0;
1339}
1340
1341static struct ccw_device_id raw3270_id[] = {
1342 { CCW_DEVICE(0x3270, 0) },
1343 { CCW_DEVICE(0x3271, 0) },
1344 { CCW_DEVICE(0x3272, 0) },
1345 { CCW_DEVICE(0x3273, 0) },
1346 { CCW_DEVICE(0x3274, 0) },
1347 { CCW_DEVICE(0x3275, 0) },
1348 { CCW_DEVICE(0x3276, 0) },
1349 { CCW_DEVICE(0x3277, 0) },
1350 { CCW_DEVICE(0x3278, 0) },
1351 { CCW_DEVICE(0x3279, 0) },
1352 { CCW_DEVICE(0x3174, 0) },
1353 { /* end of list */ },
1354};
1355
1356static struct ccw_driver raw3270_ccw_driver = {
1357 .name = "3270",
1358 .owner = THIS_MODULE,
1359 .ids = raw3270_id,
1360 .probe = &raw3270_probe,
1361 .remove = &raw3270_remove,
1362 .set_online = &raw3270_set_online,
1363 .set_offline = &raw3270_set_offline,
1364};
1365
1366static int
1367raw3270_init(void)
1368{
1369 struct raw3270 *rp;
1370 int rc;
1371
1372 if (raw3270_registered)
1373 return 0;
1374 raw3270_registered = 1;
1375 rc = ccw_driver_register(&raw3270_ccw_driver);
1376 if (rc == 0) {
1377 /* Create attributes for early (= console) device. */
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001378 mutex_lock(&raw3270_mutex);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001379 class3270 = class_create(THIS_MODULE, "3270");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 list_for_each_entry(rp, &raw3270_devices, list) {
1381 get_device(&rp->cdev->dev);
1382 raw3270_create_attributes(rp);
1383 }
Ingo Molnar14cc3e22006-03-26 01:37:14 -08001384 mutex_unlock(&raw3270_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 }
1386 return rc;
1387}
1388
1389static void
1390raw3270_exit(void)
1391{
1392 ccw_driver_unregister(&raw3270_ccw_driver);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001393 class_destroy(class3270);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394}
1395
1396MODULE_LICENSE("GPL");
1397
1398module_init(raw3270_init);
1399module_exit(raw3270_exit);
1400
1401EXPORT_SYMBOL(raw3270_request_alloc);
1402EXPORT_SYMBOL(raw3270_request_free);
1403EXPORT_SYMBOL(raw3270_request_reset);
1404EXPORT_SYMBOL(raw3270_request_set_cmd);
1405EXPORT_SYMBOL(raw3270_request_add_data);
1406EXPORT_SYMBOL(raw3270_request_set_data);
1407EXPORT_SYMBOL(raw3270_request_set_idal);
1408EXPORT_SYMBOL(raw3270_buffer_address);
1409EXPORT_SYMBOL(raw3270_add_view);
1410EXPORT_SYMBOL(raw3270_del_view);
1411EXPORT_SYMBOL(raw3270_find_view);
1412EXPORT_SYMBOL(raw3270_activate_view);
1413EXPORT_SYMBOL(raw3270_deactivate_view);
1414EXPORT_SYMBOL(raw3270_start);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001415EXPORT_SYMBOL(raw3270_start_locked);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416EXPORT_SYMBOL(raw3270_start_irq);
Richard Hitted3cb6f2005-10-30 15:00:10 -08001417EXPORT_SYMBOL(raw3270_reset);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418EXPORT_SYMBOL(raw3270_register_notifier);
1419EXPORT_SYMBOL(raw3270_unregister_notifier);
1420EXPORT_SYMBOL(raw3270_wait_queue);