16f05e69eSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * IBM/3270 Driver - core functions.
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Author(s):
61da177e4SLinus Torvalds * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
71da177e4SLinus Torvalds * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
84b214a0cSMartin Schwidefsky * Copyright IBM Corp. 2003, 2009
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #include <linux/module.h>
121da177e4SLinus Torvalds #include <linux/err.h>
131da177e4SLinus Torvalds #include <linux/init.h>
141da177e4SLinus Torvalds #include <linux/interrupt.h>
151da177e4SLinus Torvalds #include <linux/list.h>
161da177e4SLinus Torvalds #include <linux/slab.h>
171da177e4SLinus Torvalds #include <linux/types.h>
181da177e4SLinus Torvalds #include <linux/wait.h>
191da177e4SLinus Torvalds
201da177e4SLinus Torvalds #include <asm/ccwdev.h>
211da177e4SLinus Torvalds #include <asm/cio.h>
221da177e4SLinus Torvalds #include <asm/ebcdic.h>
230a87c5cfSMichael Holzheu #include <asm/diag.h>
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds #include "raw3270.h"
261da177e4SLinus Torvalds
27ed3cb6f0SRichard Hitt #include <linux/major.h>
28ed3cb6f0SRichard Hitt #include <linux/kdev_t.h>
29ed3cb6f0SRichard Hitt #include <linux/device.h>
3014cc3e2bSIngo Molnar #include <linux/mutex.h>
31ed3cb6f0SRichard Hitt
32c95571e6SMartin Schwidefsky struct class *class3270;
33754f66b5SSven Schnelle EXPORT_SYMBOL(class3270);
34ed3cb6f0SRichard Hitt
351da177e4SLinus Torvalds /* The main 3270 data structure. */
361da177e4SLinus Torvalds struct raw3270 {
371da177e4SLinus Torvalds struct list_head list;
381da177e4SLinus Torvalds struct ccw_device *cdev;
391da177e4SLinus Torvalds int minor;
401da177e4SLinus Torvalds
4191621ba7SSven Schnelle int model, rows, cols;
4291621ba7SSven Schnelle int old_model, old_rows, old_cols;
434d334fd1SMartin Schwidefsky unsigned int state;
441da177e4SLinus Torvalds unsigned long flags;
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds struct list_head req_queue; /* Request queue. */
471da177e4SLinus Torvalds struct list_head view_list; /* List of available views. */
481da177e4SLinus Torvalds struct raw3270_view *view; /* Active view. */
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds struct timer_list timer; /* Device timer. */
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds unsigned char *ascebc; /* ascii -> ebcdic table */
53132fab13SMartin Schwidefsky
544d334fd1SMartin Schwidefsky struct raw3270_view init_view;
554d334fd1SMartin Schwidefsky struct raw3270_request init_reset;
564d334fd1SMartin Schwidefsky struct raw3270_request init_readpart;
574d334fd1SMartin Schwidefsky struct raw3270_request init_readmod;
58132fab13SMartin Schwidefsky unsigned char init_data[256];
5991621ba7SSven Schnelle struct work_struct resize_work;
601da177e4SLinus Torvalds };
611da177e4SLinus Torvalds
624d334fd1SMartin Schwidefsky /* raw3270->state */
634d334fd1SMartin Schwidefsky #define RAW3270_STATE_INIT 0 /* Initial state */
644d334fd1SMartin Schwidefsky #define RAW3270_STATE_RESET 1 /* Reset command is pending */
654d334fd1SMartin Schwidefsky #define RAW3270_STATE_W4ATTN 2 /* Wait for attention interrupt */
664d334fd1SMartin Schwidefsky #define RAW3270_STATE_READMOD 3 /* Read partition is pending */
674d334fd1SMartin Schwidefsky #define RAW3270_STATE_READY 4 /* Device is usable by views */
684d334fd1SMartin Schwidefsky
691da177e4SLinus Torvalds /* raw3270->flags */
701da177e4SLinus Torvalds #define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */
711da177e4SLinus Torvalds #define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */
724d334fd1SMartin Schwidefsky #define RAW3270_FLAGS_CONSOLE 2 /* Device is the console. */
731da177e4SLinus Torvalds
741da177e4SLinus Torvalds /* Semaphore to protect global data of raw3270 (devices, views, etc). */
7514cc3e2bSIngo Molnar static DEFINE_MUTEX(raw3270_mutex);
761da177e4SLinus Torvalds
771da177e4SLinus Torvalds /* List of 3270 devices. */
78c11ca97eSDenis Cheng static LIST_HEAD(raw3270_devices);
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds /*
811da177e4SLinus Torvalds * Flag to indicate if the driver has been registered. Some operations
821da177e4SLinus Torvalds * like waiting for the end of i/o need to be done differently as long
831da177e4SLinus Torvalds * as the kernel is still starting up (console support).
841da177e4SLinus Torvalds */
851da177e4SLinus Torvalds static int raw3270_registered;
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds /* Module parameters */
88970ba6acSHeiko Carstens static bool tubxcorrect;
891da177e4SLinus Torvalds module_param(tubxcorrect, bool, 0);
901da177e4SLinus Torvalds
911da177e4SLinus Torvalds /*
921da177e4SLinus Torvalds * Wait queue for device init/delete, view delete.
931da177e4SLinus Torvalds */
941da177e4SLinus Torvalds DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
95754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_wait_queue);
961da177e4SLinus Torvalds
977e36eff1SMartin Schwidefsky static void __raw3270_disconnect(struct raw3270 *rp);
987e36eff1SMartin Schwidefsky
991da177e4SLinus Torvalds /*
1001da177e4SLinus Torvalds * Encode array for 12 bit 3270 addresses.
1011da177e4SLinus Torvalds */
1022b67fc46SHeiko Carstens static unsigned char raw3270_ebcgraf[64] = {
1031da177e4SLinus Torvalds 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
1041da177e4SLinus Torvalds 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1051da177e4SLinus Torvalds 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
1061da177e4SLinus Torvalds 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
1071da177e4SLinus Torvalds 0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
1081da177e4SLinus Torvalds 0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
1091da177e4SLinus Torvalds 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
1101da177e4SLinus Torvalds 0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
1111da177e4SLinus Torvalds };
1121da177e4SLinus Torvalds
raw3270_state_ready(struct raw3270 * rp)1134d334fd1SMartin Schwidefsky static inline int raw3270_state_ready(struct raw3270 *rp)
1144d334fd1SMartin Schwidefsky {
1154d334fd1SMartin Schwidefsky return rp->state == RAW3270_STATE_READY;
1164d334fd1SMartin Schwidefsky }
1174d334fd1SMartin Schwidefsky
raw3270_buffer_address(struct raw3270 * rp,char * cp,int x,int y)118f77f936aSSven Schnelle void raw3270_buffer_address(struct raw3270 *rp, char *cp, int x, int y)
1191da177e4SLinus Torvalds {
120f77f936aSSven Schnelle int addr;
121f77f936aSSven Schnelle
122f77f936aSSven Schnelle if (x < 0)
123f77f936aSSven Schnelle x = max_t(int, 0, rp->view->cols + x);
124f77f936aSSven Schnelle if (y < 0)
125f77f936aSSven Schnelle y = max_t(int, 0, rp->view->rows + y);
126f77f936aSSven Schnelle addr = (y * rp->view->cols) + x;
1271da177e4SLinus Torvalds if (test_bit(RAW3270_FLAGS_14BITADDR, &rp->flags)) {
1281da177e4SLinus Torvalds cp[0] = (addr >> 8) & 0x3f;
1291da177e4SLinus Torvalds cp[1] = addr & 0xff;
1301da177e4SLinus Torvalds } else {
1311da177e4SLinus Torvalds cp[0] = raw3270_ebcgraf[(addr >> 6) & 0x3f];
1321da177e4SLinus Torvalds cp[1] = raw3270_ebcgraf[addr & 0x3f];
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds }
135754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_buffer_address);
1361da177e4SLinus Torvalds
1371da177e4SLinus Torvalds /*
1381da177e4SLinus Torvalds * Allocate a new 3270 ccw request
1391da177e4SLinus Torvalds */
raw3270_request_alloc(size_t size)14013d4999aSSven Schnelle struct raw3270_request *raw3270_request_alloc(size_t size)
1411da177e4SLinus Torvalds {
1421da177e4SLinus Torvalds struct raw3270_request *rq;
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds /* Allocate request structure */
145ff61744cSSven Schnelle rq = kzalloc(sizeof(*rq), GFP_KERNEL | GFP_DMA);
1461da177e4SLinus Torvalds if (!rq)
1471da177e4SLinus Torvalds return ERR_PTR(-ENOMEM);
1481da177e4SLinus Torvalds
1491da177e4SLinus Torvalds /* alloc output buffer. */
1501da177e4SLinus Torvalds if (size > 0) {
1511da177e4SLinus Torvalds rq->buffer = kmalloc(size, GFP_KERNEL | GFP_DMA);
1521da177e4SLinus Torvalds if (!rq->buffer) {
1531da177e4SLinus Torvalds kfree(rq);
1541da177e4SLinus Torvalds return ERR_PTR(-ENOMEM);
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds rq->size = size;
1581da177e4SLinus Torvalds INIT_LIST_HEAD(&rq->list);
1591da177e4SLinus Torvalds
1601da177e4SLinus Torvalds /*
1611da177e4SLinus Torvalds * Setup ccw.
1621da177e4SLinus Torvalds */
1631da177e4SLinus Torvalds rq->ccw.cda = __pa(rq->buffer);
1641da177e4SLinus Torvalds rq->ccw.flags = CCW_FLAG_SLI;
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds return rq;
1671da177e4SLinus Torvalds }
168754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_request_alloc);
1691da177e4SLinus Torvalds
1701da177e4SLinus Torvalds /*
1711da177e4SLinus Torvalds * Free 3270 ccw request
1721da177e4SLinus Torvalds */
raw3270_request_free(struct raw3270_request * rq)17313d4999aSSven Schnelle void raw3270_request_free(struct raw3270_request *rq)
1741da177e4SLinus Torvalds {
1751da177e4SLinus Torvalds kfree(rq->buffer);
1761da177e4SLinus Torvalds kfree(rq);
1771da177e4SLinus Torvalds }
178754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_request_free);
1791da177e4SLinus Torvalds
1801da177e4SLinus Torvalds /*
1811da177e4SLinus Torvalds * Reset request to initial state.
1821da177e4SLinus Torvalds */
raw3270_request_reset(struct raw3270_request * rq)1837aeeeb92SSven Schnelle int raw3270_request_reset(struct raw3270_request *rq)
1841da177e4SLinus Torvalds {
1857aeeeb92SSven Schnelle if (WARN_ON_ONCE(!list_empty(&rq->list)))
1867aeeeb92SSven Schnelle return -EBUSY;
1871da177e4SLinus Torvalds rq->ccw.cmd_code = 0;
1881da177e4SLinus Torvalds rq->ccw.count = 0;
1891da177e4SLinus Torvalds rq->ccw.cda = __pa(rq->buffer);
1901da177e4SLinus Torvalds rq->ccw.flags = CCW_FLAG_SLI;
1911da177e4SLinus Torvalds rq->rescnt = 0;
1921da177e4SLinus Torvalds rq->rc = 0;
1937aeeeb92SSven Schnelle return 0;
1941da177e4SLinus Torvalds }
195754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_request_reset);
1961da177e4SLinus Torvalds
1971da177e4SLinus Torvalds /*
1981da177e4SLinus Torvalds * Set command code to ccw of a request.
1991da177e4SLinus Torvalds */
raw3270_request_set_cmd(struct raw3270_request * rq,u8 cmd)20013d4999aSSven Schnelle void raw3270_request_set_cmd(struct raw3270_request *rq, u8 cmd)
2011da177e4SLinus Torvalds {
2021da177e4SLinus Torvalds rq->ccw.cmd_code = cmd;
2031da177e4SLinus Torvalds }
204754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_request_set_cmd);
2051da177e4SLinus Torvalds
2061da177e4SLinus Torvalds /*
2071da177e4SLinus Torvalds * Add data fragment to output buffer.
2081da177e4SLinus Torvalds */
raw3270_request_add_data(struct raw3270_request * rq,void * data,size_t size)20913d4999aSSven Schnelle int raw3270_request_add_data(struct raw3270_request *rq, void *data, size_t size)
2101da177e4SLinus Torvalds {
2111da177e4SLinus Torvalds if (size + rq->ccw.count > rq->size)
2121da177e4SLinus Torvalds return -E2BIG;
2131da177e4SLinus Torvalds memcpy(rq->buffer + rq->ccw.count, data, size);
2141da177e4SLinus Torvalds rq->ccw.count += size;
2151da177e4SLinus Torvalds return 0;
2161da177e4SLinus Torvalds }
217754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_request_add_data);
2181da177e4SLinus Torvalds
2191da177e4SLinus Torvalds /*
2201da177e4SLinus Torvalds * Set address/length pair to ccw of a request.
2211da177e4SLinus Torvalds */
raw3270_request_set_data(struct raw3270_request * rq,void * data,size_t size)22213d4999aSSven Schnelle void raw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size)
2231da177e4SLinus Torvalds {
2241da177e4SLinus Torvalds rq->ccw.cda = __pa(data);
2251da177e4SLinus Torvalds rq->ccw.count = size;
2261da177e4SLinus Torvalds }
227754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_request_set_data);
2281da177e4SLinus Torvalds
2291da177e4SLinus Torvalds /*
2301da177e4SLinus Torvalds * Set idal buffer to ccw of a request.
2311da177e4SLinus Torvalds */
raw3270_request_set_idal(struct raw3270_request * rq,struct idal_buffer * ib)23213d4999aSSven Schnelle void raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
2331da177e4SLinus Torvalds {
2341da177e4SLinus Torvalds rq->ccw.cda = __pa(ib->data);
2351da177e4SLinus Torvalds rq->ccw.count = ib->size;
2361da177e4SLinus Torvalds rq->ccw.flags |= CCW_FLAG_IDA;
2371da177e4SLinus Torvalds }
238754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_request_set_idal);
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvalds /*
2411da177e4SLinus Torvalds * Add the request to the request queue, try to start it if the
2421da177e4SLinus Torvalds * 3270 device is idle. Return without waiting for end of i/o.
2431da177e4SLinus Torvalds */
__raw3270_start(struct raw3270 * rp,struct raw3270_view * view,struct raw3270_request * rq)24413d4999aSSven Schnelle static int __raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
2451da177e4SLinus Torvalds struct raw3270_request *rq)
2461da177e4SLinus Torvalds {
2471da177e4SLinus Torvalds rq->view = view;
2481da177e4SLinus Torvalds raw3270_get_view(view);
2491da177e4SLinus Torvalds if (list_empty(&rp->req_queue) &&
2501da177e4SLinus Torvalds !test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {
2511da177e4SLinus Torvalds /* No other requests are on the queue. Start this one. */
2521da177e4SLinus Torvalds rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
2531da177e4SLinus Torvalds (unsigned long)rq, 0, 0);
2541da177e4SLinus Torvalds if (rq->rc) {
2551da177e4SLinus Torvalds raw3270_put_view(view);
2561da177e4SLinus Torvalds return rq->rc;
2571da177e4SLinus Torvalds }
2581da177e4SLinus Torvalds }
2591da177e4SLinus Torvalds list_add_tail(&rq->list, &rp->req_queue);
2601da177e4SLinus Torvalds return 0;
2611da177e4SLinus Torvalds }
2621da177e4SLinus Torvalds
raw3270_view_active(struct raw3270_view * view)26313d4999aSSven Schnelle int raw3270_view_active(struct raw3270_view *view)
264233faec9SMartin Schwidefsky {
265233faec9SMartin Schwidefsky struct raw3270 *rp = view->dev;
266233faec9SMartin Schwidefsky
2671cf69b7bSVineeth Vijayan return rp && rp->view == view;
268233faec9SMartin Schwidefsky }
269233faec9SMartin Schwidefsky
raw3270_start(struct raw3270_view * view,struct raw3270_request * rq)27013d4999aSSven Schnelle int raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
2711da177e4SLinus Torvalds {
2721da177e4SLinus Torvalds unsigned long flags;
2731da177e4SLinus Torvalds struct raw3270 *rp;
2741da177e4SLinus Torvalds int rc;
2751da177e4SLinus Torvalds
2761da177e4SLinus Torvalds spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
2771da177e4SLinus Torvalds rp = view->dev;
2781cf69b7bSVineeth Vijayan if (!rp || rp->view != view)
2791da177e4SLinus Torvalds rc = -EACCES;
2804d334fd1SMartin Schwidefsky else if (!raw3270_state_ready(rp))
2814d334fd1SMartin Schwidefsky rc = -EBUSY;
2821da177e4SLinus Torvalds else
2831da177e4SLinus Torvalds rc = __raw3270_start(rp, view, rq);
2841da177e4SLinus Torvalds spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
2851da177e4SLinus Torvalds return rc;
2861da177e4SLinus Torvalds }
287754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_start);
2881da177e4SLinus Torvalds
raw3270_start_request(struct raw3270_view * view,struct raw3270_request * rq,int cmd,void * data,size_t len)289f08e3155SSven Schnelle int raw3270_start_request(struct raw3270_view *view, struct raw3270_request *rq,
290f08e3155SSven Schnelle int cmd, void *data, size_t len)
291f08e3155SSven Schnelle {
292f08e3155SSven Schnelle int rc;
293f08e3155SSven Schnelle
2947aeeeb92SSven Schnelle rc = raw3270_request_reset(rq);
2957aeeeb92SSven Schnelle if (rc)
2967aeeeb92SSven Schnelle return rc;
297f08e3155SSven Schnelle raw3270_request_set_cmd(rq, cmd);
298f08e3155SSven Schnelle rc = raw3270_request_add_data(rq, data, len);
299f08e3155SSven Schnelle if (rc)
300f08e3155SSven Schnelle return rc;
301f08e3155SSven Schnelle return raw3270_start(view, rq);
302f08e3155SSven Schnelle }
303754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_start_request);
304f08e3155SSven Schnelle
raw3270_start_locked(struct raw3270_view * view,struct raw3270_request * rq)30513d4999aSSven Schnelle int raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
306ed3cb6f0SRichard Hitt {
307ed3cb6f0SRichard Hitt struct raw3270 *rp;
308ed3cb6f0SRichard Hitt int rc;
309ed3cb6f0SRichard Hitt
310ed3cb6f0SRichard Hitt rp = view->dev;
3111cf69b7bSVineeth Vijayan if (!rp || rp->view != view)
312ed3cb6f0SRichard Hitt rc = -EACCES;
3134d334fd1SMartin Schwidefsky else if (!raw3270_state_ready(rp))
3144d334fd1SMartin Schwidefsky rc = -EBUSY;
315ed3cb6f0SRichard Hitt else
316ed3cb6f0SRichard Hitt rc = __raw3270_start(rp, view, rq);
317ed3cb6f0SRichard Hitt return rc;
318ed3cb6f0SRichard Hitt }
319754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_start_locked);
320ed3cb6f0SRichard Hitt
raw3270_start_irq(struct raw3270_view * view,struct raw3270_request * rq)32113d4999aSSven Schnelle int raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq)
3221da177e4SLinus Torvalds {
3231da177e4SLinus Torvalds struct raw3270 *rp;
3241da177e4SLinus Torvalds
3251da177e4SLinus Torvalds rp = view->dev;
3261da177e4SLinus Torvalds rq->view = view;
3271da177e4SLinus Torvalds raw3270_get_view(view);
3281da177e4SLinus Torvalds list_add_tail(&rq->list, &rp->req_queue);
3291da177e4SLinus Torvalds return 0;
3301da177e4SLinus Torvalds }
331754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_start_irq);
3321da177e4SLinus Torvalds
3331da177e4SLinus Torvalds /*
3341da177e4SLinus Torvalds * 3270 interrupt routine, called from the ccw_device layer
3351da177e4SLinus Torvalds */
raw3270_irq(struct ccw_device * cdev,unsigned long intparm,struct irb * irb)33613d4999aSSven Schnelle static void raw3270_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
3371da177e4SLinus Torvalds {
3381da177e4SLinus Torvalds struct raw3270 *rp;
3391da177e4SLinus Torvalds struct raw3270_view *view;
3401da177e4SLinus Torvalds struct raw3270_request *rq;
3411da177e4SLinus Torvalds
342dff59b64SGreg Kroah-Hartman rp = dev_get_drvdata(&cdev->dev);
3431da177e4SLinus Torvalds if (!rp)
3441da177e4SLinus Torvalds return;
3451da177e4SLinus Torvalds rq = (struct raw3270_request *)intparm;
3461da177e4SLinus Torvalds view = rq ? rq->view : rp->view;
3471da177e4SLinus Torvalds
3488340ab60SMartin Schwidefsky if (!IS_ERR(irb)) {
3491da177e4SLinus Torvalds /* Handle CE-DE-UE and subsequent UDE */
3508340ab60SMartin Schwidefsky if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END)
3511da177e4SLinus Torvalds clear_bit(RAW3270_FLAGS_BUSY, &rp->flags);
3528340ab60SMartin Schwidefsky if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END |
3538340ab60SMartin Schwidefsky DEV_STAT_DEV_END |
3548340ab60SMartin Schwidefsky DEV_STAT_UNIT_EXCEP))
3558340ab60SMartin Schwidefsky set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
3568340ab60SMartin Schwidefsky /* Handle disconnected devices */
3578340ab60SMartin Schwidefsky if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
3587e36eff1SMartin Schwidefsky (irb->ecw[0] & SNS0_INTERVENTION_REQ)) {
3598340ab60SMartin Schwidefsky set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
3607e36eff1SMartin Schwidefsky if (rp->state > RAW3270_STATE_RESET)
3617e36eff1SMartin Schwidefsky __raw3270_disconnect(rp);
3627e36eff1SMartin Schwidefsky }
3638340ab60SMartin Schwidefsky /* Call interrupt handler of the view */
3648340ab60SMartin Schwidefsky if (view)
3658340ab60SMartin Schwidefsky view->fn->intv(view, rq, irb);
3661da177e4SLinus Torvalds }
3678340ab60SMartin Schwidefsky
3688340ab60SMartin Schwidefsky if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags))
3698340ab60SMartin Schwidefsky /* Device busy, do not start I/O */
3708340ab60SMartin Schwidefsky return;
3718340ab60SMartin Schwidefsky
3727e36eff1SMartin Schwidefsky if (rq && !list_empty(&rq->list)) {
3731da177e4SLinus Torvalds /* The request completed, remove from queue and do callback. */
3741da177e4SLinus Torvalds list_del_init(&rq->list);
3751da177e4SLinus Torvalds if (rq->callback)
3761da177e4SLinus Torvalds rq->callback(rq, rq->callback_data);
3771da177e4SLinus Torvalds /* Do put_device for get_device in raw3270_start. */
3781da177e4SLinus Torvalds raw3270_put_view(view);
3791da177e4SLinus Torvalds }
3808340ab60SMartin Schwidefsky
3811da177e4SLinus Torvalds /*
3821da177e4SLinus Torvalds * Try to start each request on request queue until one is
3831da177e4SLinus Torvalds * started successful.
3841da177e4SLinus Torvalds */
3851da177e4SLinus Torvalds while (!list_empty(&rp->req_queue)) {
3861da177e4SLinus Torvalds rq = list_entry(rp->req_queue.next, struct raw3270_request, list);
3871da177e4SLinus Torvalds rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
3881da177e4SLinus Torvalds (unsigned long)rq, 0, 0);
3891da177e4SLinus Torvalds if (rq->rc == 0)
3901da177e4SLinus Torvalds break;
3911da177e4SLinus Torvalds /* Start failed. Remove request and do callback. */
3921da177e4SLinus Torvalds list_del_init(&rq->list);
3931da177e4SLinus Torvalds if (rq->callback)
3941da177e4SLinus Torvalds rq->callback(rq, rq->callback_data);
3951da177e4SLinus Torvalds /* Do put_device for get_device in raw3270_start. */
3961da177e4SLinus Torvalds raw3270_put_view(view);
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds }
3991da177e4SLinus Torvalds
4001da177e4SLinus Torvalds /*
4014d334fd1SMartin Schwidefsky * To determine the size of the 3270 device we need to do:
4024d334fd1SMartin Schwidefsky * 1) send a 'read partition' data stream to the device
4034d334fd1SMartin Schwidefsky * 2) wait for the attn interrupt that precedes the query reply
4044d334fd1SMartin Schwidefsky * 3) do a read modified to get the query reply
4054d334fd1SMartin Schwidefsky * To make things worse we have to cope with intervention
4064d334fd1SMartin Schwidefsky * required (3270 device switched to 'stand-by') and command
4074d334fd1SMartin Schwidefsky * rejects (old devices that can't do 'read partition').
4081da177e4SLinus Torvalds */
4091da177e4SLinus Torvalds struct raw3270_ua { /* Query Reply structure for Usable Area */
4101da177e4SLinus Torvalds struct { /* Usable Area Query Reply Base */
4111da177e4SLinus Torvalds short l; /* Length of this structured field */
4121da177e4SLinus Torvalds char sfid; /* 0x81 if Query Reply */
4131da177e4SLinus Torvalds char qcode; /* 0x81 if Usable Area */
4141da177e4SLinus Torvalds char flags0;
4151da177e4SLinus Torvalds char flags1;
4161da177e4SLinus Torvalds short w; /* Width of usable area */
4171da177e4SLinus Torvalds short h; /* Heigth of usavle area */
4181da177e4SLinus Torvalds char units; /* 0x00:in; 0x01:mm */
4191da177e4SLinus Torvalds int xr;
4201da177e4SLinus Torvalds int yr;
4211da177e4SLinus Torvalds char aw;
4221da177e4SLinus Torvalds char ah;
4231da177e4SLinus Torvalds short buffsz; /* Character buffer size, bytes */
4241da177e4SLinus Torvalds char xmin;
4251da177e4SLinus Torvalds char ymin;
4261da177e4SLinus Torvalds char xmax;
4271da177e4SLinus Torvalds char ymax;
428562baff5SSven Schnelle } __packed uab;
4291da177e4SLinus Torvalds struct { /* Alternate Usable Area Self-Defining Parameter */
4301da177e4SLinus Torvalds char l; /* Length of this Self-Defining Parm */
4311da177e4SLinus Torvalds char sdpid; /* 0x02 if Alternate Usable Area */
4321da177e4SLinus Torvalds char res;
4331da177e4SLinus Torvalds char auaid; /* 0x01 is Id for the A U A */
4341da177e4SLinus Torvalds short wauai; /* Width of AUAi */
4351da177e4SLinus Torvalds short hauai; /* Height of AUAi */
4361da177e4SLinus Torvalds char auaunits; /* 0x00:in, 0x01:mm */
4371da177e4SLinus Torvalds int auaxr;
4381da177e4SLinus Torvalds int auayr;
4391da177e4SLinus Torvalds char awauai;
4401da177e4SLinus Torvalds char ahauai;
441562baff5SSven Schnelle } __packed aua;
442562baff5SSven Schnelle } __packed;
4431da177e4SLinus Torvalds
raw3270_size_device_vm(struct raw3270 * rp)44413d4999aSSven Schnelle static void raw3270_size_device_vm(struct raw3270 *rp)
4451da177e4SLinus Torvalds {
4461da177e4SLinus Torvalds int rc, model;
4479a92fe48SCornelia Huck struct ccw_dev_id dev_id;
4484d334fd1SMartin Schwidefsky struct diag210 diag_data;
449fbaee746SSven Schnelle struct diag8c diag8c_data;
4501da177e4SLinus Torvalds
4519a92fe48SCornelia Huck ccw_device_get_id(rp->cdev, &dev_id);
452fbaee746SSven Schnelle rc = diag8c(&diag8c_data, &dev_id);
453fbaee746SSven Schnelle if (!rc) {
454fbaee746SSven Schnelle rp->model = 2;
455fbaee746SSven Schnelle rp->rows = diag8c_data.height;
456fbaee746SSven Schnelle rp->cols = diag8c_data.width;
457fbaee746SSven Schnelle if (diag8c_data.flags & 1)
458fbaee746SSven Schnelle set_bit(RAW3270_FLAGS_14BITADDR, &rp->flags);
459fbaee746SSven Schnelle return;
460fbaee746SSven Schnelle }
461fbaee746SSven Schnelle
4624d334fd1SMartin Schwidefsky diag_data.vrdcdvno = dev_id.devno;
4634d334fd1SMartin Schwidefsky diag_data.vrdclen = sizeof(struct diag210);
4644d334fd1SMartin Schwidefsky rc = diag210(&diag_data);
4654d334fd1SMartin Schwidefsky model = diag_data.vrdccrmd;
4664d334fd1SMartin Schwidefsky /* Use default model 2 if the size could not be detected */
4674d334fd1SMartin Schwidefsky if (rc || model < 2 || model > 5)
4684d334fd1SMartin Schwidefsky model = 2;
4691da177e4SLinus Torvalds switch (model) {
4701da177e4SLinus Torvalds case 2:
4711da177e4SLinus Torvalds rp->model = model;
4721da177e4SLinus Torvalds rp->rows = 24;
4731da177e4SLinus Torvalds rp->cols = 80;
4741da177e4SLinus Torvalds break;
4751da177e4SLinus Torvalds case 3:
4761da177e4SLinus Torvalds rp->model = model;
4771da177e4SLinus Torvalds rp->rows = 32;
4781da177e4SLinus Torvalds rp->cols = 80;
4791da177e4SLinus Torvalds break;
4801da177e4SLinus Torvalds case 4:
4811da177e4SLinus Torvalds rp->model = model;
4821da177e4SLinus Torvalds rp->rows = 43;
4831da177e4SLinus Torvalds rp->cols = 80;
4841da177e4SLinus Torvalds break;
4851da177e4SLinus Torvalds case 5:
4861da177e4SLinus Torvalds rp->model = model;
4871da177e4SLinus Torvalds rp->rows = 27;
4881da177e4SLinus Torvalds rp->cols = 132;
4891da177e4SLinus Torvalds break;
4901da177e4SLinus Torvalds }
4911da177e4SLinus Torvalds }
4921da177e4SLinus Torvalds
raw3270_size_device(struct raw3270 * rp,char * init_data)493cbb36313SSven Schnelle static void raw3270_size_device(struct raw3270 *rp, char *init_data)
4941da177e4SLinus Torvalds {
4951da177e4SLinus Torvalds struct raw3270_ua *uap;
4961da177e4SLinus Torvalds
4971da177e4SLinus Torvalds /* Got a Query Reply */
498cbb36313SSven Schnelle uap = (struct raw3270_ua *)(init_data + 1);
4991da177e4SLinus Torvalds /* Paranoia check. */
500cbb36313SSven Schnelle if (init_data[0] != 0x88 || uap->uab.qcode != 0x81) {
5014d334fd1SMartin Schwidefsky /* Couldn't detect size. Use default model 2. */
5024d334fd1SMartin Schwidefsky rp->model = 2;
5034d334fd1SMartin Schwidefsky rp->rows = 24;
5044d334fd1SMartin Schwidefsky rp->cols = 80;
5054d334fd1SMartin Schwidefsky return;
5064d334fd1SMartin Schwidefsky }
5071da177e4SLinus Torvalds /* Copy rows/columns of default Usable Area */
5081da177e4SLinus Torvalds rp->rows = uap->uab.h;
5091da177e4SLinus Torvalds rp->cols = uap->uab.w;
5101da177e4SLinus Torvalds /* Check for 14 bit addressing */
5111da177e4SLinus Torvalds if ((uap->uab.flags0 & 0x0d) == 0x01)
5121da177e4SLinus Torvalds set_bit(RAW3270_FLAGS_14BITADDR, &rp->flags);
5131da177e4SLinus Torvalds /* Check for Alternate Usable Area */
5141da177e4SLinus Torvalds if (uap->uab.l == sizeof(struct raw3270_ua) &&
5151da177e4SLinus Torvalds uap->aua.sdpid == 0x02) {
5161da177e4SLinus Torvalds rp->rows = uap->aua.hauai;
5171da177e4SLinus Torvalds rp->cols = uap->aua.wauai;
5181da177e4SLinus Torvalds }
5191da177e4SLinus Torvalds /* Try to find a model. */
5201da177e4SLinus Torvalds rp->model = 0;
5211da177e4SLinus Torvalds if (rp->rows == 24 && rp->cols == 80)
5221da177e4SLinus Torvalds rp->model = 2;
5231da177e4SLinus Torvalds if (rp->rows == 32 && rp->cols == 80)
5241da177e4SLinus Torvalds rp->model = 3;
5251da177e4SLinus Torvalds if (rp->rows == 43 && rp->cols == 80)
5261da177e4SLinus Torvalds rp->model = 4;
5271da177e4SLinus Torvalds if (rp->rows == 27 && rp->cols == 132)
5281da177e4SLinus Torvalds rp->model = 5;
5291da177e4SLinus Torvalds }
5304d334fd1SMartin Schwidefsky
raw3270_resize_work(struct work_struct * work)53191621ba7SSven Schnelle static void raw3270_resize_work(struct work_struct *work)
5324d334fd1SMartin Schwidefsky {
53391621ba7SSven Schnelle struct raw3270 *rp = container_of(work, struct raw3270, resize_work);
5344d334fd1SMartin Schwidefsky struct raw3270_view *view;
5354d334fd1SMartin Schwidefsky
5364d334fd1SMartin Schwidefsky /* Notify views about new size */
53791621ba7SSven Schnelle list_for_each_entry(view, &rp->view_list, list) {
5384d334fd1SMartin Schwidefsky if (view->fn->resize)
53991621ba7SSven Schnelle view->fn->resize(view, rp->model, rp->rows, rp->cols,
54091621ba7SSven Schnelle rp->old_model, rp->old_rows, rp->old_cols);
54191621ba7SSven Schnelle }
54291621ba7SSven Schnelle rp->old_cols = rp->cols;
54391621ba7SSven Schnelle rp->old_rows = rp->rows;
54491621ba7SSven Schnelle rp->old_model = rp->model;
5454d334fd1SMartin Schwidefsky /* Setup processing done, now activate a view */
5464d334fd1SMartin Schwidefsky list_for_each_entry(view, &rp->view_list, list) {
5474d334fd1SMartin Schwidefsky rp->view = view;
5484d334fd1SMartin Schwidefsky if (view->fn->activate(view) == 0)
5494d334fd1SMartin Schwidefsky break;
5504d334fd1SMartin Schwidefsky rp->view = NULL;
5514d334fd1SMartin Schwidefsky }
5524d334fd1SMartin Schwidefsky }
5534d334fd1SMartin Schwidefsky
raw3270_size_device_done(struct raw3270 * rp)55491621ba7SSven Schnelle static void raw3270_size_device_done(struct raw3270 *rp)
55591621ba7SSven Schnelle {
55691621ba7SSven Schnelle rp->view = NULL;
55791621ba7SSven Schnelle rp->state = RAW3270_STATE_READY;
55891621ba7SSven Schnelle schedule_work(&rp->resize_work);
55991621ba7SSven Schnelle }
56091621ba7SSven Schnelle
raw3270_read_modified_cb(struct raw3270_request * rq,void * data)561cbb36313SSven Schnelle void raw3270_read_modified_cb(struct raw3270_request *rq, void *data)
5624d334fd1SMartin Schwidefsky {
5634d334fd1SMartin Schwidefsky struct raw3270 *rp = rq->view->dev;
564ff61744cSSven Schnelle
565cbb36313SSven Schnelle raw3270_size_device(rp, data);
5664d334fd1SMartin Schwidefsky raw3270_size_device_done(rp);
5674d334fd1SMartin Schwidefsky }
568754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_read_modified_cb);
5694d334fd1SMartin Schwidefsky
raw3270_read_modified(struct raw3270 * rp)57013d4999aSSven Schnelle static void raw3270_read_modified(struct raw3270 *rp)
5714d334fd1SMartin Schwidefsky {
5724d334fd1SMartin Schwidefsky if (rp->state != RAW3270_STATE_W4ATTN)
5734d334fd1SMartin Schwidefsky return;
5744d334fd1SMartin Schwidefsky /* Use 'read modified' to get the result of a read partition. */
5754d334fd1SMartin Schwidefsky memset(&rp->init_readmod, 0, sizeof(rp->init_readmod));
5764d334fd1SMartin Schwidefsky memset(&rp->init_data, 0, sizeof(rp->init_data));
5774d334fd1SMartin Schwidefsky rp->init_readmod.ccw.cmd_code = TC_READMOD;
5784d334fd1SMartin Schwidefsky rp->init_readmod.ccw.flags = CCW_FLAG_SLI;
5794d334fd1SMartin Schwidefsky rp->init_readmod.ccw.count = sizeof(rp->init_data);
5804d334fd1SMartin Schwidefsky rp->init_readmod.ccw.cda = (__u32)__pa(rp->init_data);
5814d334fd1SMartin Schwidefsky rp->init_readmod.callback = raw3270_read_modified_cb;
582cbb36313SSven Schnelle rp->init_readmod.callback_data = rp->init_data;
5834d334fd1SMartin Schwidefsky rp->state = RAW3270_STATE_READMOD;
5844d334fd1SMartin Schwidefsky raw3270_start_irq(&rp->init_view, &rp->init_readmod);
5854d334fd1SMartin Schwidefsky }
5864d334fd1SMartin Schwidefsky
raw3270_writesf_readpart(struct raw3270 * rp)58713d4999aSSven Schnelle static void raw3270_writesf_readpart(struct raw3270 *rp)
5884d334fd1SMartin Schwidefsky {
589ff61744cSSven Schnelle static const unsigned char wbuf[] = {
590ff61744cSSven Schnelle 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81
591ff61744cSSven Schnelle };
5924d334fd1SMartin Schwidefsky
5934d334fd1SMartin Schwidefsky /* Store 'read partition' data stream to init_data */
5944d334fd1SMartin Schwidefsky memset(&rp->init_readpart, 0, sizeof(rp->init_readpart));
5954d334fd1SMartin Schwidefsky memset(&rp->init_data, 0, sizeof(rp->init_data));
5964d334fd1SMartin Schwidefsky memcpy(&rp->init_data, wbuf, sizeof(wbuf));
5974d334fd1SMartin Schwidefsky rp->init_readpart.ccw.cmd_code = TC_WRITESF;
5984d334fd1SMartin Schwidefsky rp->init_readpart.ccw.flags = CCW_FLAG_SLI;
5994d334fd1SMartin Schwidefsky rp->init_readpart.ccw.count = sizeof(wbuf);
6004d334fd1SMartin Schwidefsky rp->init_readpart.ccw.cda = (__u32)__pa(&rp->init_data);
6014d334fd1SMartin Schwidefsky rp->state = RAW3270_STATE_W4ATTN;
6024d334fd1SMartin Schwidefsky raw3270_start_irq(&rp->init_view, &rp->init_readpart);
6034d334fd1SMartin Schwidefsky }
6044d334fd1SMartin Schwidefsky
6054d334fd1SMartin Schwidefsky /*
6064d334fd1SMartin Schwidefsky * Device reset
6074d334fd1SMartin Schwidefsky */
raw3270_reset_device_cb(struct raw3270_request * rq,void * data)60813d4999aSSven Schnelle static void raw3270_reset_device_cb(struct raw3270_request *rq, void *data)
6094d334fd1SMartin Schwidefsky {
6104d334fd1SMartin Schwidefsky struct raw3270 *rp = rq->view->dev;
6114d334fd1SMartin Schwidefsky
6124d334fd1SMartin Schwidefsky if (rp->state != RAW3270_STATE_RESET)
6134d334fd1SMartin Schwidefsky return;
614dc3ac5ffSMartin Schwidefsky if (rq->rc) {
6154d334fd1SMartin Schwidefsky /* Reset command failed. */
6164d334fd1SMartin Schwidefsky rp->state = RAW3270_STATE_INIT;
61701a7cfa2SMartin Schwidefsky } else if (MACHINE_IS_VM) {
6184d334fd1SMartin Schwidefsky raw3270_size_device_vm(rp);
6194d334fd1SMartin Schwidefsky raw3270_size_device_done(rp);
620ff61744cSSven Schnelle } else {
6214d334fd1SMartin Schwidefsky raw3270_writesf_readpart(rp);
622ff61744cSSven Schnelle }
623bd1cb5deSMartin Schwidefsky memset(&rp->init_reset, 0, sizeof(rp->init_reset));
6244d334fd1SMartin Schwidefsky }
6254d334fd1SMartin Schwidefsky
__raw3270_reset_device(struct raw3270 * rp)62613d4999aSSven Schnelle static int __raw3270_reset_device(struct raw3270 *rp)
6274d334fd1SMartin Schwidefsky {
6284d334fd1SMartin Schwidefsky int rc;
6294d334fd1SMartin Schwidefsky
630bd1cb5deSMartin Schwidefsky /* Check if reset is already pending */
631bd1cb5deSMartin Schwidefsky if (rp->init_reset.view)
632bd1cb5deSMartin Schwidefsky return -EBUSY;
6334d334fd1SMartin Schwidefsky /* Store reset data stream to init_data/init_reset */
6344d334fd1SMartin Schwidefsky rp->init_data[0] = TW_KR;
6354d334fd1SMartin Schwidefsky rp->init_reset.ccw.cmd_code = TC_EWRITEA;
6364d334fd1SMartin Schwidefsky rp->init_reset.ccw.flags = CCW_FLAG_SLI;
6374d334fd1SMartin Schwidefsky rp->init_reset.ccw.count = 1;
6384d334fd1SMartin Schwidefsky rp->init_reset.ccw.cda = (__u32)__pa(rp->init_data);
6394d334fd1SMartin Schwidefsky rp->init_reset.callback = raw3270_reset_device_cb;
6404d334fd1SMartin Schwidefsky rc = __raw3270_start(rp, &rp->init_view, &rp->init_reset);
6414d334fd1SMartin Schwidefsky if (rc == 0 && rp->state == RAW3270_STATE_INIT)
6424d334fd1SMartin Schwidefsky rp->state = RAW3270_STATE_RESET;
6431da177e4SLinus Torvalds return rc;
6441da177e4SLinus Torvalds }
6451da177e4SLinus Torvalds
raw3270_reset_device(struct raw3270 * rp)64613d4999aSSven Schnelle static int raw3270_reset_device(struct raw3270 *rp)
6471da177e4SLinus Torvalds {
6484d334fd1SMartin Schwidefsky unsigned long flags;
6491da177e4SLinus Torvalds int rc;
6501da177e4SLinus Torvalds
6514d334fd1SMartin Schwidefsky spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
6524d334fd1SMartin Schwidefsky rc = __raw3270_reset_device(rp);
6534d334fd1SMartin Schwidefsky spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
6541da177e4SLinus Torvalds return rc;
6551da177e4SLinus Torvalds }
6561da177e4SLinus Torvalds
raw3270_reset(struct raw3270_view * view)65713d4999aSSven Schnelle int raw3270_reset(struct raw3270_view *view)
658ed3cb6f0SRichard Hitt {
659ed3cb6f0SRichard Hitt struct raw3270 *rp;
660ed3cb6f0SRichard Hitt int rc;
661ed3cb6f0SRichard Hitt
662ed3cb6f0SRichard Hitt rp = view->dev;
6631cf69b7bSVineeth Vijayan if (!rp || rp->view != view)
664ed3cb6f0SRichard Hitt rc = -EACCES;
6654d334fd1SMartin Schwidefsky else if (!raw3270_state_ready(rp))
6664d334fd1SMartin Schwidefsky rc = -EBUSY;
667ed3cb6f0SRichard Hitt else
668ed3cb6f0SRichard Hitt rc = raw3270_reset_device(view->dev);
669ed3cb6f0SRichard Hitt return rc;
670ed3cb6f0SRichard Hitt }
671754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_reset);
672ed3cb6f0SRichard Hitt
__raw3270_disconnect(struct raw3270 * rp)67313d4999aSSven Schnelle static void __raw3270_disconnect(struct raw3270 *rp)
6747e36eff1SMartin Schwidefsky {
6757e36eff1SMartin Schwidefsky struct raw3270_request *rq;
6767e36eff1SMartin Schwidefsky struct raw3270_view *view;
6777e36eff1SMartin Schwidefsky
6787e36eff1SMartin Schwidefsky rp->state = RAW3270_STATE_INIT;
6797e36eff1SMartin Schwidefsky rp->view = &rp->init_view;
6807e36eff1SMartin Schwidefsky /* Cancel all queued requests */
6817e36eff1SMartin Schwidefsky while (!list_empty(&rp->req_queue)) {
6827e36eff1SMartin Schwidefsky rq = list_entry(rp->req_queue.next, struct raw3270_request, list);
6837e36eff1SMartin Schwidefsky view = rq->view;
6847e36eff1SMartin Schwidefsky rq->rc = -EACCES;
6857e36eff1SMartin Schwidefsky list_del_init(&rq->list);
6867e36eff1SMartin Schwidefsky if (rq->callback)
6877e36eff1SMartin Schwidefsky rq->callback(rq, rq->callback_data);
6887e36eff1SMartin Schwidefsky raw3270_put_view(view);
6897e36eff1SMartin Schwidefsky }
6907e36eff1SMartin Schwidefsky /* Start from scratch */
6917e36eff1SMartin Schwidefsky __raw3270_reset_device(rp);
6927e36eff1SMartin Schwidefsky }
6937e36eff1SMartin Schwidefsky
raw3270_init_irq(struct raw3270_view * view,struct raw3270_request * rq,struct irb * irb)69413d4999aSSven Schnelle static void raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
6954d334fd1SMartin Schwidefsky struct irb *irb)
6964d334fd1SMartin Schwidefsky {
6974d334fd1SMartin Schwidefsky struct raw3270 *rp;
6984d334fd1SMartin Schwidefsky
6994d334fd1SMartin Schwidefsky if (rq) {
7004d334fd1SMartin Schwidefsky if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
7014d334fd1SMartin Schwidefsky if (irb->ecw[0] & SNS0_CMD_REJECT)
7024d334fd1SMartin Schwidefsky rq->rc = -EOPNOTSUPP;
7034d334fd1SMartin Schwidefsky else
7044d334fd1SMartin Schwidefsky rq->rc = -EIO;
7054d334fd1SMartin Schwidefsky }
7064d334fd1SMartin Schwidefsky }
7074d334fd1SMartin Schwidefsky if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
7084d334fd1SMartin Schwidefsky /* Queue read modified after attention interrupt */
7094d334fd1SMartin Schwidefsky rp = view->dev;
7104d334fd1SMartin Schwidefsky raw3270_read_modified(rp);
7114d334fd1SMartin Schwidefsky }
7124d334fd1SMartin Schwidefsky }
7134d334fd1SMartin Schwidefsky
7144d334fd1SMartin Schwidefsky static struct raw3270_fn raw3270_init_fn = {
7154d334fd1SMartin Schwidefsky .intv = raw3270_init_irq
7164d334fd1SMartin Schwidefsky };
7174d334fd1SMartin Schwidefsky
7181da177e4SLinus Torvalds /*
7191da177e4SLinus Torvalds * Setup new 3270 device.
7201da177e4SLinus Torvalds */
raw3270_setup_device(struct ccw_device * cdev,struct raw3270 * rp,char * ascebc)72113d4999aSSven Schnelle static int raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp,
72213d4999aSSven Schnelle char *ascebc)
7231da177e4SLinus Torvalds {
7241da177e4SLinus Torvalds struct list_head *l;
7251da177e4SLinus Torvalds struct raw3270 *tmp;
7261da177e4SLinus Torvalds int minor;
7271da177e4SLinus Torvalds
7281da177e4SLinus Torvalds memset(rp, 0, sizeof(struct raw3270));
7291da177e4SLinus Torvalds /* Copy ebcdic -> ascii translation table. */
7301da177e4SLinus Torvalds memcpy(ascebc, _ascebc, 256);
7311da177e4SLinus Torvalds if (tubxcorrect) {
7321da177e4SLinus Torvalds /* correct brackets and circumflex */
7331da177e4SLinus Torvalds ascebc['['] = 0xad;
7341da177e4SLinus Torvalds ascebc[']'] = 0xbd;
7351da177e4SLinus Torvalds ascebc['^'] = 0xb0;
7361da177e4SLinus Torvalds }
7371da177e4SLinus Torvalds rp->ascebc = ascebc;
7381da177e4SLinus Torvalds
7391da177e4SLinus Torvalds /* Set defaults. */
7401da177e4SLinus Torvalds rp->rows = 24;
7411da177e4SLinus Torvalds rp->cols = 80;
74291621ba7SSven Schnelle rp->old_rows = rp->rows;
74391621ba7SSven Schnelle rp->old_cols = rp->cols;
7441da177e4SLinus Torvalds
7451da177e4SLinus Torvalds INIT_LIST_HEAD(&rp->req_queue);
7461da177e4SLinus Torvalds INIT_LIST_HEAD(&rp->view_list);
7471da177e4SLinus Torvalds
7484d334fd1SMartin Schwidefsky rp->init_view.dev = rp;
7494d334fd1SMartin Schwidefsky rp->init_view.fn = &raw3270_init_fn;
7504d334fd1SMartin Schwidefsky rp->view = &rp->init_view;
75191621ba7SSven Schnelle INIT_WORK(&rp->resize_work, raw3270_resize_work);
7524d334fd1SMartin Schwidefsky
7531da177e4SLinus Torvalds /*
7541da177e4SLinus Torvalds * Add device to list and find the smallest unused minor
755ed3cb6f0SRichard Hitt * number for it. Note: there is no device with minor 0,
756ed3cb6f0SRichard Hitt * see special case for fs3270.c:fs3270_open().
7571da177e4SLinus Torvalds */
75814cc3e2bSIngo Molnar mutex_lock(&raw3270_mutex);
7591da177e4SLinus Torvalds /* Keep the list sorted. */
760ed3cb6f0SRichard Hitt minor = RAW3270_FIRSTMINOR;
7611da177e4SLinus Torvalds rp->minor = -1;
7621da177e4SLinus Torvalds list_for_each(l, &raw3270_devices) {
7631da177e4SLinus Torvalds tmp = list_entry(l, struct raw3270, list);
7641da177e4SLinus Torvalds if (tmp->minor > minor) {
7651da177e4SLinus Torvalds rp->minor = minor;
7661da177e4SLinus Torvalds __list_add(&rp->list, l->prev, l);
7671da177e4SLinus Torvalds break;
7681da177e4SLinus Torvalds }
7691da177e4SLinus Torvalds minor++;
7701da177e4SLinus Torvalds }
771ed3cb6f0SRichard Hitt if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) {
7721da177e4SLinus Torvalds rp->minor = minor;
7731da177e4SLinus Torvalds list_add_tail(&rp->list, &raw3270_devices);
7741da177e4SLinus Torvalds }
77514cc3e2bSIngo Molnar mutex_unlock(&raw3270_mutex);
7761da177e4SLinus Torvalds /* No free minor number? Then give up. */
7771da177e4SLinus Torvalds if (rp->minor == -1)
7781da177e4SLinus Torvalds return -EUSERS;
7791da177e4SLinus Torvalds rp->cdev = cdev;
780dff59b64SGreg Kroah-Hartman dev_set_drvdata(&cdev->dev, rp);
7811da177e4SLinus Torvalds cdev->handler = raw3270_irq;
7821da177e4SLinus Torvalds return 0;
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds
7851da177e4SLinus Torvalds #ifdef CONFIG_TN3270_CONSOLE
7862253e8d7SSebastian Ott /* Tentative definition - see below for actual definition. */
7872253e8d7SSebastian Ott static struct ccw_driver raw3270_ccw_driver;
7882253e8d7SSebastian Ott
raw3270_state_final(struct raw3270 * rp)789e036ea81SHeiko Carstens static inline int raw3270_state_final(struct raw3270 *rp)
790e036ea81SHeiko Carstens {
791e036ea81SHeiko Carstens return rp->state == RAW3270_STATE_INIT ||
792e036ea81SHeiko Carstens rp->state == RAW3270_STATE_READY;
793e036ea81SHeiko Carstens }
794e036ea81SHeiko Carstens
7951da177e4SLinus Torvalds /*
7961da177e4SLinus Torvalds * Setup 3270 device configured as console.
7971da177e4SLinus Torvalds */
raw3270_setup_console(void)7982253e8d7SSebastian Ott struct raw3270 __init *raw3270_setup_console(void)
7991da177e4SLinus Torvalds {
8002253e8d7SSebastian Ott struct ccw_device *cdev;
8014d334fd1SMartin Schwidefsky unsigned long flags;
8021da177e4SLinus Torvalds struct raw3270 *rp;
8031da177e4SLinus Torvalds char *ascebc;
8041da177e4SLinus Torvalds int rc;
8051da177e4SLinus Torvalds
8061e532096SSebastian Ott cdev = ccw_device_create_console(&raw3270_ccw_driver);
8072253e8d7SSebastian Ott if (IS_ERR(cdev))
8082253e8d7SSebastian Ott return ERR_CAST(cdev);
8092253e8d7SSebastian Ott
810ff61744cSSven Schnelle rp = kzalloc(sizeof(*rp), GFP_KERNEL | GFP_DMA);
81133403dcfSHeiko Carstens ascebc = kzalloc(256, GFP_KERNEL);
8121da177e4SLinus Torvalds rc = raw3270_setup_device(cdev, rp, ascebc);
8131da177e4SLinus Torvalds if (rc)
8141da177e4SLinus Torvalds return ERR_PTR(rc);
8151da177e4SLinus Torvalds set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
8161e532096SSebastian Ott
8171e532096SSebastian Ott rc = ccw_device_enable_console(cdev);
8181e532096SSebastian Ott if (rc) {
8191e532096SSebastian Ott ccw_device_destroy_console(cdev);
8201e532096SSebastian Ott return ERR_PTR(rc);
8211e532096SSebastian Ott }
8221e532096SSebastian Ott
8234d334fd1SMartin Schwidefsky spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
8244d334fd1SMartin Schwidefsky do {
8254d334fd1SMartin Schwidefsky __raw3270_reset_device(rp);
8264d334fd1SMartin Schwidefsky while (!raw3270_state_final(rp)) {
827188561a4SSebastian Ott ccw_device_wait_idle(rp->cdev);
8284d334fd1SMartin Schwidefsky barrier();
8294d334fd1SMartin Schwidefsky }
8304d334fd1SMartin Schwidefsky } while (rp->state != RAW3270_STATE_READY);
8314d334fd1SMartin Schwidefsky spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
8321da177e4SLinus Torvalds return rp;
8331da177e4SLinus Torvalds }
8341da177e4SLinus Torvalds
raw3270_wait_cons_dev(struct raw3270 * rp)83513d4999aSSven Schnelle void raw3270_wait_cons_dev(struct raw3270 *rp)
8361da177e4SLinus Torvalds {
8371da177e4SLinus Torvalds unsigned long flags;
8381da177e4SLinus Torvalds
8391da177e4SLinus Torvalds spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
840188561a4SSebastian Ott ccw_device_wait_idle(rp->cdev);
8411da177e4SLinus Torvalds spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
8421da177e4SLinus Torvalds }
8431da177e4SLinus Torvalds
8441da177e4SLinus Torvalds #endif
8451da177e4SLinus Torvalds
8461da177e4SLinus Torvalds /*
8471da177e4SLinus Torvalds * Create a 3270 device structure.
8481da177e4SLinus Torvalds */
raw3270_create_device(struct ccw_device * cdev)84913d4999aSSven Schnelle static struct raw3270 *raw3270_create_device(struct ccw_device *cdev)
8501da177e4SLinus Torvalds {
8511da177e4SLinus Torvalds struct raw3270 *rp;
8521da177e4SLinus Torvalds char *ascebc;
8531da177e4SLinus Torvalds int rc;
8541da177e4SLinus Torvalds
855ff61744cSSven Schnelle rp = kzalloc(sizeof(*rp), GFP_KERNEL | GFP_DMA);
8561da177e4SLinus Torvalds if (!rp)
8571da177e4SLinus Torvalds return ERR_PTR(-ENOMEM);
8581da177e4SLinus Torvalds ascebc = kmalloc(256, GFP_KERNEL);
8591da177e4SLinus Torvalds if (!ascebc) {
8601da177e4SLinus Torvalds kfree(rp);
8611da177e4SLinus Torvalds return ERR_PTR(-ENOMEM);
8621da177e4SLinus Torvalds }
8631da177e4SLinus Torvalds rc = raw3270_setup_device(cdev, rp, ascebc);
8641da177e4SLinus Torvalds if (rc) {
8651da177e4SLinus Torvalds kfree(rp->ascebc);
8661da177e4SLinus Torvalds kfree(rp);
8671da177e4SLinus Torvalds rp = ERR_PTR(rc);
8681da177e4SLinus Torvalds }
8691da177e4SLinus Torvalds /* Get reference to ccw_device structure. */
8701da177e4SLinus Torvalds get_device(&cdev->dev);
8711da177e4SLinus Torvalds return rp;
8721da177e4SLinus Torvalds }
8731da177e4SLinus Torvalds
8741da177e4SLinus Torvalds /*
8754ae46db9SGuilherme G. Piccoli * This helper just validates that it is safe to activate a
8764ae46db9SGuilherme G. Piccoli * view in the panic() context, due to locking restrictions.
8774ae46db9SGuilherme G. Piccoli */
raw3270_view_lock_unavailable(struct raw3270_view * view)8784ae46db9SGuilherme G. Piccoli int raw3270_view_lock_unavailable(struct raw3270_view *view)
8794ae46db9SGuilherme G. Piccoli {
8804ae46db9SGuilherme G. Piccoli struct raw3270 *rp = view->dev;
8814ae46db9SGuilherme G. Piccoli
8824ae46db9SGuilherme G. Piccoli if (!rp)
8834ae46db9SGuilherme G. Piccoli return -ENODEV;
8844ae46db9SGuilherme G. Piccoli if (spin_is_locked(get_ccwdev_lock(rp->cdev)))
8854ae46db9SGuilherme G. Piccoli return -EBUSY;
8864ae46db9SGuilherme G. Piccoli return 0;
8874ae46db9SGuilherme G. Piccoli }
8884ae46db9SGuilherme G. Piccoli
raw3270_assign_activate_view(struct raw3270 * rp,struct raw3270_view * view)889420105f4SSven Schnelle static int raw3270_assign_activate_view(struct raw3270 *rp, struct raw3270_view *view)
890420105f4SSven Schnelle {
891420105f4SSven Schnelle rp->view = view;
892420105f4SSven Schnelle return view->fn->activate(view);
893420105f4SSven Schnelle }
894420105f4SSven Schnelle
__raw3270_activate_view(struct raw3270 * rp,struct raw3270_view * view)895420105f4SSven Schnelle static int __raw3270_activate_view(struct raw3270 *rp, struct raw3270_view *view)
896420105f4SSven Schnelle {
897420105f4SSven Schnelle struct raw3270_view *oldview = NULL, *nv;
898420105f4SSven Schnelle int rc;
899420105f4SSven Schnelle
900420105f4SSven Schnelle if (rp->view == view)
901420105f4SSven Schnelle return 0;
902420105f4SSven Schnelle
903420105f4SSven Schnelle if (!raw3270_state_ready(rp))
904420105f4SSven Schnelle return -EBUSY;
905420105f4SSven Schnelle
906420105f4SSven Schnelle if (rp->view && rp->view->fn->deactivate) {
907420105f4SSven Schnelle oldview = rp->view;
908420105f4SSven Schnelle oldview->fn->deactivate(oldview);
909420105f4SSven Schnelle }
910420105f4SSven Schnelle
911420105f4SSven Schnelle rc = raw3270_assign_activate_view(rp, view);
912420105f4SSven Schnelle if (!rc)
913420105f4SSven Schnelle return 0;
914420105f4SSven Schnelle
915420105f4SSven Schnelle /* Didn't work. Try to reactivate the old view. */
916420105f4SSven Schnelle if (oldview) {
917420105f4SSven Schnelle rc = raw3270_assign_activate_view(rp, oldview);
918420105f4SSven Schnelle if (!rc)
919420105f4SSven Schnelle return 0;
920420105f4SSven Schnelle }
921420105f4SSven Schnelle
922420105f4SSven Schnelle /* Didn't work as well. Try any other view. */
923420105f4SSven Schnelle list_for_each_entry(nv, &rp->view_list, list) {
924420105f4SSven Schnelle if (nv == view || nv == oldview)
925420105f4SSven Schnelle continue;
926420105f4SSven Schnelle rc = raw3270_assign_activate_view(rp, nv);
927420105f4SSven Schnelle if (!rc)
928420105f4SSven Schnelle break;
929420105f4SSven Schnelle rp->view = NULL;
930420105f4SSven Schnelle }
931420105f4SSven Schnelle return rc;
932420105f4SSven Schnelle }
933420105f4SSven Schnelle
9344ae46db9SGuilherme G. Piccoli /*
9351da177e4SLinus Torvalds * Activate a view.
9361da177e4SLinus Torvalds */
raw3270_activate_view(struct raw3270_view * view)93713d4999aSSven Schnelle int raw3270_activate_view(struct raw3270_view *view)
9381da177e4SLinus Torvalds {
9391da177e4SLinus Torvalds struct raw3270 *rp;
9401da177e4SLinus Torvalds unsigned long flags;
9411da177e4SLinus Torvalds int rc;
9421da177e4SLinus Torvalds
9431da177e4SLinus Torvalds rp = view->dev;
9441da177e4SLinus Torvalds if (!rp)
9451da177e4SLinus Torvalds return -ENODEV;
9461da177e4SLinus Torvalds spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
947420105f4SSven Schnelle rc = __raw3270_activate_view(rp, view);
9481da177e4SLinus Torvalds spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
9491da177e4SLinus Torvalds return rc;
9501da177e4SLinus Torvalds }
951754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_activate_view);
9521da177e4SLinus Torvalds
9531da177e4SLinus Torvalds /*
9541da177e4SLinus Torvalds * Deactivate current view.
9551da177e4SLinus Torvalds */
raw3270_deactivate_view(struct raw3270_view * view)95613d4999aSSven Schnelle void raw3270_deactivate_view(struct raw3270_view *view)
9571da177e4SLinus Torvalds {
9581da177e4SLinus Torvalds unsigned long flags;
9591da177e4SLinus Torvalds struct raw3270 *rp;
9601da177e4SLinus Torvalds
9611da177e4SLinus Torvalds rp = view->dev;
9621da177e4SLinus Torvalds if (!rp)
9631da177e4SLinus Torvalds return;
9641da177e4SLinus Torvalds spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
9651da177e4SLinus Torvalds if (rp->view == view) {
9661da177e4SLinus Torvalds view->fn->deactivate(view);
967d2c993d8SHeiko Carstens rp->view = NULL;
9681da177e4SLinus Torvalds /* Move deactivated view to end of list. */
9691da177e4SLinus Torvalds list_del_init(&view->list);
9701da177e4SLinus Torvalds list_add_tail(&view->list, &rp->view_list);
9711da177e4SLinus Torvalds /* Try to activate another view. */
9721cf69b7bSVineeth Vijayan if (raw3270_state_ready(rp)) {
973ed3cb6f0SRichard Hitt list_for_each_entry(view, &rp->view_list, list) {
9741da177e4SLinus Torvalds rp->view = view;
975ed3cb6f0SRichard Hitt if (view->fn->activate(view) == 0)
9761da177e4SLinus Torvalds break;
977d2c993d8SHeiko Carstens rp->view = NULL;
9781da177e4SLinus Torvalds }
9791da177e4SLinus Torvalds }
9801da177e4SLinus Torvalds }
9811da177e4SLinus Torvalds spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
9821da177e4SLinus Torvalds }
983754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_deactivate_view);
9841da177e4SLinus Torvalds
9851da177e4SLinus Torvalds /*
9861da177e4SLinus Torvalds * Add view to device with minor "minor".
9871da177e4SLinus Torvalds */
raw3270_add_view(struct raw3270_view * view,struct raw3270_fn * fn,int minor,int subclass)98813d4999aSSven Schnelle int raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn,
98913d4999aSSven Schnelle int minor, int subclass)
9901da177e4SLinus Torvalds {
9911da177e4SLinus Torvalds unsigned long flags;
9921da177e4SLinus Torvalds struct raw3270 *rp;
9931da177e4SLinus Torvalds int rc;
9941da177e4SLinus Torvalds
995ed3cb6f0SRichard Hitt if (minor <= 0)
996ed3cb6f0SRichard Hitt return -ENODEV;
99714cc3e2bSIngo Molnar mutex_lock(&raw3270_mutex);
9981da177e4SLinus Torvalds rc = -ENODEV;
9991da177e4SLinus Torvalds list_for_each_entry(rp, &raw3270_devices, list) {
10001da177e4SLinus Torvalds if (rp->minor != minor)
10011da177e4SLinus Torvalds continue;
10021da177e4SLinus Torvalds spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
10031da177e4SLinus Torvalds atomic_set(&view->ref_count, 2);
10041da177e4SLinus Torvalds view->dev = rp;
10051da177e4SLinus Torvalds view->fn = fn;
10061da177e4SLinus Torvalds view->model = rp->model;
10071da177e4SLinus Torvalds view->rows = rp->rows;
10081da177e4SLinus Torvalds view->cols = rp->cols;
10091da177e4SLinus Torvalds view->ascebc = rp->ascebc;
10101da177e4SLinus Torvalds spin_lock_init(&view->lock);
10115712f330SMartin Schwidefsky lockdep_set_subclass(&view->lock, subclass);
1012ed3cb6f0SRichard Hitt list_add(&view->list, &rp->view_list);
10131da177e4SLinus Torvalds rc = 0;
10141da177e4SLinus Torvalds spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
10151da177e4SLinus Torvalds break;
10161da177e4SLinus Torvalds }
101714cc3e2bSIngo Molnar mutex_unlock(&raw3270_mutex);
10181da177e4SLinus Torvalds return rc;
10191da177e4SLinus Torvalds }
1020754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_add_view);
10211da177e4SLinus Torvalds
10221da177e4SLinus Torvalds /*
10231da177e4SLinus Torvalds * Find specific view of device with minor "minor".
10241da177e4SLinus Torvalds */
raw3270_find_view(struct raw3270_fn * fn,int minor)102513d4999aSSven Schnelle struct raw3270_view *raw3270_find_view(struct raw3270_fn *fn, int minor)
10261da177e4SLinus Torvalds {
10271da177e4SLinus Torvalds struct raw3270 *rp;
10281da177e4SLinus Torvalds struct raw3270_view *view, *tmp;
10291da177e4SLinus Torvalds unsigned long flags;
10301da177e4SLinus Torvalds
103114cc3e2bSIngo Molnar mutex_lock(&raw3270_mutex);
10321da177e4SLinus Torvalds view = ERR_PTR(-ENODEV);
10331da177e4SLinus Torvalds list_for_each_entry(rp, &raw3270_devices, list) {
10341da177e4SLinus Torvalds if (rp->minor != minor)
10351da177e4SLinus Torvalds continue;
10361da177e4SLinus Torvalds spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
10371da177e4SLinus Torvalds list_for_each_entry(tmp, &rp->view_list, list) {
10381da177e4SLinus Torvalds if (tmp->fn == fn) {
10391da177e4SLinus Torvalds raw3270_get_view(tmp);
10401da177e4SLinus Torvalds view = tmp;
10411da177e4SLinus Torvalds break;
10421da177e4SLinus Torvalds }
10431da177e4SLinus Torvalds }
10441da177e4SLinus Torvalds spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
10451da177e4SLinus Torvalds break;
10461da177e4SLinus Torvalds }
104714cc3e2bSIngo Molnar mutex_unlock(&raw3270_mutex);
10481da177e4SLinus Torvalds return view;
10491da177e4SLinus Torvalds }
1050754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_find_view);
10511da177e4SLinus Torvalds
10521da177e4SLinus Torvalds /*
10531da177e4SLinus Torvalds * Remove view from device and free view structure via call to view->fn->free.
10541da177e4SLinus Torvalds */
raw3270_del_view(struct raw3270_view * view)105513d4999aSSven Schnelle void raw3270_del_view(struct raw3270_view *view)
10561da177e4SLinus Torvalds {
10571da177e4SLinus Torvalds unsigned long flags;
10581da177e4SLinus Torvalds struct raw3270 *rp;
10591da177e4SLinus Torvalds struct raw3270_view *nv;
10601da177e4SLinus Torvalds
10611da177e4SLinus Torvalds rp = view->dev;
10621da177e4SLinus Torvalds spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
10631da177e4SLinus Torvalds if (rp->view == view) {
10641da177e4SLinus Torvalds view->fn->deactivate(view);
1065d2c993d8SHeiko Carstens rp->view = NULL;
10661da177e4SLinus Torvalds }
10671da177e4SLinus Torvalds list_del_init(&view->list);
10681cf69b7bSVineeth Vijayan if (!rp->view && raw3270_state_ready(rp)) {
10691da177e4SLinus Torvalds /* Try to activate another view. */
10701da177e4SLinus Torvalds list_for_each_entry(nv, &rp->view_list, list) {
1071ed3cb6f0SRichard Hitt if (nv->fn->activate(nv) == 0) {
10721da177e4SLinus Torvalds rp->view = nv;
10731da177e4SLinus Torvalds break;
10741da177e4SLinus Torvalds }
10751da177e4SLinus Torvalds }
10761da177e4SLinus Torvalds }
10771da177e4SLinus Torvalds spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
10781da177e4SLinus Torvalds /* Wait for reference counter to drop to zero. */
10791da177e4SLinus Torvalds atomic_dec(&view->ref_count);
10801da177e4SLinus Torvalds wait_event(raw3270_wait_queue, atomic_read(&view->ref_count) == 0);
10811da177e4SLinus Torvalds if (view->fn->free)
10821da177e4SLinus Torvalds view->fn->free(view);
10831da177e4SLinus Torvalds }
1084754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_del_view);
10851da177e4SLinus Torvalds
10861da177e4SLinus Torvalds /*
10871da177e4SLinus Torvalds * Remove a 3270 device structure.
10881da177e4SLinus Torvalds */
raw3270_delete_device(struct raw3270 * rp)108913d4999aSSven Schnelle static void raw3270_delete_device(struct raw3270 *rp)
10901da177e4SLinus Torvalds {
10911da177e4SLinus Torvalds struct ccw_device *cdev;
10921da177e4SLinus Torvalds
10931da177e4SLinus Torvalds /* Remove from device chain. */
109414cc3e2bSIngo Molnar mutex_lock(&raw3270_mutex);
10951da177e4SLinus Torvalds list_del_init(&rp->list);
109614cc3e2bSIngo Molnar mutex_unlock(&raw3270_mutex);
10971da177e4SLinus Torvalds
10981da177e4SLinus Torvalds /* Disconnect from ccw_device. */
10991da177e4SLinus Torvalds cdev = rp->cdev;
1100d2c993d8SHeiko Carstens rp->cdev = NULL;
1101dff59b64SGreg Kroah-Hartman dev_set_drvdata(&cdev->dev, NULL);
1102d2c993d8SHeiko Carstens cdev->handler = NULL;
11031da177e4SLinus Torvalds
11041da177e4SLinus Torvalds /* Put ccw_device structure. */
11051da177e4SLinus Torvalds put_device(&cdev->dev);
11061da177e4SLinus Torvalds
11071da177e4SLinus Torvalds /* Now free raw3270 structure. */
11081da177e4SLinus Torvalds kfree(rp->ascebc);
11091da177e4SLinus Torvalds kfree(rp);
11101da177e4SLinus Torvalds }
11111da177e4SLinus Torvalds
raw3270_probe(struct ccw_device * cdev)111213d4999aSSven Schnelle static int raw3270_probe(struct ccw_device *cdev)
11131da177e4SLinus Torvalds {
11141da177e4SLinus Torvalds return 0;
11151da177e4SLinus Torvalds }
11161da177e4SLinus Torvalds
11171da177e4SLinus Torvalds /*
11181da177e4SLinus Torvalds * Additional attributes for a 3270 device
11191da177e4SLinus Torvalds */
model_show(struct device * dev,struct device_attribute * attr,char * buf)112082df96d8SSven Schnelle static ssize_t model_show(struct device *dev, struct device_attribute *attr,
112113d4999aSSven Schnelle char *buf)
11221da177e4SLinus Torvalds {
11234b9e0436SQing Wang return sysfs_emit(buf, "%i\n",
1124dff59b64SGreg Kroah-Hartman ((struct raw3270 *)dev_get_drvdata(dev))->model);
11251da177e4SLinus Torvalds }
112682df96d8SSven Schnelle static DEVICE_ATTR_RO(model);
11271da177e4SLinus Torvalds
rows_show(struct device * dev,struct device_attribute * attr,char * buf)112882df96d8SSven Schnelle static ssize_t rows_show(struct device *dev, struct device_attribute *attr,
112913d4999aSSven Schnelle char *buf)
11301da177e4SLinus Torvalds {
11314b9e0436SQing Wang return sysfs_emit(buf, "%i\n",
1132dff59b64SGreg Kroah-Hartman ((struct raw3270 *)dev_get_drvdata(dev))->rows);
11331da177e4SLinus Torvalds }
113482df96d8SSven Schnelle static DEVICE_ATTR_RO(rows);
11351da177e4SLinus Torvalds
11361da177e4SLinus Torvalds static ssize_t
columns_show(struct device * dev,struct device_attribute * attr,char * buf)113782df96d8SSven Schnelle columns_show(struct device *dev, struct device_attribute *attr,
113813d4999aSSven Schnelle char *buf)
11391da177e4SLinus Torvalds {
11404b9e0436SQing Wang return sysfs_emit(buf, "%i\n",
1141dff59b64SGreg Kroah-Hartman ((struct raw3270 *)dev_get_drvdata(dev))->cols);
11421da177e4SLinus Torvalds }
114382df96d8SSven Schnelle static DEVICE_ATTR_RO(columns);
11441da177e4SLinus Torvalds
11451da177e4SLinus Torvalds static struct attribute *raw3270_attrs[] = {
11461da177e4SLinus Torvalds &dev_attr_model.attr,
11471da177e4SLinus Torvalds &dev_attr_rows.attr,
11481da177e4SLinus Torvalds &dev_attr_columns.attr,
11491da177e4SLinus Torvalds NULL,
11501da177e4SLinus Torvalds };
11511da177e4SLinus Torvalds
1152cb0259caSArvind Yadav static const struct attribute_group raw3270_attr_group = {
11531da177e4SLinus Torvalds .attrs = raw3270_attrs,
11541da177e4SLinus Torvalds };
11551da177e4SLinus Torvalds
raw3270_create_attributes(struct raw3270 * rp)1156d7cf0d57SHeiko Carstens static int raw3270_create_attributes(struct raw3270 *rp)
11571da177e4SLinus Torvalds {
1158c95571e6SMartin Schwidefsky return sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
11591da177e4SLinus Torvalds }
11601da177e4SLinus Torvalds
11611da177e4SLinus Torvalds /*
11621da177e4SLinus Torvalds * Notifier for device addition/removal
11631da177e4SLinus Torvalds */
1164c11ca97eSDenis Cheng static LIST_HEAD(raw3270_notifier);
11651da177e4SLinus Torvalds
raw3270_register_notifier(struct raw3270_notifier * notifier)1166c95571e6SMartin Schwidefsky int raw3270_register_notifier(struct raw3270_notifier *notifier)
11671da177e4SLinus Torvalds {
11681da177e4SLinus Torvalds struct raw3270 *rp;
11691da177e4SLinus Torvalds
117014cc3e2bSIngo Molnar mutex_lock(&raw3270_mutex);
1171c95571e6SMartin Schwidefsky list_add_tail(¬ifier->list, &raw3270_notifier);
1172c95571e6SMartin Schwidefsky list_for_each_entry(rp, &raw3270_devices, list)
1173c95571e6SMartin Schwidefsky notifier->create(rp->minor);
117414cc3e2bSIngo Molnar mutex_unlock(&raw3270_mutex);
11751da177e4SLinus Torvalds return 0;
11761da177e4SLinus Torvalds }
1177754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_register_notifier);
11781da177e4SLinus Torvalds
raw3270_unregister_notifier(struct raw3270_notifier * notifier)1179c95571e6SMartin Schwidefsky void raw3270_unregister_notifier(struct raw3270_notifier *notifier)
11801da177e4SLinus Torvalds {
1181c95571e6SMartin Schwidefsky struct raw3270 *rp;
11821da177e4SLinus Torvalds
118314cc3e2bSIngo Molnar mutex_lock(&raw3270_mutex);
1184c95571e6SMartin Schwidefsky list_for_each_entry(rp, &raw3270_devices, list)
1185c95571e6SMartin Schwidefsky notifier->destroy(rp->minor);
1186c95571e6SMartin Schwidefsky list_del(¬ifier->list);
118714cc3e2bSIngo Molnar mutex_unlock(&raw3270_mutex);
11881da177e4SLinus Torvalds }
1189754f66b5SSven Schnelle EXPORT_SYMBOL(raw3270_unregister_notifier);
11901da177e4SLinus Torvalds
11911da177e4SLinus Torvalds /*
11921da177e4SLinus Torvalds * Set 3270 device online.
11931da177e4SLinus Torvalds */
raw3270_set_online(struct ccw_device * cdev)119413d4999aSSven Schnelle static int raw3270_set_online(struct ccw_device *cdev)
11951da177e4SLinus Torvalds {
11961da177e4SLinus Torvalds struct raw3270_notifier *np;
1197c95571e6SMartin Schwidefsky struct raw3270 *rp;
11981da177e4SLinus Torvalds int rc;
11991da177e4SLinus Torvalds
12001da177e4SLinus Torvalds rp = raw3270_create_device(cdev);
12011da177e4SLinus Torvalds if (IS_ERR(rp))
12021da177e4SLinus Torvalds return PTR_ERR(rp);
1203d7cf0d57SHeiko Carstens rc = raw3270_create_attributes(rp);
1204d7cf0d57SHeiko Carstens if (rc)
1205d7cf0d57SHeiko Carstens goto failure;
12064d334fd1SMartin Schwidefsky raw3270_reset_device(rp);
120714cc3e2bSIngo Molnar mutex_lock(&raw3270_mutex);
12081da177e4SLinus Torvalds list_for_each_entry(np, &raw3270_notifier, list)
1209c95571e6SMartin Schwidefsky np->create(rp->minor);
121014cc3e2bSIngo Molnar mutex_unlock(&raw3270_mutex);
12111da177e4SLinus Torvalds return 0;
1212ed3cb6f0SRichard Hitt
1213ed3cb6f0SRichard Hitt failure:
1214ed3cb6f0SRichard Hitt raw3270_delete_device(rp);
1215ed3cb6f0SRichard Hitt return rc;
12161da177e4SLinus Torvalds }
12171da177e4SLinus Torvalds
12181da177e4SLinus Torvalds /*
12191da177e4SLinus Torvalds * Remove 3270 device structure.
12201da177e4SLinus Torvalds */
raw3270_remove(struct ccw_device * cdev)122113d4999aSSven Schnelle static void raw3270_remove(struct ccw_device *cdev)
12221da177e4SLinus Torvalds {
12231da177e4SLinus Torvalds unsigned long flags;
12241da177e4SLinus Torvalds struct raw3270 *rp;
12251da177e4SLinus Torvalds struct raw3270_view *v;
12261da177e4SLinus Torvalds struct raw3270_notifier *np;
12271da177e4SLinus Torvalds
1228dff59b64SGreg Kroah-Hartman rp = dev_get_drvdata(&cdev->dev);
1229ed3cb6f0SRichard Hitt /*
1230ed3cb6f0SRichard Hitt * _remove is the opposite of _probe; it's probe that
1231ed3cb6f0SRichard Hitt * should set up rp. raw3270_remove gets entered for
1232ed3cb6f0SRichard Hitt * devices even if they haven't been varied online.
1233ed3cb6f0SRichard Hitt * Thus, rp may validly be NULL here.
1234ed3cb6f0SRichard Hitt */
123531bc2324SSven Schnelle if (!rp)
1236ed3cb6f0SRichard Hitt return;
12371da177e4SLinus Torvalds
12381da177e4SLinus Torvalds sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
12391da177e4SLinus Torvalds
12401da177e4SLinus Torvalds /* Deactivate current view and remove all views. */
12411da177e4SLinus Torvalds spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
12421da177e4SLinus Torvalds if (rp->view) {
12434d334fd1SMartin Schwidefsky if (rp->view->fn->deactivate)
12441da177e4SLinus Torvalds rp->view->fn->deactivate(rp->view);
1245d2c993d8SHeiko Carstens rp->view = NULL;
12461da177e4SLinus Torvalds }
12471da177e4SLinus Torvalds while (!list_empty(&rp->view_list)) {
12481da177e4SLinus Torvalds v = list_entry(rp->view_list.next, struct raw3270_view, list);
12491da177e4SLinus Torvalds if (v->fn->release)
12501da177e4SLinus Torvalds v->fn->release(v);
12511da177e4SLinus Torvalds spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
12521da177e4SLinus Torvalds raw3270_del_view(v);
12531da177e4SLinus Torvalds spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
12541da177e4SLinus Torvalds }
12551da177e4SLinus Torvalds spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
12561da177e4SLinus Torvalds
125714cc3e2bSIngo Molnar mutex_lock(&raw3270_mutex);
12581da177e4SLinus Torvalds list_for_each_entry(np, &raw3270_notifier, list)
1259c95571e6SMartin Schwidefsky np->destroy(rp->minor);
126014cc3e2bSIngo Molnar mutex_unlock(&raw3270_mutex);
12611da177e4SLinus Torvalds
12621da177e4SLinus Torvalds /* Reset 3270 device. */
12631da177e4SLinus Torvalds raw3270_reset_device(rp);
12641da177e4SLinus Torvalds /* And finally remove it. */
12651da177e4SLinus Torvalds raw3270_delete_device(rp);
12661da177e4SLinus Torvalds }
12671da177e4SLinus Torvalds
12681da177e4SLinus Torvalds /*
12691da177e4SLinus Torvalds * Set 3270 device offline.
12701da177e4SLinus Torvalds */
raw3270_set_offline(struct ccw_device * cdev)127113d4999aSSven Schnelle static int raw3270_set_offline(struct ccw_device *cdev)
12721da177e4SLinus Torvalds {
12731da177e4SLinus Torvalds struct raw3270 *rp;
12741da177e4SLinus Torvalds
1275dff59b64SGreg Kroah-Hartman rp = dev_get_drvdata(&cdev->dev);
12761da177e4SLinus Torvalds if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags))
12771da177e4SLinus Torvalds return -EBUSY;
12781da177e4SLinus Torvalds raw3270_remove(cdev);
12791da177e4SLinus Torvalds return 0;
12801da177e4SLinus Torvalds }
12811da177e4SLinus Torvalds
12821da177e4SLinus Torvalds static struct ccw_device_id raw3270_id[] = {
12831da177e4SLinus Torvalds { CCW_DEVICE(0x3270, 0) },
12841da177e4SLinus Torvalds { CCW_DEVICE(0x3271, 0) },
12851da177e4SLinus Torvalds { CCW_DEVICE(0x3272, 0) },
12861da177e4SLinus Torvalds { CCW_DEVICE(0x3273, 0) },
12871da177e4SLinus Torvalds { CCW_DEVICE(0x3274, 0) },
12881da177e4SLinus Torvalds { CCW_DEVICE(0x3275, 0) },
12891da177e4SLinus Torvalds { CCW_DEVICE(0x3276, 0) },
12901da177e4SLinus Torvalds { CCW_DEVICE(0x3277, 0) },
12911da177e4SLinus Torvalds { CCW_DEVICE(0x3278, 0) },
12921da177e4SLinus Torvalds { CCW_DEVICE(0x3279, 0) },
12931da177e4SLinus Torvalds { CCW_DEVICE(0x3174, 0) },
12941da177e4SLinus Torvalds { /* end of list */ },
12951da177e4SLinus Torvalds };
12961da177e4SLinus Torvalds
12971da177e4SLinus Torvalds static struct ccw_driver raw3270_ccw_driver = {
12983bda058bSSebastian Ott .driver = {
12991da177e4SLinus Torvalds .name = "3270",
13001da177e4SLinus Torvalds .owner = THIS_MODULE,
13013bda058bSSebastian Ott },
13021da177e4SLinus Torvalds .ids = raw3270_id,
13031da177e4SLinus Torvalds .probe = &raw3270_probe,
13041da177e4SLinus Torvalds .remove = &raw3270_remove,
13051da177e4SLinus Torvalds .set_online = &raw3270_set_online,
13061da177e4SLinus Torvalds .set_offline = &raw3270_set_offline,
1307420f42ecSHeiko Carstens .int_class = IRQIO_C70,
13081da177e4SLinus Torvalds };
13091da177e4SLinus Torvalds
raw3270_init(void)131013d4999aSSven Schnelle static int raw3270_init(void)
13111da177e4SLinus Torvalds {
13121da177e4SLinus Torvalds struct raw3270 *rp;
13131da177e4SLinus Torvalds int rc;
13141da177e4SLinus Torvalds
13151da177e4SLinus Torvalds if (raw3270_registered)
13161da177e4SLinus Torvalds return 0;
13171da177e4SLinus Torvalds raw3270_registered = 1;
13181da177e4SLinus Torvalds rc = ccw_driver_register(&raw3270_ccw_driver);
13191da177e4SLinus Torvalds if (rc == 0) {
13201da177e4SLinus Torvalds /* Create attributes for early (= console) device. */
132114cc3e2bSIngo Molnar mutex_lock(&raw3270_mutex);
1322*1aaba11dSGreg Kroah-Hartman class3270 = class_create("3270");
13231da177e4SLinus Torvalds list_for_each_entry(rp, &raw3270_devices, list) {
13241da177e4SLinus Torvalds get_device(&rp->cdev->dev);
13251da177e4SLinus Torvalds raw3270_create_attributes(rp);
13261da177e4SLinus Torvalds }
132714cc3e2bSIngo Molnar mutex_unlock(&raw3270_mutex);
13281da177e4SLinus Torvalds }
13291da177e4SLinus Torvalds return rc;
13301da177e4SLinus Torvalds }
13311da177e4SLinus Torvalds
raw3270_exit(void)133213d4999aSSven Schnelle static void raw3270_exit(void)
13331da177e4SLinus Torvalds {
13341da177e4SLinus Torvalds ccw_driver_unregister(&raw3270_ccw_driver);
1335ed3cb6f0SRichard Hitt class_destroy(class3270);
13361da177e4SLinus Torvalds }
13371da177e4SLinus Torvalds
13381da177e4SLinus Torvalds MODULE_LICENSE("GPL");
13391da177e4SLinus Torvalds
13401da177e4SLinus Torvalds module_init(raw3270_init);
13411da177e4SLinus Torvalds module_exit(raw3270_exit);
1342