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