xref: /OK3568_Linux_fs/kernel/drivers/s390/char/raw3270.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * IBM/3270 Driver - core functions.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Author(s):
6*4882a593Smuzhiyun  *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
7*4882a593Smuzhiyun  *   Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
8*4882a593Smuzhiyun  *     Copyright IBM Corp. 2003, 2009
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/err.h>
13*4882a593Smuzhiyun #include <linux/init.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun #include <linux/list.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/types.h>
18*4882a593Smuzhiyun #include <linux/wait.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <asm/ccwdev.h>
21*4882a593Smuzhiyun #include <asm/cio.h>
22*4882a593Smuzhiyun #include <asm/ebcdic.h>
23*4882a593Smuzhiyun #include <asm/diag.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include "raw3270.h"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun #include <linux/major.h>
28*4882a593Smuzhiyun #include <linux/kdev_t.h>
29*4882a593Smuzhiyun #include <linux/device.h>
30*4882a593Smuzhiyun #include <linux/mutex.h>
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun struct class *class3270;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun /* The main 3270 data structure. */
35*4882a593Smuzhiyun struct raw3270 {
36*4882a593Smuzhiyun 	struct list_head list;
37*4882a593Smuzhiyun 	struct ccw_device *cdev;
38*4882a593Smuzhiyun 	int minor;
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun 	short model, rows, cols;
41*4882a593Smuzhiyun 	unsigned int state;
42*4882a593Smuzhiyun 	unsigned long flags;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	struct list_head req_queue;	/* Request queue. */
45*4882a593Smuzhiyun 	struct list_head view_list;	/* List of available views. */
46*4882a593Smuzhiyun 	struct raw3270_view *view;	/* Active view. */
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	struct timer_list timer;	/* Device timer. */
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	unsigned char *ascebc;		/* ascii -> ebcdic table */
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	struct raw3270_view init_view;
53*4882a593Smuzhiyun 	struct raw3270_request init_reset;
54*4882a593Smuzhiyun 	struct raw3270_request init_readpart;
55*4882a593Smuzhiyun 	struct raw3270_request init_readmod;
56*4882a593Smuzhiyun 	unsigned char init_data[256];
57*4882a593Smuzhiyun };
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun /* raw3270->state */
60*4882a593Smuzhiyun #define RAW3270_STATE_INIT	0	/* Initial state */
61*4882a593Smuzhiyun #define RAW3270_STATE_RESET	1	/* Reset command is pending */
62*4882a593Smuzhiyun #define RAW3270_STATE_W4ATTN	2	/* Wait for attention interrupt */
63*4882a593Smuzhiyun #define RAW3270_STATE_READMOD	3	/* Read partition is pending */
64*4882a593Smuzhiyun #define RAW3270_STATE_READY	4	/* Device is usable by views */
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /* raw3270->flags */
67*4882a593Smuzhiyun #define RAW3270_FLAGS_14BITADDR	0	/* 14-bit buffer addresses */
68*4882a593Smuzhiyun #define RAW3270_FLAGS_BUSY	1	/* Device busy, leave it alone */
69*4882a593Smuzhiyun #define RAW3270_FLAGS_CONSOLE	2	/* Device is the console. */
70*4882a593Smuzhiyun #define RAW3270_FLAGS_FROZEN	3	/* set if 3270 is frozen for suspend */
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /* Semaphore to protect global data of raw3270 (devices, views, etc). */
73*4882a593Smuzhiyun static DEFINE_MUTEX(raw3270_mutex);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun /* List of 3270 devices. */
76*4882a593Smuzhiyun static LIST_HEAD(raw3270_devices);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun /*
79*4882a593Smuzhiyun  * Flag to indicate if the driver has been registered. Some operations
80*4882a593Smuzhiyun  * like waiting for the end of i/o need to be done differently as long
81*4882a593Smuzhiyun  * as the kernel is still starting up (console support).
82*4882a593Smuzhiyun  */
83*4882a593Smuzhiyun static int raw3270_registered;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /* Module parameters */
86*4882a593Smuzhiyun static bool tubxcorrect;
87*4882a593Smuzhiyun module_param(tubxcorrect, bool, 0);
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun /*
90*4882a593Smuzhiyun  * Wait queue for device init/delete, view delete.
91*4882a593Smuzhiyun  */
92*4882a593Smuzhiyun DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun static void __raw3270_disconnect(struct raw3270 *rp);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun /*
97*4882a593Smuzhiyun  * Encode array for 12 bit 3270 addresses.
98*4882a593Smuzhiyun  */
99*4882a593Smuzhiyun static unsigned char raw3270_ebcgraf[64] =	{
100*4882a593Smuzhiyun 	0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
101*4882a593Smuzhiyun 	0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
102*4882a593Smuzhiyun 	0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
103*4882a593Smuzhiyun 	0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
104*4882a593Smuzhiyun 	0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
105*4882a593Smuzhiyun 	0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
106*4882a593Smuzhiyun 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
107*4882a593Smuzhiyun 	0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
108*4882a593Smuzhiyun };
109*4882a593Smuzhiyun 
raw3270_state_ready(struct raw3270 * rp)110*4882a593Smuzhiyun static inline int raw3270_state_ready(struct raw3270 *rp)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	return rp->state == RAW3270_STATE_READY;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
raw3270_state_final(struct raw3270 * rp)115*4882a593Smuzhiyun static inline int raw3270_state_final(struct raw3270 *rp)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	return rp->state == RAW3270_STATE_INIT ||
118*4882a593Smuzhiyun 		rp->state == RAW3270_STATE_READY;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun void
raw3270_buffer_address(struct raw3270 * rp,char * cp,unsigned short addr)122*4882a593Smuzhiyun raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun 	if (test_bit(RAW3270_FLAGS_14BITADDR, &rp->flags)) {
125*4882a593Smuzhiyun 		cp[0] = (addr >> 8) & 0x3f;
126*4882a593Smuzhiyun 		cp[1] = addr & 0xff;
127*4882a593Smuzhiyun 	} else {
128*4882a593Smuzhiyun 		cp[0] = raw3270_ebcgraf[(addr >> 6) & 0x3f];
129*4882a593Smuzhiyun 		cp[1] = raw3270_ebcgraf[addr & 0x3f];
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun /*
134*4882a593Smuzhiyun  * Allocate a new 3270 ccw request
135*4882a593Smuzhiyun  */
136*4882a593Smuzhiyun struct raw3270_request *
raw3270_request_alloc(size_t size)137*4882a593Smuzhiyun raw3270_request_alloc(size_t size)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	struct raw3270_request *rq;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/* Allocate request structure */
142*4882a593Smuzhiyun 	rq = kzalloc(sizeof(struct raw3270_request), GFP_KERNEL | GFP_DMA);
143*4882a593Smuzhiyun 	if (!rq)
144*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	/* alloc output buffer. */
147*4882a593Smuzhiyun 	if (size > 0) {
148*4882a593Smuzhiyun 		rq->buffer = kmalloc(size, GFP_KERNEL | GFP_DMA);
149*4882a593Smuzhiyun 		if (!rq->buffer) {
150*4882a593Smuzhiyun 			kfree(rq);
151*4882a593Smuzhiyun 			return ERR_PTR(-ENOMEM);
152*4882a593Smuzhiyun 		}
153*4882a593Smuzhiyun 	}
154*4882a593Smuzhiyun 	rq->size = size;
155*4882a593Smuzhiyun 	INIT_LIST_HEAD(&rq->list);
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	/*
158*4882a593Smuzhiyun 	 * Setup ccw.
159*4882a593Smuzhiyun 	 */
160*4882a593Smuzhiyun 	rq->ccw.cda = __pa(rq->buffer);
161*4882a593Smuzhiyun 	rq->ccw.flags = CCW_FLAG_SLI;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	return rq;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun /*
167*4882a593Smuzhiyun  * Free 3270 ccw request
168*4882a593Smuzhiyun  */
169*4882a593Smuzhiyun void
raw3270_request_free(struct raw3270_request * rq)170*4882a593Smuzhiyun raw3270_request_free (struct raw3270_request *rq)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	kfree(rq->buffer);
173*4882a593Smuzhiyun 	kfree(rq);
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun /*
177*4882a593Smuzhiyun  * Reset request to initial state.
178*4882a593Smuzhiyun  */
179*4882a593Smuzhiyun void
raw3270_request_reset(struct raw3270_request * rq)180*4882a593Smuzhiyun raw3270_request_reset(struct raw3270_request *rq)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	BUG_ON(!list_empty(&rq->list));
183*4882a593Smuzhiyun 	rq->ccw.cmd_code = 0;
184*4882a593Smuzhiyun 	rq->ccw.count = 0;
185*4882a593Smuzhiyun 	rq->ccw.cda = __pa(rq->buffer);
186*4882a593Smuzhiyun 	rq->ccw.flags = CCW_FLAG_SLI;
187*4882a593Smuzhiyun 	rq->rescnt = 0;
188*4882a593Smuzhiyun 	rq->rc = 0;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun /*
192*4882a593Smuzhiyun  * Set command code to ccw of a request.
193*4882a593Smuzhiyun  */
194*4882a593Smuzhiyun void
raw3270_request_set_cmd(struct raw3270_request * rq,u8 cmd)195*4882a593Smuzhiyun raw3270_request_set_cmd(struct raw3270_request *rq, u8 cmd)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	rq->ccw.cmd_code = cmd;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun /*
201*4882a593Smuzhiyun  * Add data fragment to output buffer.
202*4882a593Smuzhiyun  */
203*4882a593Smuzhiyun int
raw3270_request_add_data(struct raw3270_request * rq,void * data,size_t size)204*4882a593Smuzhiyun raw3270_request_add_data(struct raw3270_request *rq, void *data, size_t size)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	if (size + rq->ccw.count > rq->size)
207*4882a593Smuzhiyun 		return -E2BIG;
208*4882a593Smuzhiyun 	memcpy(rq->buffer + rq->ccw.count, data, size);
209*4882a593Smuzhiyun 	rq->ccw.count += size;
210*4882a593Smuzhiyun 	return 0;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun /*
214*4882a593Smuzhiyun  * Set address/length pair to ccw of a request.
215*4882a593Smuzhiyun  */
216*4882a593Smuzhiyun void
raw3270_request_set_data(struct raw3270_request * rq,void * data,size_t size)217*4882a593Smuzhiyun raw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	rq->ccw.cda = __pa(data);
220*4882a593Smuzhiyun 	rq->ccw.count = size;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun /*
224*4882a593Smuzhiyun  * Set idal buffer to ccw of a request.
225*4882a593Smuzhiyun  */
226*4882a593Smuzhiyun void
raw3270_request_set_idal(struct raw3270_request * rq,struct idal_buffer * ib)227*4882a593Smuzhiyun raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun 	rq->ccw.cda = __pa(ib->data);
230*4882a593Smuzhiyun 	rq->ccw.count = ib->size;
231*4882a593Smuzhiyun 	rq->ccw.flags |= CCW_FLAG_IDA;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun /*
235*4882a593Smuzhiyun  * Add the request to the request queue, try to start it if the
236*4882a593Smuzhiyun  * 3270 device is idle. Return without waiting for end of i/o.
237*4882a593Smuzhiyun  */
238*4882a593Smuzhiyun static int
__raw3270_start(struct raw3270 * rp,struct raw3270_view * view,struct raw3270_request * rq)239*4882a593Smuzhiyun __raw3270_start(struct raw3270 *rp, struct raw3270_view *view,
240*4882a593Smuzhiyun 		struct raw3270_request *rq)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	rq->view = view;
243*4882a593Smuzhiyun 	raw3270_get_view(view);
244*4882a593Smuzhiyun 	if (list_empty(&rp->req_queue) &&
245*4882a593Smuzhiyun 	    !test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {
246*4882a593Smuzhiyun 		/* No other requests are on the queue. Start this one. */
247*4882a593Smuzhiyun 		rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
248*4882a593Smuzhiyun 					       (unsigned long) rq, 0, 0);
249*4882a593Smuzhiyun 		if (rq->rc) {
250*4882a593Smuzhiyun 			raw3270_put_view(view);
251*4882a593Smuzhiyun 			return rq->rc;
252*4882a593Smuzhiyun 		}
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 	list_add_tail(&rq->list, &rp->req_queue);
255*4882a593Smuzhiyun 	return 0;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun int
raw3270_view_active(struct raw3270_view * view)259*4882a593Smuzhiyun raw3270_view_active(struct raw3270_view *view)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun 	struct raw3270 *rp = view->dev;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	return rp && rp->view == view &&
264*4882a593Smuzhiyun 		!test_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun int
raw3270_start(struct raw3270_view * view,struct raw3270_request * rq)268*4882a593Smuzhiyun raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun 	unsigned long flags;
271*4882a593Smuzhiyun 	struct raw3270 *rp;
272*4882a593Smuzhiyun 	int rc;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
275*4882a593Smuzhiyun 	rp = view->dev;
276*4882a593Smuzhiyun 	if (!rp || rp->view != view ||
277*4882a593Smuzhiyun 	    test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
278*4882a593Smuzhiyun 		rc = -EACCES;
279*4882a593Smuzhiyun 	else if (!raw3270_state_ready(rp))
280*4882a593Smuzhiyun 		rc = -EBUSY;
281*4882a593Smuzhiyun 	else
282*4882a593Smuzhiyun 		rc =  __raw3270_start(rp, view, rq);
283*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
284*4882a593Smuzhiyun 	return rc;
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun int
raw3270_start_locked(struct raw3270_view * view,struct raw3270_request * rq)288*4882a593Smuzhiyun raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
289*4882a593Smuzhiyun {
290*4882a593Smuzhiyun 	struct raw3270 *rp;
291*4882a593Smuzhiyun 	int rc;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	rp = view->dev;
294*4882a593Smuzhiyun 	if (!rp || rp->view != view ||
295*4882a593Smuzhiyun 	    test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
296*4882a593Smuzhiyun 		rc = -EACCES;
297*4882a593Smuzhiyun 	else if (!raw3270_state_ready(rp))
298*4882a593Smuzhiyun 		rc = -EBUSY;
299*4882a593Smuzhiyun 	else
300*4882a593Smuzhiyun 		rc =  __raw3270_start(rp, view, rq);
301*4882a593Smuzhiyun 	return rc;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun int
raw3270_start_irq(struct raw3270_view * view,struct raw3270_request * rq)305*4882a593Smuzhiyun raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun 	struct raw3270 *rp;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	rp = view->dev;
310*4882a593Smuzhiyun 	rq->view = view;
311*4882a593Smuzhiyun 	raw3270_get_view(view);
312*4882a593Smuzhiyun 	list_add_tail(&rq->list, &rp->req_queue);
313*4882a593Smuzhiyun 	return 0;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun /*
317*4882a593Smuzhiyun  * 3270 interrupt routine, called from the ccw_device layer
318*4882a593Smuzhiyun  */
319*4882a593Smuzhiyun static void
raw3270_irq(struct ccw_device * cdev,unsigned long intparm,struct irb * irb)320*4882a593Smuzhiyun raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	struct raw3270 *rp;
323*4882a593Smuzhiyun 	struct raw3270_view *view;
324*4882a593Smuzhiyun 	struct raw3270_request *rq;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	rp = dev_get_drvdata(&cdev->dev);
327*4882a593Smuzhiyun 	if (!rp)
328*4882a593Smuzhiyun 		return;
329*4882a593Smuzhiyun 	rq = (struct raw3270_request *) intparm;
330*4882a593Smuzhiyun 	view = rq ? rq->view : rp->view;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	if (!IS_ERR(irb)) {
333*4882a593Smuzhiyun 		/* Handle CE-DE-UE and subsequent UDE */
334*4882a593Smuzhiyun 		if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END)
335*4882a593Smuzhiyun 			clear_bit(RAW3270_FLAGS_BUSY, &rp->flags);
336*4882a593Smuzhiyun 		if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END |
337*4882a593Smuzhiyun 					    DEV_STAT_DEV_END |
338*4882a593Smuzhiyun 					    DEV_STAT_UNIT_EXCEP))
339*4882a593Smuzhiyun 			set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
340*4882a593Smuzhiyun 		/* Handle disconnected devices */
341*4882a593Smuzhiyun 		if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
342*4882a593Smuzhiyun 		    (irb->ecw[0] & SNS0_INTERVENTION_REQ)) {
343*4882a593Smuzhiyun 			set_bit(RAW3270_FLAGS_BUSY, &rp->flags);
344*4882a593Smuzhiyun 			if (rp->state > RAW3270_STATE_RESET)
345*4882a593Smuzhiyun 				__raw3270_disconnect(rp);
346*4882a593Smuzhiyun 		}
347*4882a593Smuzhiyun 		/* Call interrupt handler of the view */
348*4882a593Smuzhiyun 		if (view)
349*4882a593Smuzhiyun 			view->fn->intv(view, rq, irb);
350*4882a593Smuzhiyun 	}
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags))
353*4882a593Smuzhiyun 		/* Device busy, do not start I/O */
354*4882a593Smuzhiyun 		return;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	if (rq && !list_empty(&rq->list)) {
357*4882a593Smuzhiyun 		/* The request completed, remove from queue and do callback. */
358*4882a593Smuzhiyun 		list_del_init(&rq->list);
359*4882a593Smuzhiyun 		if (rq->callback)
360*4882a593Smuzhiyun 			rq->callback(rq, rq->callback_data);
361*4882a593Smuzhiyun 		/* Do put_device for get_device in raw3270_start. */
362*4882a593Smuzhiyun 		raw3270_put_view(view);
363*4882a593Smuzhiyun 	}
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	/*
366*4882a593Smuzhiyun 	 * Try to start each request on request queue until one is
367*4882a593Smuzhiyun 	 * started successful.
368*4882a593Smuzhiyun 	 */
369*4882a593Smuzhiyun 	while (!list_empty(&rp->req_queue)) {
370*4882a593Smuzhiyun 		rq = list_entry(rp->req_queue.next,struct raw3270_request,list);
371*4882a593Smuzhiyun 		rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
372*4882a593Smuzhiyun 					  (unsigned long) rq, 0, 0);
373*4882a593Smuzhiyun 		if (rq->rc == 0)
374*4882a593Smuzhiyun 			break;
375*4882a593Smuzhiyun 		/* Start failed. Remove request and do callback. */
376*4882a593Smuzhiyun 		list_del_init(&rq->list);
377*4882a593Smuzhiyun 		if (rq->callback)
378*4882a593Smuzhiyun 			rq->callback(rq, rq->callback_data);
379*4882a593Smuzhiyun 		/* Do put_device for get_device in raw3270_start. */
380*4882a593Smuzhiyun 		raw3270_put_view(view);
381*4882a593Smuzhiyun 	}
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun /*
385*4882a593Smuzhiyun  * To determine the size of the 3270 device we need to do:
386*4882a593Smuzhiyun  * 1) send a 'read partition' data stream to the device
387*4882a593Smuzhiyun  * 2) wait for the attn interrupt that precedes the query reply
388*4882a593Smuzhiyun  * 3) do a read modified to get the query reply
389*4882a593Smuzhiyun  * To make things worse we have to cope with intervention
390*4882a593Smuzhiyun  * required (3270 device switched to 'stand-by') and command
391*4882a593Smuzhiyun  * rejects (old devices that can't do 'read partition').
392*4882a593Smuzhiyun  */
393*4882a593Smuzhiyun struct raw3270_ua {	/* Query Reply structure for Usable Area */
394*4882a593Smuzhiyun 	struct {	/* Usable Area Query Reply Base */
395*4882a593Smuzhiyun 		short l;	/* Length of this structured field */
396*4882a593Smuzhiyun 		char  sfid;	/* 0x81 if Query Reply */
397*4882a593Smuzhiyun 		char  qcode;	/* 0x81 if Usable Area */
398*4882a593Smuzhiyun 		char  flags0;
399*4882a593Smuzhiyun 		char  flags1;
400*4882a593Smuzhiyun 		short w;	/* Width of usable area */
401*4882a593Smuzhiyun 		short h;	/* Heigth of usavle area */
402*4882a593Smuzhiyun 		char  units;	/* 0x00:in; 0x01:mm */
403*4882a593Smuzhiyun 		int   xr;
404*4882a593Smuzhiyun 		int   yr;
405*4882a593Smuzhiyun 		char  aw;
406*4882a593Smuzhiyun 		char  ah;
407*4882a593Smuzhiyun 		short buffsz;	/* Character buffer size, bytes */
408*4882a593Smuzhiyun 		char  xmin;
409*4882a593Smuzhiyun 		char  ymin;
410*4882a593Smuzhiyun 		char  xmax;
411*4882a593Smuzhiyun 		char  ymax;
412*4882a593Smuzhiyun 	} __attribute__ ((packed)) uab;
413*4882a593Smuzhiyun 	struct {	/* Alternate Usable Area Self-Defining Parameter */
414*4882a593Smuzhiyun 		char  l;	/* Length of this Self-Defining Parm */
415*4882a593Smuzhiyun 		char  sdpid;	/* 0x02 if Alternate Usable Area */
416*4882a593Smuzhiyun 		char  res;
417*4882a593Smuzhiyun 		char  auaid;	/* 0x01 is Id for the A U A */
418*4882a593Smuzhiyun 		short wauai;	/* Width of AUAi */
419*4882a593Smuzhiyun 		short hauai;	/* Height of AUAi */
420*4882a593Smuzhiyun 		char  auaunits;	/* 0x00:in, 0x01:mm */
421*4882a593Smuzhiyun 		int   auaxr;
422*4882a593Smuzhiyun 		int   auayr;
423*4882a593Smuzhiyun 		char  awauai;
424*4882a593Smuzhiyun 		char  ahauai;
425*4882a593Smuzhiyun 	} __attribute__ ((packed)) aua;
426*4882a593Smuzhiyun } __attribute__ ((packed));
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun static void
raw3270_size_device_vm(struct raw3270 * rp)429*4882a593Smuzhiyun raw3270_size_device_vm(struct raw3270 *rp)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun 	int rc, model;
432*4882a593Smuzhiyun 	struct ccw_dev_id dev_id;
433*4882a593Smuzhiyun 	struct diag210 diag_data;
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	ccw_device_get_id(rp->cdev, &dev_id);
436*4882a593Smuzhiyun 	diag_data.vrdcdvno = dev_id.devno;
437*4882a593Smuzhiyun 	diag_data.vrdclen = sizeof(struct diag210);
438*4882a593Smuzhiyun 	rc = diag210(&diag_data);
439*4882a593Smuzhiyun 	model = diag_data.vrdccrmd;
440*4882a593Smuzhiyun 	/* Use default model 2 if the size could not be detected */
441*4882a593Smuzhiyun 	if (rc || model < 2 || model > 5)
442*4882a593Smuzhiyun 		model = 2;
443*4882a593Smuzhiyun 	switch (model) {
444*4882a593Smuzhiyun 	case 2:
445*4882a593Smuzhiyun 		rp->model = model;
446*4882a593Smuzhiyun 		rp->rows = 24;
447*4882a593Smuzhiyun 		rp->cols = 80;
448*4882a593Smuzhiyun 		break;
449*4882a593Smuzhiyun 	case 3:
450*4882a593Smuzhiyun 		rp->model = model;
451*4882a593Smuzhiyun 		rp->rows = 32;
452*4882a593Smuzhiyun 		rp->cols = 80;
453*4882a593Smuzhiyun 		break;
454*4882a593Smuzhiyun 	case 4:
455*4882a593Smuzhiyun 		rp->model = model;
456*4882a593Smuzhiyun 		rp->rows = 43;
457*4882a593Smuzhiyun 		rp->cols = 80;
458*4882a593Smuzhiyun 		break;
459*4882a593Smuzhiyun 	case 5:
460*4882a593Smuzhiyun 		rp->model = model;
461*4882a593Smuzhiyun 		rp->rows = 27;
462*4882a593Smuzhiyun 		rp->cols = 132;
463*4882a593Smuzhiyun 		break;
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun static void
raw3270_size_device(struct raw3270 * rp)468*4882a593Smuzhiyun raw3270_size_device(struct raw3270 *rp)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun 	struct raw3270_ua *uap;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	/* Got a Query Reply */
473*4882a593Smuzhiyun 	uap = (struct raw3270_ua *) (rp->init_data + 1);
474*4882a593Smuzhiyun 	/* Paranoia check. */
475*4882a593Smuzhiyun 	if (rp->init_readmod.rc || rp->init_data[0] != 0x88 ||
476*4882a593Smuzhiyun 	    uap->uab.qcode != 0x81) {
477*4882a593Smuzhiyun 		/* Couldn't detect size. Use default model 2. */
478*4882a593Smuzhiyun 		rp->model = 2;
479*4882a593Smuzhiyun 		rp->rows = 24;
480*4882a593Smuzhiyun 		rp->cols = 80;
481*4882a593Smuzhiyun 		return;
482*4882a593Smuzhiyun 	}
483*4882a593Smuzhiyun 	/* Copy rows/columns of default Usable Area */
484*4882a593Smuzhiyun 	rp->rows = uap->uab.h;
485*4882a593Smuzhiyun 	rp->cols = uap->uab.w;
486*4882a593Smuzhiyun 	/* Check for 14 bit addressing */
487*4882a593Smuzhiyun 	if ((uap->uab.flags0 & 0x0d) == 0x01)
488*4882a593Smuzhiyun 		set_bit(RAW3270_FLAGS_14BITADDR, &rp->flags);
489*4882a593Smuzhiyun 	/* Check for Alternate Usable Area */
490*4882a593Smuzhiyun 	if (uap->uab.l == sizeof(struct raw3270_ua) &&
491*4882a593Smuzhiyun 	    uap->aua.sdpid == 0x02) {
492*4882a593Smuzhiyun 		rp->rows = uap->aua.hauai;
493*4882a593Smuzhiyun 		rp->cols = uap->aua.wauai;
494*4882a593Smuzhiyun 	}
495*4882a593Smuzhiyun 	/* Try to find a model. */
496*4882a593Smuzhiyun 	rp->model = 0;
497*4882a593Smuzhiyun 	if (rp->rows == 24 && rp->cols == 80)
498*4882a593Smuzhiyun 		rp->model = 2;
499*4882a593Smuzhiyun 	if (rp->rows == 32 && rp->cols == 80)
500*4882a593Smuzhiyun 		rp->model = 3;
501*4882a593Smuzhiyun 	if (rp->rows == 43 && rp->cols == 80)
502*4882a593Smuzhiyun 		rp->model = 4;
503*4882a593Smuzhiyun 	if (rp->rows == 27 && rp->cols == 132)
504*4882a593Smuzhiyun 		rp->model = 5;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun static void
raw3270_size_device_done(struct raw3270 * rp)508*4882a593Smuzhiyun raw3270_size_device_done(struct raw3270 *rp)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun 	struct raw3270_view *view;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	rp->view = NULL;
513*4882a593Smuzhiyun 	rp->state = RAW3270_STATE_READY;
514*4882a593Smuzhiyun 	/* Notify views about new size */
515*4882a593Smuzhiyun 	list_for_each_entry(view, &rp->view_list, list)
516*4882a593Smuzhiyun 		if (view->fn->resize)
517*4882a593Smuzhiyun 			view->fn->resize(view, rp->model, rp->rows, rp->cols);
518*4882a593Smuzhiyun 	/* Setup processing done, now activate a view */
519*4882a593Smuzhiyun 	list_for_each_entry(view, &rp->view_list, list) {
520*4882a593Smuzhiyun 		rp->view = view;
521*4882a593Smuzhiyun 		if (view->fn->activate(view) == 0)
522*4882a593Smuzhiyun 			break;
523*4882a593Smuzhiyun 		rp->view = NULL;
524*4882a593Smuzhiyun 	}
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun static void
raw3270_read_modified_cb(struct raw3270_request * rq,void * data)528*4882a593Smuzhiyun raw3270_read_modified_cb(struct raw3270_request *rq, void *data)
529*4882a593Smuzhiyun {
530*4882a593Smuzhiyun 	struct raw3270 *rp = rq->view->dev;
531*4882a593Smuzhiyun 
532*4882a593Smuzhiyun 	raw3270_size_device(rp);
533*4882a593Smuzhiyun 	raw3270_size_device_done(rp);
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun static void
raw3270_read_modified(struct raw3270 * rp)537*4882a593Smuzhiyun raw3270_read_modified(struct raw3270 *rp)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	if (rp->state != RAW3270_STATE_W4ATTN)
540*4882a593Smuzhiyun 		return;
541*4882a593Smuzhiyun 	/* Use 'read modified' to get the result of a read partition. */
542*4882a593Smuzhiyun 	memset(&rp->init_readmod, 0, sizeof(rp->init_readmod));
543*4882a593Smuzhiyun 	memset(&rp->init_data, 0, sizeof(rp->init_data));
544*4882a593Smuzhiyun 	rp->init_readmod.ccw.cmd_code = TC_READMOD;
545*4882a593Smuzhiyun 	rp->init_readmod.ccw.flags = CCW_FLAG_SLI;
546*4882a593Smuzhiyun 	rp->init_readmod.ccw.count = sizeof(rp->init_data);
547*4882a593Smuzhiyun 	rp->init_readmod.ccw.cda = (__u32) __pa(rp->init_data);
548*4882a593Smuzhiyun 	rp->init_readmod.callback = raw3270_read_modified_cb;
549*4882a593Smuzhiyun 	rp->state = RAW3270_STATE_READMOD;
550*4882a593Smuzhiyun 	raw3270_start_irq(&rp->init_view, &rp->init_readmod);
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun static void
raw3270_writesf_readpart(struct raw3270 * rp)554*4882a593Smuzhiyun raw3270_writesf_readpart(struct raw3270 *rp)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun 	static const unsigned char wbuf[] =
557*4882a593Smuzhiyun 		{ 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	/* Store 'read partition' data stream to init_data */
560*4882a593Smuzhiyun 	memset(&rp->init_readpart, 0, sizeof(rp->init_readpart));
561*4882a593Smuzhiyun 	memset(&rp->init_data, 0, sizeof(rp->init_data));
562*4882a593Smuzhiyun 	memcpy(&rp->init_data, wbuf, sizeof(wbuf));
563*4882a593Smuzhiyun 	rp->init_readpart.ccw.cmd_code = TC_WRITESF;
564*4882a593Smuzhiyun 	rp->init_readpart.ccw.flags = CCW_FLAG_SLI;
565*4882a593Smuzhiyun 	rp->init_readpart.ccw.count = sizeof(wbuf);
566*4882a593Smuzhiyun 	rp->init_readpart.ccw.cda = (__u32) __pa(&rp->init_data);
567*4882a593Smuzhiyun 	rp->state = RAW3270_STATE_W4ATTN;
568*4882a593Smuzhiyun 	raw3270_start_irq(&rp->init_view, &rp->init_readpart);
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun /*
572*4882a593Smuzhiyun  * Device reset
573*4882a593Smuzhiyun  */
574*4882a593Smuzhiyun static void
raw3270_reset_device_cb(struct raw3270_request * rq,void * data)575*4882a593Smuzhiyun raw3270_reset_device_cb(struct raw3270_request *rq, void *data)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun 	struct raw3270 *rp = rq->view->dev;
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun 	if (rp->state != RAW3270_STATE_RESET)
580*4882a593Smuzhiyun 		return;
581*4882a593Smuzhiyun 	if (rq->rc) {
582*4882a593Smuzhiyun 		/* Reset command failed. */
583*4882a593Smuzhiyun 		rp->state = RAW3270_STATE_INIT;
584*4882a593Smuzhiyun 	} else if (MACHINE_IS_VM) {
585*4882a593Smuzhiyun 		raw3270_size_device_vm(rp);
586*4882a593Smuzhiyun 		raw3270_size_device_done(rp);
587*4882a593Smuzhiyun 	} else
588*4882a593Smuzhiyun 		raw3270_writesf_readpart(rp);
589*4882a593Smuzhiyun 	memset(&rp->init_reset, 0, sizeof(rp->init_reset));
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun static int
__raw3270_reset_device(struct raw3270 * rp)593*4882a593Smuzhiyun __raw3270_reset_device(struct raw3270 *rp)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun 	int rc;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	/* Check if reset is already pending */
598*4882a593Smuzhiyun 	if (rp->init_reset.view)
599*4882a593Smuzhiyun 		return -EBUSY;
600*4882a593Smuzhiyun 	/* Store reset data stream to init_data/init_reset */
601*4882a593Smuzhiyun 	rp->init_data[0] = TW_KR;
602*4882a593Smuzhiyun 	rp->init_reset.ccw.cmd_code = TC_EWRITEA;
603*4882a593Smuzhiyun 	rp->init_reset.ccw.flags = CCW_FLAG_SLI;
604*4882a593Smuzhiyun 	rp->init_reset.ccw.count = 1;
605*4882a593Smuzhiyun 	rp->init_reset.ccw.cda = (__u32) __pa(rp->init_data);
606*4882a593Smuzhiyun 	rp->init_reset.callback = raw3270_reset_device_cb;
607*4882a593Smuzhiyun 	rc = __raw3270_start(rp, &rp->init_view, &rp->init_reset);
608*4882a593Smuzhiyun 	if (rc == 0 && rp->state == RAW3270_STATE_INIT)
609*4882a593Smuzhiyun 		rp->state = RAW3270_STATE_RESET;
610*4882a593Smuzhiyun 	return rc;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun static int
raw3270_reset_device(struct raw3270 * rp)614*4882a593Smuzhiyun raw3270_reset_device(struct raw3270 *rp)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun 	unsigned long flags;
617*4882a593Smuzhiyun 	int rc;
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
620*4882a593Smuzhiyun 	rc = __raw3270_reset_device(rp);
621*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
622*4882a593Smuzhiyun 	return rc;
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun int
raw3270_reset(struct raw3270_view * view)626*4882a593Smuzhiyun raw3270_reset(struct raw3270_view *view)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	struct raw3270 *rp;
629*4882a593Smuzhiyun 	int rc;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	rp = view->dev;
632*4882a593Smuzhiyun 	if (!rp || rp->view != view ||
633*4882a593Smuzhiyun 	    test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
634*4882a593Smuzhiyun 		rc = -EACCES;
635*4882a593Smuzhiyun 	else if (!raw3270_state_ready(rp))
636*4882a593Smuzhiyun 		rc = -EBUSY;
637*4882a593Smuzhiyun 	else
638*4882a593Smuzhiyun 		rc = raw3270_reset_device(view->dev);
639*4882a593Smuzhiyun 	return rc;
640*4882a593Smuzhiyun }
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun static void
__raw3270_disconnect(struct raw3270 * rp)643*4882a593Smuzhiyun __raw3270_disconnect(struct raw3270 *rp)
644*4882a593Smuzhiyun {
645*4882a593Smuzhiyun 	struct raw3270_request *rq;
646*4882a593Smuzhiyun 	struct raw3270_view *view;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	rp->state = RAW3270_STATE_INIT;
649*4882a593Smuzhiyun 	rp->view = &rp->init_view;
650*4882a593Smuzhiyun 	/* Cancel all queued requests */
651*4882a593Smuzhiyun 	while (!list_empty(&rp->req_queue)) {
652*4882a593Smuzhiyun 		rq = list_entry(rp->req_queue.next,struct raw3270_request,list);
653*4882a593Smuzhiyun 		view = rq->view;
654*4882a593Smuzhiyun 		rq->rc = -EACCES;
655*4882a593Smuzhiyun 		list_del_init(&rq->list);
656*4882a593Smuzhiyun 		if (rq->callback)
657*4882a593Smuzhiyun 			rq->callback(rq, rq->callback_data);
658*4882a593Smuzhiyun 		raw3270_put_view(view);
659*4882a593Smuzhiyun 	}
660*4882a593Smuzhiyun 	/* Start from scratch */
661*4882a593Smuzhiyun 	__raw3270_reset_device(rp);
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun static void
raw3270_init_irq(struct raw3270_view * view,struct raw3270_request * rq,struct irb * irb)665*4882a593Smuzhiyun raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
666*4882a593Smuzhiyun 		 struct irb *irb)
667*4882a593Smuzhiyun {
668*4882a593Smuzhiyun 	struct raw3270 *rp;
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	if (rq) {
671*4882a593Smuzhiyun 		if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
672*4882a593Smuzhiyun 			if (irb->ecw[0] & SNS0_CMD_REJECT)
673*4882a593Smuzhiyun 				rq->rc = -EOPNOTSUPP;
674*4882a593Smuzhiyun 			else
675*4882a593Smuzhiyun 				rq->rc = -EIO;
676*4882a593Smuzhiyun 		}
677*4882a593Smuzhiyun 	}
678*4882a593Smuzhiyun 	if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
679*4882a593Smuzhiyun 		/* Queue read modified after attention interrupt */
680*4882a593Smuzhiyun 		rp = view->dev;
681*4882a593Smuzhiyun 		raw3270_read_modified(rp);
682*4882a593Smuzhiyun 	}
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun static struct raw3270_fn raw3270_init_fn = {
686*4882a593Smuzhiyun 	.intv = raw3270_init_irq
687*4882a593Smuzhiyun };
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun /*
690*4882a593Smuzhiyun  * Setup new 3270 device.
691*4882a593Smuzhiyun  */
692*4882a593Smuzhiyun static int
raw3270_setup_device(struct ccw_device * cdev,struct raw3270 * rp,char * ascebc)693*4882a593Smuzhiyun raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun 	struct list_head *l;
696*4882a593Smuzhiyun 	struct raw3270 *tmp;
697*4882a593Smuzhiyun 	int minor;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	memset(rp, 0, sizeof(struct raw3270));
700*4882a593Smuzhiyun 	/* Copy ebcdic -> ascii translation table. */
701*4882a593Smuzhiyun 	memcpy(ascebc, _ascebc, 256);
702*4882a593Smuzhiyun 	if (tubxcorrect) {
703*4882a593Smuzhiyun 		/* correct brackets and circumflex */
704*4882a593Smuzhiyun 		ascebc['['] = 0xad;
705*4882a593Smuzhiyun 		ascebc[']'] = 0xbd;
706*4882a593Smuzhiyun 		ascebc['^'] = 0xb0;
707*4882a593Smuzhiyun 	}
708*4882a593Smuzhiyun 	rp->ascebc = ascebc;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	/* Set defaults. */
711*4882a593Smuzhiyun 	rp->rows = 24;
712*4882a593Smuzhiyun 	rp->cols = 80;
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	INIT_LIST_HEAD(&rp->req_queue);
715*4882a593Smuzhiyun 	INIT_LIST_HEAD(&rp->view_list);
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	rp->init_view.dev = rp;
718*4882a593Smuzhiyun 	rp->init_view.fn = &raw3270_init_fn;
719*4882a593Smuzhiyun 	rp->view = &rp->init_view;
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 	/*
722*4882a593Smuzhiyun 	 * Add device to list and find the smallest unused minor
723*4882a593Smuzhiyun 	 * number for it. Note: there is no device with minor 0,
724*4882a593Smuzhiyun 	 * see special case for fs3270.c:fs3270_open().
725*4882a593Smuzhiyun 	 */
726*4882a593Smuzhiyun 	mutex_lock(&raw3270_mutex);
727*4882a593Smuzhiyun 	/* Keep the list sorted. */
728*4882a593Smuzhiyun 	minor = RAW3270_FIRSTMINOR;
729*4882a593Smuzhiyun 	rp->minor = -1;
730*4882a593Smuzhiyun 	list_for_each(l, &raw3270_devices) {
731*4882a593Smuzhiyun 		tmp = list_entry(l, struct raw3270, list);
732*4882a593Smuzhiyun 		if (tmp->minor > minor) {
733*4882a593Smuzhiyun 			rp->minor = minor;
734*4882a593Smuzhiyun 			__list_add(&rp->list, l->prev, l);
735*4882a593Smuzhiyun 			break;
736*4882a593Smuzhiyun 		}
737*4882a593Smuzhiyun 		minor++;
738*4882a593Smuzhiyun 	}
739*4882a593Smuzhiyun 	if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) {
740*4882a593Smuzhiyun 		rp->minor = minor;
741*4882a593Smuzhiyun 		list_add_tail(&rp->list, &raw3270_devices);
742*4882a593Smuzhiyun 	}
743*4882a593Smuzhiyun 	mutex_unlock(&raw3270_mutex);
744*4882a593Smuzhiyun 	/* No free minor number? Then give up. */
745*4882a593Smuzhiyun 	if (rp->minor == -1)
746*4882a593Smuzhiyun 		return -EUSERS;
747*4882a593Smuzhiyun 	rp->cdev = cdev;
748*4882a593Smuzhiyun 	dev_set_drvdata(&cdev->dev, rp);
749*4882a593Smuzhiyun 	cdev->handler = raw3270_irq;
750*4882a593Smuzhiyun 	return 0;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun #ifdef CONFIG_TN3270_CONSOLE
754*4882a593Smuzhiyun /* Tentative definition - see below for actual definition. */
755*4882a593Smuzhiyun static struct ccw_driver raw3270_ccw_driver;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun /*
758*4882a593Smuzhiyun  * Setup 3270 device configured as console.
759*4882a593Smuzhiyun  */
raw3270_setup_console(void)760*4882a593Smuzhiyun struct raw3270 __init *raw3270_setup_console(void)
761*4882a593Smuzhiyun {
762*4882a593Smuzhiyun 	struct ccw_device *cdev;
763*4882a593Smuzhiyun 	unsigned long flags;
764*4882a593Smuzhiyun 	struct raw3270 *rp;
765*4882a593Smuzhiyun 	char *ascebc;
766*4882a593Smuzhiyun 	int rc;
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	cdev = ccw_device_create_console(&raw3270_ccw_driver);
769*4882a593Smuzhiyun 	if (IS_ERR(cdev))
770*4882a593Smuzhiyun 		return ERR_CAST(cdev);
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 	rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
773*4882a593Smuzhiyun 	ascebc = kzalloc(256, GFP_KERNEL);
774*4882a593Smuzhiyun 	rc = raw3270_setup_device(cdev, rp, ascebc);
775*4882a593Smuzhiyun 	if (rc)
776*4882a593Smuzhiyun 		return ERR_PTR(rc);
777*4882a593Smuzhiyun 	set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	rc = ccw_device_enable_console(cdev);
780*4882a593Smuzhiyun 	if (rc) {
781*4882a593Smuzhiyun 		ccw_device_destroy_console(cdev);
782*4882a593Smuzhiyun 		return ERR_PTR(rc);
783*4882a593Smuzhiyun 	}
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
786*4882a593Smuzhiyun 	do {
787*4882a593Smuzhiyun 		__raw3270_reset_device(rp);
788*4882a593Smuzhiyun 		while (!raw3270_state_final(rp)) {
789*4882a593Smuzhiyun 			ccw_device_wait_idle(rp->cdev);
790*4882a593Smuzhiyun 			barrier();
791*4882a593Smuzhiyun 		}
792*4882a593Smuzhiyun 	} while (rp->state != RAW3270_STATE_READY);
793*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
794*4882a593Smuzhiyun 	return rp;
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun void
raw3270_wait_cons_dev(struct raw3270 * rp)798*4882a593Smuzhiyun raw3270_wait_cons_dev(struct raw3270 *rp)
799*4882a593Smuzhiyun {
800*4882a593Smuzhiyun 	unsigned long flags;
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
803*4882a593Smuzhiyun 	ccw_device_wait_idle(rp->cdev);
804*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun #endif
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun /*
810*4882a593Smuzhiyun  * Create a 3270 device structure.
811*4882a593Smuzhiyun  */
812*4882a593Smuzhiyun static struct raw3270 *
raw3270_create_device(struct ccw_device * cdev)813*4882a593Smuzhiyun raw3270_create_device(struct ccw_device *cdev)
814*4882a593Smuzhiyun {
815*4882a593Smuzhiyun 	struct raw3270 *rp;
816*4882a593Smuzhiyun 	char *ascebc;
817*4882a593Smuzhiyun 	int rc;
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
820*4882a593Smuzhiyun 	if (!rp)
821*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
822*4882a593Smuzhiyun 	ascebc = kmalloc(256, GFP_KERNEL);
823*4882a593Smuzhiyun 	if (!ascebc) {
824*4882a593Smuzhiyun 		kfree(rp);
825*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
826*4882a593Smuzhiyun 	}
827*4882a593Smuzhiyun 	rc = raw3270_setup_device(cdev, rp, ascebc);
828*4882a593Smuzhiyun 	if (rc) {
829*4882a593Smuzhiyun 		kfree(rp->ascebc);
830*4882a593Smuzhiyun 		kfree(rp);
831*4882a593Smuzhiyun 		rp = ERR_PTR(rc);
832*4882a593Smuzhiyun 	}
833*4882a593Smuzhiyun 	/* Get reference to ccw_device structure. */
834*4882a593Smuzhiyun 	get_device(&cdev->dev);
835*4882a593Smuzhiyun 	return rp;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun /*
839*4882a593Smuzhiyun  * Activate a view.
840*4882a593Smuzhiyun  */
841*4882a593Smuzhiyun int
raw3270_activate_view(struct raw3270_view * view)842*4882a593Smuzhiyun raw3270_activate_view(struct raw3270_view *view)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun 	struct raw3270 *rp;
845*4882a593Smuzhiyun 	struct raw3270_view *oldview, *nv;
846*4882a593Smuzhiyun 	unsigned long flags;
847*4882a593Smuzhiyun 	int rc;
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	rp = view->dev;
850*4882a593Smuzhiyun 	if (!rp)
851*4882a593Smuzhiyun 		return -ENODEV;
852*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
853*4882a593Smuzhiyun 	if (rp->view == view)
854*4882a593Smuzhiyun 		rc = 0;
855*4882a593Smuzhiyun 	else if (!raw3270_state_ready(rp))
856*4882a593Smuzhiyun 		rc = -EBUSY;
857*4882a593Smuzhiyun 	else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
858*4882a593Smuzhiyun 		rc = -EACCES;
859*4882a593Smuzhiyun 	else {
860*4882a593Smuzhiyun 		oldview = NULL;
861*4882a593Smuzhiyun 		if (rp->view && rp->view->fn->deactivate) {
862*4882a593Smuzhiyun 			oldview = rp->view;
863*4882a593Smuzhiyun 			oldview->fn->deactivate(oldview);
864*4882a593Smuzhiyun 		}
865*4882a593Smuzhiyun 		rp->view = view;
866*4882a593Smuzhiyun 		rc = view->fn->activate(view);
867*4882a593Smuzhiyun 		if (rc) {
868*4882a593Smuzhiyun 			/* Didn't work. Try to reactivate the old view. */
869*4882a593Smuzhiyun 			rp->view = oldview;
870*4882a593Smuzhiyun 			if (!oldview || oldview->fn->activate(oldview) != 0) {
871*4882a593Smuzhiyun 				/* Didn't work as well. Try any other view. */
872*4882a593Smuzhiyun 				list_for_each_entry(nv, &rp->view_list, list)
873*4882a593Smuzhiyun 					if (nv != view && nv != oldview) {
874*4882a593Smuzhiyun 						rp->view = nv;
875*4882a593Smuzhiyun 						if (nv->fn->activate(nv) == 0)
876*4882a593Smuzhiyun 							break;
877*4882a593Smuzhiyun 						rp->view = NULL;
878*4882a593Smuzhiyun 					}
879*4882a593Smuzhiyun 			}
880*4882a593Smuzhiyun 		}
881*4882a593Smuzhiyun 	}
882*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
883*4882a593Smuzhiyun 	return rc;
884*4882a593Smuzhiyun }
885*4882a593Smuzhiyun 
886*4882a593Smuzhiyun /*
887*4882a593Smuzhiyun  * Deactivate current view.
888*4882a593Smuzhiyun  */
889*4882a593Smuzhiyun void
raw3270_deactivate_view(struct raw3270_view * view)890*4882a593Smuzhiyun raw3270_deactivate_view(struct raw3270_view *view)
891*4882a593Smuzhiyun {
892*4882a593Smuzhiyun 	unsigned long flags;
893*4882a593Smuzhiyun 	struct raw3270 *rp;
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	rp = view->dev;
896*4882a593Smuzhiyun 	if (!rp)
897*4882a593Smuzhiyun 		return;
898*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
899*4882a593Smuzhiyun 	if (rp->view == view) {
900*4882a593Smuzhiyun 		view->fn->deactivate(view);
901*4882a593Smuzhiyun 		rp->view = NULL;
902*4882a593Smuzhiyun 		/* Move deactivated view to end of list. */
903*4882a593Smuzhiyun 		list_del_init(&view->list);
904*4882a593Smuzhiyun 		list_add_tail(&view->list, &rp->view_list);
905*4882a593Smuzhiyun 		/* Try to activate another view. */
906*4882a593Smuzhiyun 		if (raw3270_state_ready(rp) &&
907*4882a593Smuzhiyun 		    !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
908*4882a593Smuzhiyun 			list_for_each_entry(view, &rp->view_list, list) {
909*4882a593Smuzhiyun 				rp->view = view;
910*4882a593Smuzhiyun 				if (view->fn->activate(view) == 0)
911*4882a593Smuzhiyun 					break;
912*4882a593Smuzhiyun 				rp->view = NULL;
913*4882a593Smuzhiyun 			}
914*4882a593Smuzhiyun 		}
915*4882a593Smuzhiyun 	}
916*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun /*
920*4882a593Smuzhiyun  * Add view to device with minor "minor".
921*4882a593Smuzhiyun  */
922*4882a593Smuzhiyun int
raw3270_add_view(struct raw3270_view * view,struct raw3270_fn * fn,int minor,int subclass)923*4882a593Smuzhiyun raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor, int subclass)
924*4882a593Smuzhiyun {
925*4882a593Smuzhiyun 	unsigned long flags;
926*4882a593Smuzhiyun 	struct raw3270 *rp;
927*4882a593Smuzhiyun 	int rc;
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	if (minor <= 0)
930*4882a593Smuzhiyun 		return -ENODEV;
931*4882a593Smuzhiyun 	mutex_lock(&raw3270_mutex);
932*4882a593Smuzhiyun 	rc = -ENODEV;
933*4882a593Smuzhiyun 	list_for_each_entry(rp, &raw3270_devices, list) {
934*4882a593Smuzhiyun 		if (rp->minor != minor)
935*4882a593Smuzhiyun 			continue;
936*4882a593Smuzhiyun 		spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
937*4882a593Smuzhiyun 		atomic_set(&view->ref_count, 2);
938*4882a593Smuzhiyun 		view->dev = rp;
939*4882a593Smuzhiyun 		view->fn = fn;
940*4882a593Smuzhiyun 		view->model = rp->model;
941*4882a593Smuzhiyun 		view->rows = rp->rows;
942*4882a593Smuzhiyun 		view->cols = rp->cols;
943*4882a593Smuzhiyun 		view->ascebc = rp->ascebc;
944*4882a593Smuzhiyun 		spin_lock_init(&view->lock);
945*4882a593Smuzhiyun 		lockdep_set_subclass(&view->lock, subclass);
946*4882a593Smuzhiyun 		list_add(&view->list, &rp->view_list);
947*4882a593Smuzhiyun 		rc = 0;
948*4882a593Smuzhiyun 		spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
949*4882a593Smuzhiyun 		break;
950*4882a593Smuzhiyun 	}
951*4882a593Smuzhiyun 	mutex_unlock(&raw3270_mutex);
952*4882a593Smuzhiyun 	return rc;
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun /*
956*4882a593Smuzhiyun  * Find specific view of device with minor "minor".
957*4882a593Smuzhiyun  */
958*4882a593Smuzhiyun struct raw3270_view *
raw3270_find_view(struct raw3270_fn * fn,int minor)959*4882a593Smuzhiyun raw3270_find_view(struct raw3270_fn *fn, int minor)
960*4882a593Smuzhiyun {
961*4882a593Smuzhiyun 	struct raw3270 *rp;
962*4882a593Smuzhiyun 	struct raw3270_view *view, *tmp;
963*4882a593Smuzhiyun 	unsigned long flags;
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	mutex_lock(&raw3270_mutex);
966*4882a593Smuzhiyun 	view = ERR_PTR(-ENODEV);
967*4882a593Smuzhiyun 	list_for_each_entry(rp, &raw3270_devices, list) {
968*4882a593Smuzhiyun 		if (rp->minor != minor)
969*4882a593Smuzhiyun 			continue;
970*4882a593Smuzhiyun 		spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
971*4882a593Smuzhiyun 		list_for_each_entry(tmp, &rp->view_list, list) {
972*4882a593Smuzhiyun 			if (tmp->fn == fn) {
973*4882a593Smuzhiyun 				raw3270_get_view(tmp);
974*4882a593Smuzhiyun 				view = tmp;
975*4882a593Smuzhiyun 				break;
976*4882a593Smuzhiyun 			}
977*4882a593Smuzhiyun 		}
978*4882a593Smuzhiyun 		spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
979*4882a593Smuzhiyun 		break;
980*4882a593Smuzhiyun 	}
981*4882a593Smuzhiyun 	mutex_unlock(&raw3270_mutex);
982*4882a593Smuzhiyun 	return view;
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun /*
986*4882a593Smuzhiyun  * Remove view from device and free view structure via call to view->fn->free.
987*4882a593Smuzhiyun  */
988*4882a593Smuzhiyun void
raw3270_del_view(struct raw3270_view * view)989*4882a593Smuzhiyun raw3270_del_view(struct raw3270_view *view)
990*4882a593Smuzhiyun {
991*4882a593Smuzhiyun 	unsigned long flags;
992*4882a593Smuzhiyun 	struct raw3270 *rp;
993*4882a593Smuzhiyun 	struct raw3270_view *nv;
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	rp = view->dev;
996*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
997*4882a593Smuzhiyun 	if (rp->view == view) {
998*4882a593Smuzhiyun 		view->fn->deactivate(view);
999*4882a593Smuzhiyun 		rp->view = NULL;
1000*4882a593Smuzhiyun 	}
1001*4882a593Smuzhiyun 	list_del_init(&view->list);
1002*4882a593Smuzhiyun 	if (!rp->view && raw3270_state_ready(rp) &&
1003*4882a593Smuzhiyun 	    !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
1004*4882a593Smuzhiyun 		/* Try to activate another view. */
1005*4882a593Smuzhiyun 		list_for_each_entry(nv, &rp->view_list, list) {
1006*4882a593Smuzhiyun 			if (nv->fn->activate(nv) == 0) {
1007*4882a593Smuzhiyun 				rp->view = nv;
1008*4882a593Smuzhiyun 				break;
1009*4882a593Smuzhiyun 			}
1010*4882a593Smuzhiyun 		}
1011*4882a593Smuzhiyun 	}
1012*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1013*4882a593Smuzhiyun 	/* Wait for reference counter to drop to zero. */
1014*4882a593Smuzhiyun 	atomic_dec(&view->ref_count);
1015*4882a593Smuzhiyun 	wait_event(raw3270_wait_queue, atomic_read(&view->ref_count) == 0);
1016*4882a593Smuzhiyun 	if (view->fn->free)
1017*4882a593Smuzhiyun 		view->fn->free(view);
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun /*
1021*4882a593Smuzhiyun  * Remove a 3270 device structure.
1022*4882a593Smuzhiyun  */
1023*4882a593Smuzhiyun static void
raw3270_delete_device(struct raw3270 * rp)1024*4882a593Smuzhiyun raw3270_delete_device(struct raw3270 *rp)
1025*4882a593Smuzhiyun {
1026*4882a593Smuzhiyun 	struct ccw_device *cdev;
1027*4882a593Smuzhiyun 
1028*4882a593Smuzhiyun 	/* Remove from device chain. */
1029*4882a593Smuzhiyun 	mutex_lock(&raw3270_mutex);
1030*4882a593Smuzhiyun 	list_del_init(&rp->list);
1031*4882a593Smuzhiyun 	mutex_unlock(&raw3270_mutex);
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 	/* Disconnect from ccw_device. */
1034*4882a593Smuzhiyun 	cdev = rp->cdev;
1035*4882a593Smuzhiyun 	rp->cdev = NULL;
1036*4882a593Smuzhiyun 	dev_set_drvdata(&cdev->dev, NULL);
1037*4882a593Smuzhiyun 	cdev->handler = NULL;
1038*4882a593Smuzhiyun 
1039*4882a593Smuzhiyun 	/* Put ccw_device structure. */
1040*4882a593Smuzhiyun 	put_device(&cdev->dev);
1041*4882a593Smuzhiyun 
1042*4882a593Smuzhiyun 	/* Now free raw3270 structure. */
1043*4882a593Smuzhiyun 	kfree(rp->ascebc);
1044*4882a593Smuzhiyun 	kfree(rp);
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun static int
raw3270_probe(struct ccw_device * cdev)1048*4882a593Smuzhiyun raw3270_probe (struct ccw_device *cdev)
1049*4882a593Smuzhiyun {
1050*4882a593Smuzhiyun 	return 0;
1051*4882a593Smuzhiyun }
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun /*
1054*4882a593Smuzhiyun  * Additional attributes for a 3270 device
1055*4882a593Smuzhiyun  */
1056*4882a593Smuzhiyun static ssize_t
raw3270_model_show(struct device * dev,struct device_attribute * attr,char * buf)1057*4882a593Smuzhiyun raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf)
1058*4882a593Smuzhiyun {
1059*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%i\n",
1060*4882a593Smuzhiyun 			((struct raw3270 *) dev_get_drvdata(dev))->model);
1061*4882a593Smuzhiyun }
1062*4882a593Smuzhiyun static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun static ssize_t
raw3270_rows_show(struct device * dev,struct device_attribute * attr,char * buf)1065*4882a593Smuzhiyun raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
1066*4882a593Smuzhiyun {
1067*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%i\n",
1068*4882a593Smuzhiyun 			((struct raw3270 *) dev_get_drvdata(dev))->rows);
1069*4882a593Smuzhiyun }
1070*4882a593Smuzhiyun static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun static ssize_t
raw3270_columns_show(struct device * dev,struct device_attribute * attr,char * buf)1073*4882a593Smuzhiyun raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
1074*4882a593Smuzhiyun {
1075*4882a593Smuzhiyun 	return snprintf(buf, PAGE_SIZE, "%i\n",
1076*4882a593Smuzhiyun 			((struct raw3270 *) dev_get_drvdata(dev))->cols);
1077*4882a593Smuzhiyun }
1078*4882a593Smuzhiyun static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun static struct attribute * raw3270_attrs[] = {
1081*4882a593Smuzhiyun 	&dev_attr_model.attr,
1082*4882a593Smuzhiyun 	&dev_attr_rows.attr,
1083*4882a593Smuzhiyun 	&dev_attr_columns.attr,
1084*4882a593Smuzhiyun 	NULL,
1085*4882a593Smuzhiyun };
1086*4882a593Smuzhiyun 
1087*4882a593Smuzhiyun static const struct attribute_group raw3270_attr_group = {
1088*4882a593Smuzhiyun 	.attrs = raw3270_attrs,
1089*4882a593Smuzhiyun };
1090*4882a593Smuzhiyun 
raw3270_create_attributes(struct raw3270 * rp)1091*4882a593Smuzhiyun static int raw3270_create_attributes(struct raw3270 *rp)
1092*4882a593Smuzhiyun {
1093*4882a593Smuzhiyun 	return sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun /*
1097*4882a593Smuzhiyun  * Notifier for device addition/removal
1098*4882a593Smuzhiyun  */
1099*4882a593Smuzhiyun static LIST_HEAD(raw3270_notifier);
1100*4882a593Smuzhiyun 
raw3270_register_notifier(struct raw3270_notifier * notifier)1101*4882a593Smuzhiyun int raw3270_register_notifier(struct raw3270_notifier *notifier)
1102*4882a593Smuzhiyun {
1103*4882a593Smuzhiyun 	struct raw3270 *rp;
1104*4882a593Smuzhiyun 
1105*4882a593Smuzhiyun 	mutex_lock(&raw3270_mutex);
1106*4882a593Smuzhiyun 	list_add_tail(&notifier->list, &raw3270_notifier);
1107*4882a593Smuzhiyun 	list_for_each_entry(rp, &raw3270_devices, list)
1108*4882a593Smuzhiyun 		notifier->create(rp->minor);
1109*4882a593Smuzhiyun 	mutex_unlock(&raw3270_mutex);
1110*4882a593Smuzhiyun 	return 0;
1111*4882a593Smuzhiyun }
1112*4882a593Smuzhiyun 
raw3270_unregister_notifier(struct raw3270_notifier * notifier)1113*4882a593Smuzhiyun void raw3270_unregister_notifier(struct raw3270_notifier *notifier)
1114*4882a593Smuzhiyun {
1115*4882a593Smuzhiyun 	struct raw3270 *rp;
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 	mutex_lock(&raw3270_mutex);
1118*4882a593Smuzhiyun 	list_for_each_entry(rp, &raw3270_devices, list)
1119*4882a593Smuzhiyun 		notifier->destroy(rp->minor);
1120*4882a593Smuzhiyun 	list_del(&notifier->list);
1121*4882a593Smuzhiyun 	mutex_unlock(&raw3270_mutex);
1122*4882a593Smuzhiyun }
1123*4882a593Smuzhiyun 
1124*4882a593Smuzhiyun /*
1125*4882a593Smuzhiyun  * Set 3270 device online.
1126*4882a593Smuzhiyun  */
1127*4882a593Smuzhiyun static int
raw3270_set_online(struct ccw_device * cdev)1128*4882a593Smuzhiyun raw3270_set_online (struct ccw_device *cdev)
1129*4882a593Smuzhiyun {
1130*4882a593Smuzhiyun 	struct raw3270_notifier *np;
1131*4882a593Smuzhiyun 	struct raw3270 *rp;
1132*4882a593Smuzhiyun 	int rc;
1133*4882a593Smuzhiyun 
1134*4882a593Smuzhiyun 	rp = raw3270_create_device(cdev);
1135*4882a593Smuzhiyun 	if (IS_ERR(rp))
1136*4882a593Smuzhiyun 		return PTR_ERR(rp);
1137*4882a593Smuzhiyun 	rc = raw3270_create_attributes(rp);
1138*4882a593Smuzhiyun 	if (rc)
1139*4882a593Smuzhiyun 		goto failure;
1140*4882a593Smuzhiyun 	raw3270_reset_device(rp);
1141*4882a593Smuzhiyun 	mutex_lock(&raw3270_mutex);
1142*4882a593Smuzhiyun 	list_for_each_entry(np, &raw3270_notifier, list)
1143*4882a593Smuzhiyun 		np->create(rp->minor);
1144*4882a593Smuzhiyun 	mutex_unlock(&raw3270_mutex);
1145*4882a593Smuzhiyun 	return 0;
1146*4882a593Smuzhiyun 
1147*4882a593Smuzhiyun failure:
1148*4882a593Smuzhiyun 	raw3270_delete_device(rp);
1149*4882a593Smuzhiyun 	return rc;
1150*4882a593Smuzhiyun }
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun /*
1153*4882a593Smuzhiyun  * Remove 3270 device structure.
1154*4882a593Smuzhiyun  */
1155*4882a593Smuzhiyun static void
raw3270_remove(struct ccw_device * cdev)1156*4882a593Smuzhiyun raw3270_remove (struct ccw_device *cdev)
1157*4882a593Smuzhiyun {
1158*4882a593Smuzhiyun 	unsigned long flags;
1159*4882a593Smuzhiyun 	struct raw3270 *rp;
1160*4882a593Smuzhiyun 	struct raw3270_view *v;
1161*4882a593Smuzhiyun 	struct raw3270_notifier *np;
1162*4882a593Smuzhiyun 
1163*4882a593Smuzhiyun 	rp = dev_get_drvdata(&cdev->dev);
1164*4882a593Smuzhiyun 	/*
1165*4882a593Smuzhiyun 	 * _remove is the opposite of _probe; it's probe that
1166*4882a593Smuzhiyun 	 * should set up rp.  raw3270_remove gets entered for
1167*4882a593Smuzhiyun 	 * devices even if they haven't been varied online.
1168*4882a593Smuzhiyun 	 * Thus, rp may validly be NULL here.
1169*4882a593Smuzhiyun 	 */
1170*4882a593Smuzhiyun 	if (rp == NULL)
1171*4882a593Smuzhiyun 		return;
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun 	sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
1174*4882a593Smuzhiyun 
1175*4882a593Smuzhiyun 	/* Deactivate current view and remove all views. */
1176*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1177*4882a593Smuzhiyun 	if (rp->view) {
1178*4882a593Smuzhiyun 		if (rp->view->fn->deactivate)
1179*4882a593Smuzhiyun 			rp->view->fn->deactivate(rp->view);
1180*4882a593Smuzhiyun 		rp->view = NULL;
1181*4882a593Smuzhiyun 	}
1182*4882a593Smuzhiyun 	while (!list_empty(&rp->view_list)) {
1183*4882a593Smuzhiyun 		v = list_entry(rp->view_list.next, struct raw3270_view, list);
1184*4882a593Smuzhiyun 		if (v->fn->release)
1185*4882a593Smuzhiyun 			v->fn->release(v);
1186*4882a593Smuzhiyun 		spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
1187*4882a593Smuzhiyun 		raw3270_del_view(v);
1188*4882a593Smuzhiyun 		spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
1189*4882a593Smuzhiyun 	}
1190*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
1191*4882a593Smuzhiyun 
1192*4882a593Smuzhiyun 	mutex_lock(&raw3270_mutex);
1193*4882a593Smuzhiyun 	list_for_each_entry(np, &raw3270_notifier, list)
1194*4882a593Smuzhiyun 		np->destroy(rp->minor);
1195*4882a593Smuzhiyun 	mutex_unlock(&raw3270_mutex);
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	/* Reset 3270 device. */
1198*4882a593Smuzhiyun 	raw3270_reset_device(rp);
1199*4882a593Smuzhiyun 	/* And finally remove it. */
1200*4882a593Smuzhiyun 	raw3270_delete_device(rp);
1201*4882a593Smuzhiyun }
1202*4882a593Smuzhiyun 
1203*4882a593Smuzhiyun /*
1204*4882a593Smuzhiyun  * Set 3270 device offline.
1205*4882a593Smuzhiyun  */
1206*4882a593Smuzhiyun static int
raw3270_set_offline(struct ccw_device * cdev)1207*4882a593Smuzhiyun raw3270_set_offline (struct ccw_device *cdev)
1208*4882a593Smuzhiyun {
1209*4882a593Smuzhiyun 	struct raw3270 *rp;
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun 	rp = dev_get_drvdata(&cdev->dev);
1212*4882a593Smuzhiyun 	if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags))
1213*4882a593Smuzhiyun 		return -EBUSY;
1214*4882a593Smuzhiyun 	raw3270_remove(cdev);
1215*4882a593Smuzhiyun 	return 0;
1216*4882a593Smuzhiyun }
1217*4882a593Smuzhiyun 
raw3270_pm_stop(struct ccw_device * cdev)1218*4882a593Smuzhiyun static int raw3270_pm_stop(struct ccw_device *cdev)
1219*4882a593Smuzhiyun {
1220*4882a593Smuzhiyun 	struct raw3270 *rp;
1221*4882a593Smuzhiyun 	struct raw3270_view *view;
1222*4882a593Smuzhiyun 	unsigned long flags;
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	rp = dev_get_drvdata(&cdev->dev);
1225*4882a593Smuzhiyun 	if (!rp)
1226*4882a593Smuzhiyun 		return 0;
1227*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1228*4882a593Smuzhiyun 	if (rp->view && rp->view->fn->deactivate)
1229*4882a593Smuzhiyun 		rp->view->fn->deactivate(rp->view);
1230*4882a593Smuzhiyun 	if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) {
1231*4882a593Smuzhiyun 		/*
1232*4882a593Smuzhiyun 		 * Release tty and fullscreen for all non-console
1233*4882a593Smuzhiyun 		 * devices.
1234*4882a593Smuzhiyun 		 */
1235*4882a593Smuzhiyun 		list_for_each_entry(view, &rp->view_list, list) {
1236*4882a593Smuzhiyun 			if (view->fn->release)
1237*4882a593Smuzhiyun 				view->fn->release(view);
1238*4882a593Smuzhiyun 		}
1239*4882a593Smuzhiyun 	}
1240*4882a593Smuzhiyun 	set_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
1241*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1242*4882a593Smuzhiyun 	return 0;
1243*4882a593Smuzhiyun }
1244*4882a593Smuzhiyun 
raw3270_pm_start(struct ccw_device * cdev)1245*4882a593Smuzhiyun static int raw3270_pm_start(struct ccw_device *cdev)
1246*4882a593Smuzhiyun {
1247*4882a593Smuzhiyun 	struct raw3270 *rp;
1248*4882a593Smuzhiyun 	unsigned long flags;
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun 	rp = dev_get_drvdata(&cdev->dev);
1251*4882a593Smuzhiyun 	if (!rp)
1252*4882a593Smuzhiyun 		return 0;
1253*4882a593Smuzhiyun 	spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
1254*4882a593Smuzhiyun 	clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
1255*4882a593Smuzhiyun 	if (rp->view && rp->view->fn->activate)
1256*4882a593Smuzhiyun 		rp->view->fn->activate(rp->view);
1257*4882a593Smuzhiyun 	spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
1258*4882a593Smuzhiyun 	return 0;
1259*4882a593Smuzhiyun }
1260*4882a593Smuzhiyun 
raw3270_pm_unfreeze(struct raw3270_view * view)1261*4882a593Smuzhiyun void raw3270_pm_unfreeze(struct raw3270_view *view)
1262*4882a593Smuzhiyun {
1263*4882a593Smuzhiyun #ifdef CONFIG_TN3270_CONSOLE
1264*4882a593Smuzhiyun 	struct raw3270 *rp;
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun 	rp = view->dev;
1267*4882a593Smuzhiyun 	if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
1268*4882a593Smuzhiyun 		ccw_device_force_console(rp->cdev);
1269*4882a593Smuzhiyun #endif
1270*4882a593Smuzhiyun }
1271*4882a593Smuzhiyun 
1272*4882a593Smuzhiyun static struct ccw_device_id raw3270_id[] = {
1273*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3270, 0) },
1274*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3271, 0) },
1275*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3272, 0) },
1276*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3273, 0) },
1277*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3274, 0) },
1278*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3275, 0) },
1279*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3276, 0) },
1280*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3277, 0) },
1281*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3278, 0) },
1282*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3279, 0) },
1283*4882a593Smuzhiyun 	{ CCW_DEVICE(0x3174, 0) },
1284*4882a593Smuzhiyun 	{ /* end of list */ },
1285*4882a593Smuzhiyun };
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun static struct ccw_driver raw3270_ccw_driver = {
1288*4882a593Smuzhiyun 	.driver = {
1289*4882a593Smuzhiyun 		.name	= "3270",
1290*4882a593Smuzhiyun 		.owner	= THIS_MODULE,
1291*4882a593Smuzhiyun 	},
1292*4882a593Smuzhiyun 	.ids		= raw3270_id,
1293*4882a593Smuzhiyun 	.probe		= &raw3270_probe,
1294*4882a593Smuzhiyun 	.remove		= &raw3270_remove,
1295*4882a593Smuzhiyun 	.set_online	= &raw3270_set_online,
1296*4882a593Smuzhiyun 	.set_offline	= &raw3270_set_offline,
1297*4882a593Smuzhiyun 	.freeze		= &raw3270_pm_stop,
1298*4882a593Smuzhiyun 	.thaw		= &raw3270_pm_start,
1299*4882a593Smuzhiyun 	.restore	= &raw3270_pm_start,
1300*4882a593Smuzhiyun 	.int_class	= IRQIO_C70,
1301*4882a593Smuzhiyun };
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun static int
raw3270_init(void)1304*4882a593Smuzhiyun raw3270_init(void)
1305*4882a593Smuzhiyun {
1306*4882a593Smuzhiyun 	struct raw3270 *rp;
1307*4882a593Smuzhiyun 	int rc;
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	if (raw3270_registered)
1310*4882a593Smuzhiyun 		return 0;
1311*4882a593Smuzhiyun 	raw3270_registered = 1;
1312*4882a593Smuzhiyun 	rc = ccw_driver_register(&raw3270_ccw_driver);
1313*4882a593Smuzhiyun 	if (rc == 0) {
1314*4882a593Smuzhiyun 		/* Create attributes for early (= console) device. */
1315*4882a593Smuzhiyun 		mutex_lock(&raw3270_mutex);
1316*4882a593Smuzhiyun 		class3270 = class_create(THIS_MODULE, "3270");
1317*4882a593Smuzhiyun 		list_for_each_entry(rp, &raw3270_devices, list) {
1318*4882a593Smuzhiyun 			get_device(&rp->cdev->dev);
1319*4882a593Smuzhiyun 			raw3270_create_attributes(rp);
1320*4882a593Smuzhiyun 		}
1321*4882a593Smuzhiyun 		mutex_unlock(&raw3270_mutex);
1322*4882a593Smuzhiyun 	}
1323*4882a593Smuzhiyun 	return rc;
1324*4882a593Smuzhiyun }
1325*4882a593Smuzhiyun 
1326*4882a593Smuzhiyun static void
raw3270_exit(void)1327*4882a593Smuzhiyun raw3270_exit(void)
1328*4882a593Smuzhiyun {
1329*4882a593Smuzhiyun 	ccw_driver_unregister(&raw3270_ccw_driver);
1330*4882a593Smuzhiyun 	class_destroy(class3270);
1331*4882a593Smuzhiyun }
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1334*4882a593Smuzhiyun 
1335*4882a593Smuzhiyun module_init(raw3270_init);
1336*4882a593Smuzhiyun module_exit(raw3270_exit);
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun EXPORT_SYMBOL(class3270);
1339*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_request_alloc);
1340*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_request_free);
1341*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_request_reset);
1342*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_request_set_cmd);
1343*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_request_add_data);
1344*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_request_set_data);
1345*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_request_set_idal);
1346*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_buffer_address);
1347*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_add_view);
1348*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_del_view);
1349*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_find_view);
1350*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_activate_view);
1351*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_deactivate_view);
1352*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_start);
1353*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_start_locked);
1354*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_start_irq);
1355*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_reset);
1356*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_register_notifier);
1357*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_unregister_notifier);
1358*4882a593Smuzhiyun EXPORT_SYMBOL(raw3270_wait_queue);
1359