mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 13:14:07 +08:00
s390/3270: asynchronous size sensing
Convert the synchronous size sense code to an interrupt driven approach. This allows to set the device online even if the terminal is not connected. With the new code views can be registered without a connected terminal, the tty can be opened as soon as the device is online. After the terminal has been connected and the size has been determined the tty is resized to match the device characteristics.. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
c95571e680
commit
4d334fd155
@ -37,6 +37,7 @@ struct raw3270 {
|
|||||||
int minor;
|
int minor;
|
||||||
|
|
||||||
short model, rows, cols;
|
short model, rows, cols;
|
||||||
|
unsigned int state;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
struct list_head req_queue; /* Request queue. */
|
struct list_head req_queue; /* Request queue. */
|
||||||
@ -47,17 +48,25 @@ struct raw3270 {
|
|||||||
|
|
||||||
unsigned char *ascebc; /* ascii -> ebcdic table */
|
unsigned char *ascebc; /* ascii -> ebcdic table */
|
||||||
|
|
||||||
struct raw3270_request init_request;
|
struct raw3270_view init_view;
|
||||||
|
struct raw3270_request init_reset;
|
||||||
|
struct raw3270_request init_readpart;
|
||||||
|
struct raw3270_request init_readmod;
|
||||||
unsigned char init_data[256];
|
unsigned char init_data[256];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* raw3270->state */
|
||||||
|
#define RAW3270_STATE_INIT 0 /* Initial state */
|
||||||
|
#define RAW3270_STATE_RESET 1 /* Reset command is pending */
|
||||||
|
#define RAW3270_STATE_W4ATTN 2 /* Wait for attention interrupt */
|
||||||
|
#define RAW3270_STATE_READMOD 3 /* Read partition is pending */
|
||||||
|
#define RAW3270_STATE_READY 4 /* Device is usable by views */
|
||||||
|
|
||||||
/* raw3270->flags */
|
/* raw3270->flags */
|
||||||
#define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */
|
#define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */
|
||||||
#define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */
|
#define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */
|
||||||
#define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */
|
#define RAW3270_FLAGS_CONSOLE 2 /* Device is the console. */
|
||||||
#define RAW3270_FLAGS_READY 4 /* Device is useable by views */
|
#define RAW3270_FLAGS_FROZEN 3 /* set if 3270 is frozen for suspend */
|
||||||
#define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */
|
|
||||||
#define RAW3270_FLAGS_FROZEN 16 /* set if 3270 is frozen for suspend */
|
|
||||||
|
|
||||||
/* Semaphore to protect global data of raw3270 (devices, views, etc). */
|
/* Semaphore to protect global data of raw3270 (devices, views, etc). */
|
||||||
static DEFINE_MUTEX(raw3270_mutex);
|
static DEFINE_MUTEX(raw3270_mutex);
|
||||||
@ -95,6 +104,17 @@ static unsigned char raw3270_ebcgraf[64] = {
|
|||||||
0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
|
0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline int raw3270_state_ready(struct raw3270 *rp)
|
||||||
|
{
|
||||||
|
return rp->state == RAW3270_STATE_READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int raw3270_state_final(struct raw3270 *rp)
|
||||||
|
{
|
||||||
|
return rp->state == RAW3270_STATE_INIT ||
|
||||||
|
rp->state == RAW3270_STATE_READY;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
|
raw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr)
|
||||||
{
|
{
|
||||||
@ -212,7 +232,7 @@ raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
|
|||||||
* Stop running ccw.
|
* Stop running ccw.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
raw3270_halt_io_nolock(struct raw3270 *rp, struct raw3270_request *rq)
|
__raw3270_halt_io(struct raw3270 *rp, struct raw3270_request *rq)
|
||||||
{
|
{
|
||||||
int retries;
|
int retries;
|
||||||
int rc;
|
int rc;
|
||||||
@ -231,18 +251,6 @@ raw3270_halt_io_nolock(struct raw3270 *rp, struct raw3270_request *rq)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
raw3270_halt_io(struct raw3270 *rp, struct raw3270_request *rq)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
|
||||||
rc = raw3270_halt_io_nolock(rp, rq);
|
|
||||||
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add the request to the request queue, try to start it if the
|
* Add the request to the request queue, try to start it if the
|
||||||
* 3270 device is idle. Return without waiting for end of i/o.
|
* 3270 device is idle. Return without waiting for end of i/o.
|
||||||
@ -279,8 +287,8 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
|
|||||||
if (!rp || rp->view != view ||
|
if (!rp || rp->view != view ||
|
||||||
test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
|
test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
|
||||||
rc = -EACCES;
|
rc = -EACCES;
|
||||||
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
|
else if (!raw3270_state_ready(rp))
|
||||||
rc = -ENODEV;
|
rc = -EBUSY;
|
||||||
else
|
else
|
||||||
rc = __raw3270_start(rp, view, rq);
|
rc = __raw3270_start(rp, view, rq);
|
||||||
spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
|
spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
|
||||||
@ -297,8 +305,8 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
|
|||||||
if (!rp || rp->view != view ||
|
if (!rp || rp->view != view ||
|
||||||
test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
|
test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
|
||||||
rc = -EACCES;
|
rc = -EACCES;
|
||||||
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
|
else if (!raw3270_state_ready(rp))
|
||||||
rc = -ENODEV;
|
rc = -EBUSY;
|
||||||
else
|
else
|
||||||
rc = __raw3270_start(rp, view, rq);
|
rc = __raw3270_start(rp, view, rq);
|
||||||
return rc;
|
return rc;
|
||||||
@ -376,7 +384,7 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
|||||||
case RAW3270_IO_STOP:
|
case RAW3270_IO_STOP:
|
||||||
if (!rq)
|
if (!rq)
|
||||||
break;
|
break;
|
||||||
raw3270_halt_io_nolock(rp, rq);
|
__raw3270_halt_io(rp, rq);
|
||||||
rq->rc = -EIO;
|
rq->rc = -EIO;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -411,9 +419,14 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Size sensing.
|
* To determine the size of the 3270 device we need to do:
|
||||||
|
* 1) send a 'read partition' data stream to the device
|
||||||
|
* 2) wait for the attn interrupt that precedes the query reply
|
||||||
|
* 3) do a read modified to get the query reply
|
||||||
|
* To make things worse we have to cope with intervention
|
||||||
|
* required (3270 device switched to 'stand-by') and command
|
||||||
|
* rejects (old devices that can't do 'read partition').
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct raw3270_ua { /* Query Reply structure for Usable Area */
|
struct raw3270_ua { /* Query Reply structure for Usable Area */
|
||||||
struct { /* Usable Area Query Reply Base */
|
struct { /* Usable Area Query Reply Base */
|
||||||
short l; /* Length of this structured field */
|
short l; /* Length of this structured field */
|
||||||
@ -449,117 +462,21 @@ struct raw3270_ua { /* Query Reply structure for Usable Area */
|
|||||||
} __attribute__ ((packed)) aua;
|
} __attribute__ ((packed)) aua;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
static struct diag210 raw3270_init_diag210;
|
|
||||||
static DEFINE_MUTEX(raw3270_init_mutex);
|
|
||||||
|
|
||||||
static int
|
|
||||||
raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
|
|
||||||
struct irb *irb)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Unit-Check Processing:
|
|
||||||
* Expect Command Reject or Intervention Required.
|
|
||||||
*/
|
|
||||||
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
|
|
||||||
/* Request finished abnormally. */
|
|
||||||
if (irb->ecw[0] & SNS0_INTERVENTION_REQ) {
|
|
||||||
set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags);
|
|
||||||
return RAW3270_IO_BUSY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (rq) {
|
|
||||||
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
|
|
||||||
if (irb->ecw[0] & SNS0_CMD_REJECT)
|
|
||||||
rq->rc = -EOPNOTSUPP;
|
|
||||||
else
|
|
||||||
rq->rc = -EIO;
|
|
||||||
} else
|
|
||||||
/* Request finished normally. Copy residual count. */
|
|
||||||
rq->rescnt = irb->scsw.cmd.count;
|
|
||||||
}
|
|
||||||
if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
|
|
||||||
set_bit(RAW3270_FLAGS_ATTN, &view->dev->flags);
|
|
||||||
wake_up(&raw3270_wait_queue);
|
|
||||||
}
|
|
||||||
return RAW3270_IO_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct raw3270_fn raw3270_init_fn = {
|
|
||||||
.intv = raw3270_init_irq
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct raw3270_view raw3270_init_view = {
|
|
||||||
.fn = &raw3270_init_fn
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* raw3270_wait/raw3270_wait_interruptible/__raw3270_wakeup
|
|
||||||
* Wait for end of request. The request must have been started
|
|
||||||
* with raw3270_start, rc = 0. The device lock may NOT have been
|
|
||||||
* released between calling raw3270_start and raw3270_wait.
|
|
||||||
*/
|
|
||||||
static void
|
static void
|
||||||
raw3270_wake_init(struct raw3270_request *rq, void *data)
|
raw3270_size_device_vm(struct raw3270 *rp)
|
||||||
{
|
|
||||||
wake_up((wait_queue_head_t *) data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Special wait function that can cope with console initialization.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view,
|
|
||||||
struct raw3270_request *rq)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
#ifdef CONFIG_TN3270_CONSOLE
|
|
||||||
if (raw3270_registered == 0) {
|
|
||||||
spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
|
|
||||||
rq->callback = NULL;
|
|
||||||
rc = __raw3270_start(rp, view, rq);
|
|
||||||
if (rc == 0)
|
|
||||||
while (!raw3270_request_final(rq)) {
|
|
||||||
wait_cons_dev();
|
|
||||||
barrier();
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
|
|
||||||
return rq->rc;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
rq->callback = raw3270_wake_init;
|
|
||||||
rq->callback_data = &raw3270_wait_queue;
|
|
||||||
spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
|
|
||||||
rc = __raw3270_start(rp, view, rq);
|
|
||||||
spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
/* Now wait for the completion. */
|
|
||||||
rc = wait_event_interruptible(raw3270_wait_queue,
|
|
||||||
raw3270_request_final(rq));
|
|
||||||
if (rc == -ERESTARTSYS) { /* Interrupted by a signal. */
|
|
||||||
raw3270_halt_io(view->dev, rq);
|
|
||||||
/* No wait for the halt to complete. */
|
|
||||||
wait_event(raw3270_wait_queue, raw3270_request_final(rq));
|
|
||||||
return -ERESTARTSYS;
|
|
||||||
}
|
|
||||||
return rq->rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
__raw3270_size_device_vm(struct raw3270 *rp)
|
|
||||||
{
|
{
|
||||||
int rc, model;
|
int rc, model;
|
||||||
struct ccw_dev_id dev_id;
|
struct ccw_dev_id dev_id;
|
||||||
|
struct diag210 diag_data;
|
||||||
|
|
||||||
ccw_device_get_id(rp->cdev, &dev_id);
|
ccw_device_get_id(rp->cdev, &dev_id);
|
||||||
raw3270_init_diag210.vrdcdvno = dev_id.devno;
|
diag_data.vrdcdvno = dev_id.devno;
|
||||||
raw3270_init_diag210.vrdclen = sizeof(struct diag210);
|
diag_data.vrdclen = sizeof(struct diag210);
|
||||||
rc = diag210(&raw3270_init_diag210);
|
rc = diag210(&diag_data);
|
||||||
if (rc)
|
model = diag_data.vrdccrmd;
|
||||||
return rc;
|
/* Use default model 2 if the size could not be detected */
|
||||||
model = raw3270_init_diag210.vrdccrmd;
|
if (rc || model < 2 || model > 5)
|
||||||
|
model = 2;
|
||||||
switch (model) {
|
switch (model) {
|
||||||
case 2:
|
case 2:
|
||||||
rp->model = model;
|
rp->model = model;
|
||||||
@ -581,77 +498,25 @@ __raw3270_size_device_vm(struct raw3270 *rp)
|
|||||||
rp->rows = 27;
|
rp->rows = 27;
|
||||||
rp->cols = 132;
|
rp->cols = 132;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
rc = -EOPNOTSUPP;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
__raw3270_size_device(struct raw3270 *rp)
|
raw3270_size_device(struct raw3270 *rp)
|
||||||
{
|
{
|
||||||
static const unsigned char wbuf[] =
|
|
||||||
{ 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
|
|
||||||
struct raw3270_ua *uap;
|
struct raw3270_ua *uap;
|
||||||
int rc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To determine the size of the 3270 device we need to do:
|
|
||||||
* 1) send a 'read partition' data stream to the device
|
|
||||||
* 2) wait for the attn interrupt that precedes the query reply
|
|
||||||
* 3) do a read modified to get the query reply
|
|
||||||
* To make things worse we have to cope with intervention
|
|
||||||
* required (3270 device switched to 'stand-by') and command
|
|
||||||
* rejects (old devices that can't do 'read partition').
|
|
||||||
*/
|
|
||||||
memset(&rp->init_request, 0, sizeof(rp->init_request));
|
|
||||||
memset(&rp->init_data, 0, 256);
|
|
||||||
/* Store 'read partition' data stream to init_data */
|
|
||||||
memcpy(&rp->init_data, wbuf, sizeof(wbuf));
|
|
||||||
INIT_LIST_HEAD(&rp->init_request.list);
|
|
||||||
rp->init_request.ccw.cmd_code = TC_WRITESF;
|
|
||||||
rp->init_request.ccw.flags = CCW_FLAG_SLI;
|
|
||||||
rp->init_request.ccw.count = sizeof(wbuf);
|
|
||||||
rp->init_request.ccw.cda = (__u32) __pa(&rp->init_data);
|
|
||||||
|
|
||||||
rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
|
|
||||||
if (rc)
|
|
||||||
/* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
/* Wait for attention interrupt. */
|
|
||||||
#ifdef CONFIG_TN3270_CONSOLE
|
|
||||||
if (raw3270_registered == 0) {
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
|
||||||
while (!test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags))
|
|
||||||
wait_cons_dev();
|
|
||||||
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
rc = wait_event_interruptible(raw3270_wait_queue,
|
|
||||||
test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags));
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The device accepted the 'read partition' command. Now
|
|
||||||
* set up a read ccw and issue it.
|
|
||||||
*/
|
|
||||||
rp->init_request.ccw.cmd_code = TC_READMOD;
|
|
||||||
rp->init_request.ccw.flags = CCW_FLAG_SLI;
|
|
||||||
rp->init_request.ccw.count = sizeof(rp->init_data);
|
|
||||||
rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
|
|
||||||
rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
|
|
||||||
if (rc)
|
|
||||||
return rc;
|
|
||||||
/* Got a Query Reply */
|
/* Got a Query Reply */
|
||||||
uap = (struct raw3270_ua *) (rp->init_data + 1);
|
uap = (struct raw3270_ua *) (rp->init_data + 1);
|
||||||
/* Paranoia check. */
|
/* Paranoia check. */
|
||||||
if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
|
if (rp->init_readmod.rc || rp->init_data[0] != 0x88 ||
|
||||||
return -EOPNOTSUPP;
|
uap->uab.qcode != 0x81) {
|
||||||
|
/* Couldn't detect size. Use default model 2. */
|
||||||
|
rp->model = 2;
|
||||||
|
rp->rows = 24;
|
||||||
|
rp->cols = 80;
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* Copy rows/columns of default Usable Area */
|
/* Copy rows/columns of default Usable Area */
|
||||||
rp->rows = uap->uab.h;
|
rp->rows = uap->uab.h;
|
||||||
rp->cols = uap->uab.w;
|
rp->cols = uap->uab.w;
|
||||||
@ -664,66 +529,131 @@ __raw3270_size_device(struct raw3270 *rp)
|
|||||||
rp->rows = uap->aua.hauai;
|
rp->rows = uap->aua.hauai;
|
||||||
rp->cols = uap->aua.wauai;
|
rp->cols = uap->aua.wauai;
|
||||||
}
|
}
|
||||||
return 0;
|
/* Try to find a model. */
|
||||||
|
rp->model = 0;
|
||||||
|
if (rp->rows == 24 && rp->cols == 80)
|
||||||
|
rp->model = 2;
|
||||||
|
if (rp->rows == 32 && rp->cols == 80)
|
||||||
|
rp->model = 3;
|
||||||
|
if (rp->rows == 43 && rp->cols == 80)
|
||||||
|
rp->model = 4;
|
||||||
|
if (rp->rows == 27 && rp->cols == 132)
|
||||||
|
rp->model = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
raw3270_size_device_done(struct raw3270 *rp)
|
||||||
|
{
|
||||||
|
struct raw3270_view *view;
|
||||||
|
|
||||||
|
rp->view = NULL;
|
||||||
|
rp->state = RAW3270_STATE_READY;
|
||||||
|
/* Notify views about new size */
|
||||||
|
list_for_each_entry(view, &rp->view_list, list)
|
||||||
|
if (view->fn->resize)
|
||||||
|
view->fn->resize(view, rp->model, rp->rows, rp->cols);
|
||||||
|
/* Setup processing done, now activate a view */
|
||||||
|
list_for_each_entry(view, &rp->view_list, list) {
|
||||||
|
rp->view = view;
|
||||||
|
if (view->fn->activate(view) == 0)
|
||||||
|
break;
|
||||||
|
rp->view = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
raw3270_read_modified_cb(struct raw3270_request *rq, void *data)
|
||||||
|
{
|
||||||
|
struct raw3270 *rp = rq->view->dev;
|
||||||
|
|
||||||
|
raw3270_size_device(rp);
|
||||||
|
raw3270_size_device_done(rp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
raw3270_read_modified(struct raw3270 *rp)
|
||||||
|
{
|
||||||
|
if (rp->state != RAW3270_STATE_W4ATTN)
|
||||||
|
return;
|
||||||
|
/* Use 'read modified' to get the result of a read partition. */
|
||||||
|
memset(&rp->init_readmod, 0, sizeof(rp->init_readmod));
|
||||||
|
memset(&rp->init_data, 0, sizeof(rp->init_data));
|
||||||
|
rp->init_readmod.ccw.cmd_code = TC_READMOD;
|
||||||
|
rp->init_readmod.ccw.flags = CCW_FLAG_SLI;
|
||||||
|
rp->init_readmod.ccw.count = sizeof(rp->init_data);
|
||||||
|
rp->init_readmod.ccw.cda = (__u32) __pa(rp->init_data);
|
||||||
|
rp->init_readmod.callback = raw3270_read_modified_cb;
|
||||||
|
rp->state = RAW3270_STATE_READMOD;
|
||||||
|
raw3270_start_irq(&rp->init_view, &rp->init_readmod);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
raw3270_writesf_readpart(struct raw3270 *rp)
|
||||||
|
{
|
||||||
|
static const unsigned char wbuf[] =
|
||||||
|
{ 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
|
||||||
|
|
||||||
|
/* Store 'read partition' data stream to init_data */
|
||||||
|
memset(&rp->init_readpart, 0, sizeof(rp->init_readpart));
|
||||||
|
memset(&rp->init_data, 0, sizeof(rp->init_data));
|
||||||
|
memcpy(&rp->init_data, wbuf, sizeof(wbuf));
|
||||||
|
rp->init_readpart.ccw.cmd_code = TC_WRITESF;
|
||||||
|
rp->init_readpart.ccw.flags = CCW_FLAG_SLI;
|
||||||
|
rp->init_readpart.ccw.count = sizeof(wbuf);
|
||||||
|
rp->init_readpart.ccw.cda = (__u32) __pa(&rp->init_data);
|
||||||
|
rp->state = RAW3270_STATE_W4ATTN;
|
||||||
|
raw3270_start_irq(&rp->init_view, &rp->init_readpart);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Device reset
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
raw3270_reset_device_cb(struct raw3270_request *rq, void *data)
|
||||||
|
{
|
||||||
|
struct raw3270 *rp = rq->view->dev;
|
||||||
|
|
||||||
|
if (rp->state != RAW3270_STATE_RESET)
|
||||||
|
return;
|
||||||
|
if (rq && rq->rc) {
|
||||||
|
/* Reset command failed. */
|
||||||
|
rp->state = RAW3270_STATE_INIT;
|
||||||
|
} else if (0 && MACHINE_IS_VM) {
|
||||||
|
raw3270_size_device_vm(rp);
|
||||||
|
raw3270_size_device_done(rp);
|
||||||
|
} else
|
||||||
|
raw3270_writesf_readpart(rp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
raw3270_size_device(struct raw3270 *rp)
|
__raw3270_reset_device(struct raw3270 *rp)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
mutex_lock(&raw3270_init_mutex);
|
/* Store reset data stream to init_data/init_reset */
|
||||||
rp->view = &raw3270_init_view;
|
memset(&rp->init_reset, 0, sizeof(rp->init_reset));
|
||||||
raw3270_init_view.dev = rp;
|
memset(&rp->init_data, 0, sizeof(rp->init_data));
|
||||||
if (MACHINE_IS_VM)
|
rp->init_data[0] = TW_KR;
|
||||||
rc = __raw3270_size_device_vm(rp);
|
rp->init_reset.ccw.cmd_code = TC_EWRITEA;
|
||||||
else
|
rp->init_reset.ccw.flags = CCW_FLAG_SLI;
|
||||||
rc = __raw3270_size_device(rp);
|
rp->init_reset.ccw.count = 1;
|
||||||
raw3270_init_view.dev = NULL;
|
rp->init_reset.ccw.cda = (__u32) __pa(rp->init_data);
|
||||||
rp->view = NULL;
|
rp->init_reset.callback = raw3270_reset_device_cb;
|
||||||
mutex_unlock(&raw3270_init_mutex);
|
rc = __raw3270_start(rp, &rp->init_view, &rp->init_reset);
|
||||||
if (rc == 0) { /* Found something. */
|
if (rc == 0 && rp->state == RAW3270_STATE_INIT)
|
||||||
/* Try to find a model. */
|
rp->state = RAW3270_STATE_RESET;
|
||||||
rp->model = 0;
|
|
||||||
if (rp->rows == 24 && rp->cols == 80)
|
|
||||||
rp->model = 2;
|
|
||||||
if (rp->rows == 32 && rp->cols == 80)
|
|
||||||
rp->model = 3;
|
|
||||||
if (rp->rows == 43 && rp->cols == 80)
|
|
||||||
rp->model = 4;
|
|
||||||
if (rp->rows == 27 && rp->cols == 132)
|
|
||||||
rp->model = 5;
|
|
||||||
} else {
|
|
||||||
/* Couldn't detect size. Use default model 2. */
|
|
||||||
rp->model = 2;
|
|
||||||
rp->rows = 24;
|
|
||||||
rp->cols = 80;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
raw3270_reset_device(struct raw3270 *rp)
|
raw3270_reset_device(struct raw3270 *rp)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
mutex_lock(&raw3270_init_mutex);
|
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
||||||
memset(&rp->init_request, 0, sizeof(rp->init_request));
|
rc = __raw3270_reset_device(rp);
|
||||||
memset(&rp->init_data, 0, sizeof(rp->init_data));
|
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
||||||
/* Store reset data stream to init_data/init_request */
|
|
||||||
rp->init_data[0] = TW_KR;
|
|
||||||
INIT_LIST_HEAD(&rp->init_request.list);
|
|
||||||
rp->init_request.ccw.cmd_code = TC_EWRITEA;
|
|
||||||
rp->init_request.ccw.flags = CCW_FLAG_SLI;
|
|
||||||
rp->init_request.ccw.count = 1;
|
|
||||||
rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
|
|
||||||
rp->view = &raw3270_init_view;
|
|
||||||
raw3270_init_view.dev = rp;
|
|
||||||
rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
|
|
||||||
raw3270_init_view.dev = NULL;
|
|
||||||
rp->view = NULL;
|
|
||||||
mutex_unlock(&raw3270_init_mutex);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -737,13 +667,50 @@ raw3270_reset(struct raw3270_view *view)
|
|||||||
if (!rp || rp->view != view ||
|
if (!rp || rp->view != view ||
|
||||||
test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
|
test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
|
||||||
rc = -EACCES;
|
rc = -EACCES;
|
||||||
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
|
else if (!raw3270_state_ready(rp))
|
||||||
rc = -ENODEV;
|
rc = -EBUSY;
|
||||||
else
|
else
|
||||||
rc = raw3270_reset_device(view->dev);
|
rc = raw3270_reset_device(view->dev);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq,
|
||||||
|
struct irb *irb)
|
||||||
|
{
|
||||||
|
struct raw3270 *rp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unit-Check Processing:
|
||||||
|
* Expect Command Reject or Intervention Required.
|
||||||
|
*/
|
||||||
|
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
|
||||||
|
/* Request finished abnormally. */
|
||||||
|
if (irb->ecw[0] & SNS0_INTERVENTION_REQ) {
|
||||||
|
set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags);
|
||||||
|
return RAW3270_IO_BUSY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rq) {
|
||||||
|
if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
|
||||||
|
if (irb->ecw[0] & SNS0_CMD_REJECT)
|
||||||
|
rq->rc = -EOPNOTSUPP;
|
||||||
|
else
|
||||||
|
rq->rc = -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
|
||||||
|
/* Queue read modified after attention interrupt */
|
||||||
|
rp = view->dev;
|
||||||
|
raw3270_read_modified(rp);
|
||||||
|
}
|
||||||
|
return RAW3270_IO_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct raw3270_fn raw3270_init_fn = {
|
||||||
|
.intv = raw3270_init_irq
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup new 3270 device.
|
* Setup new 3270 device.
|
||||||
*/
|
*/
|
||||||
@ -772,6 +739,10 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
|
|||||||
INIT_LIST_HEAD(&rp->req_queue);
|
INIT_LIST_HEAD(&rp->req_queue);
|
||||||
INIT_LIST_HEAD(&rp->view_list);
|
INIT_LIST_HEAD(&rp->view_list);
|
||||||
|
|
||||||
|
rp->init_view.dev = rp;
|
||||||
|
rp->init_view.fn = &raw3270_init_fn;
|
||||||
|
rp->view = &rp->init_view;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add device to list and find the smallest unused minor
|
* Add device to list and find the smallest unused minor
|
||||||
* number for it. Note: there is no device with minor 0,
|
* number for it. Note: there is no device with minor 0,
|
||||||
@ -810,6 +781,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
|
|||||||
*/
|
*/
|
||||||
struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
|
struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
struct raw3270 *rp;
|
struct raw3270 *rp;
|
||||||
char *ascebc;
|
char *ascebc;
|
||||||
int rc;
|
int rc;
|
||||||
@ -820,16 +792,15 @@ struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return ERR_PTR(rc);
|
return ERR_PTR(rc);
|
||||||
set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
|
set_bit(RAW3270_FLAGS_CONSOLE, &rp->flags);
|
||||||
rc = raw3270_reset_device(rp);
|
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
||||||
if (rc)
|
do {
|
||||||
return ERR_PTR(rc);
|
__raw3270_reset_device(rp);
|
||||||
rc = raw3270_size_device(rp);
|
while (!raw3270_state_final(rp)) {
|
||||||
if (rc)
|
wait_cons_dev();
|
||||||
return ERR_PTR(rc);
|
barrier();
|
||||||
rc = raw3270_reset_device(rp);
|
}
|
||||||
if (rc)
|
} while (rp->state != RAW3270_STATE_READY);
|
||||||
return ERR_PTR(rc);
|
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
||||||
set_bit(RAW3270_FLAGS_READY, &rp->flags);
|
|
||||||
return rp;
|
return rp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -891,13 +862,13 @@ raw3270_activate_view(struct raw3270_view *view)
|
|||||||
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
||||||
if (rp->view == view)
|
if (rp->view == view)
|
||||||
rc = 0;
|
rc = 0;
|
||||||
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
|
else if (!raw3270_state_ready(rp))
|
||||||
rc = -ENODEV;
|
rc = -EBUSY;
|
||||||
else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
|
else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
|
||||||
rc = -EACCES;
|
rc = -EACCES;
|
||||||
else {
|
else {
|
||||||
oldview = NULL;
|
oldview = NULL;
|
||||||
if (rp->view) {
|
if (rp->view && rp->view->fn->deactivate) {
|
||||||
oldview = rp->view;
|
oldview = rp->view;
|
||||||
oldview->fn->deactivate(oldview);
|
oldview->fn->deactivate(oldview);
|
||||||
}
|
}
|
||||||
@ -942,7 +913,7 @@ raw3270_deactivate_view(struct raw3270_view *view)
|
|||||||
list_del_init(&view->list);
|
list_del_init(&view->list);
|
||||||
list_add_tail(&view->list, &rp->view_list);
|
list_add_tail(&view->list, &rp->view_list);
|
||||||
/* Try to activate another view. */
|
/* Try to activate another view. */
|
||||||
if (test_bit(RAW3270_FLAGS_READY, &rp->flags) &&
|
if (raw3270_state_ready(rp) &&
|
||||||
!test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
|
!test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
|
||||||
list_for_each_entry(view, &rp->view_list, list) {
|
list_for_each_entry(view, &rp->view_list, list) {
|
||||||
rp->view = view;
|
rp->view = view;
|
||||||
@ -973,18 +944,16 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
|
|||||||
if (rp->minor != minor)
|
if (rp->minor != minor)
|
||||||
continue;
|
continue;
|
||||||
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
||||||
if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
|
atomic_set(&view->ref_count, 2);
|
||||||
atomic_set(&view->ref_count, 2);
|
view->dev = rp;
|
||||||
view->dev = rp;
|
view->fn = fn;
|
||||||
view->fn = fn;
|
view->model = rp->model;
|
||||||
view->model = rp->model;
|
view->rows = rp->rows;
|
||||||
view->rows = rp->rows;
|
view->cols = rp->cols;
|
||||||
view->cols = rp->cols;
|
view->ascebc = rp->ascebc;
|
||||||
view->ascebc = rp->ascebc;
|
spin_lock_init(&view->lock);
|
||||||
spin_lock_init(&view->lock);
|
list_add(&view->list, &rp->view_list);
|
||||||
list_add(&view->list, &rp->view_list);
|
rc = 0;
|
||||||
rc = 0;
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1008,14 +977,11 @@ raw3270_find_view(struct raw3270_fn *fn, int minor)
|
|||||||
if (rp->minor != minor)
|
if (rp->minor != minor)
|
||||||
continue;
|
continue;
|
||||||
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
||||||
if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
|
list_for_each_entry(tmp, &rp->view_list, list) {
|
||||||
view = ERR_PTR(-ENOENT);
|
if (tmp->fn == fn) {
|
||||||
list_for_each_entry(tmp, &rp->view_list, list) {
|
raw3270_get_view(tmp);
|
||||||
if (tmp->fn == fn) {
|
view = tmp;
|
||||||
raw3270_get_view(tmp);
|
break;
|
||||||
view = tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
||||||
@ -1042,7 +1008,7 @@ raw3270_del_view(struct raw3270_view *view)
|
|||||||
rp->view = NULL;
|
rp->view = NULL;
|
||||||
}
|
}
|
||||||
list_del_init(&view->list);
|
list_del_init(&view->list);
|
||||||
if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags) &&
|
if (!rp->view && raw3270_state_ready(rp) &&
|
||||||
!test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
|
!test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) {
|
||||||
/* Try to activate another view. */
|
/* Try to activate another view. */
|
||||||
list_for_each_entry(nv, &rp->view_list, list) {
|
list_for_each_entry(nv, &rp->view_list, list) {
|
||||||
@ -1177,19 +1143,10 @@ raw3270_set_online (struct ccw_device *cdev)
|
|||||||
rp = raw3270_create_device(cdev);
|
rp = raw3270_create_device(cdev);
|
||||||
if (IS_ERR(rp))
|
if (IS_ERR(rp))
|
||||||
return PTR_ERR(rp);
|
return PTR_ERR(rp);
|
||||||
rc = raw3270_reset_device(rp);
|
|
||||||
if (rc)
|
|
||||||
goto failure;
|
|
||||||
rc = raw3270_size_device(rp);
|
|
||||||
if (rc)
|
|
||||||
goto failure;
|
|
||||||
rc = raw3270_reset_device(rp);
|
|
||||||
if (rc)
|
|
||||||
goto failure;
|
|
||||||
rc = raw3270_create_attributes(rp);
|
rc = raw3270_create_attributes(rp);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto failure;
|
goto failure;
|
||||||
set_bit(RAW3270_FLAGS_READY, &rp->flags);
|
raw3270_reset_device(rp);
|
||||||
mutex_lock(&raw3270_mutex);
|
mutex_lock(&raw3270_mutex);
|
||||||
list_for_each_entry(np, &raw3270_notifier, list)
|
list_for_each_entry(np, &raw3270_notifier, list)
|
||||||
np->create(rp->minor);
|
np->create(rp->minor);
|
||||||
@ -1221,14 +1178,14 @@ raw3270_remove (struct ccw_device *cdev)
|
|||||||
*/
|
*/
|
||||||
if (rp == NULL)
|
if (rp == NULL)
|
||||||
return;
|
return;
|
||||||
clear_bit(RAW3270_FLAGS_READY, &rp->flags);
|
|
||||||
|
|
||||||
sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
|
sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
|
||||||
|
|
||||||
/* Deactivate current view and remove all views. */
|
/* Deactivate current view and remove all views. */
|
||||||
spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
|
spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
|
||||||
if (rp->view) {
|
if (rp->view) {
|
||||||
rp->view->fn->deactivate(rp->view);
|
if (rp->view->fn->deactivate)
|
||||||
|
rp->view->fn->deactivate(rp->view);
|
||||||
rp->view = NULL;
|
rp->view = NULL;
|
||||||
}
|
}
|
||||||
while (!list_empty(&rp->view_list)) {
|
while (!list_empty(&rp->view_list)) {
|
||||||
@ -1277,7 +1234,7 @@ static int raw3270_pm_stop(struct ccw_device *cdev)
|
|||||||
if (!rp)
|
if (!rp)
|
||||||
return 0;
|
return 0;
|
||||||
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
||||||
if (rp->view)
|
if (rp->view && rp->view->fn->deactivate)
|
||||||
rp->view->fn->deactivate(rp->view);
|
rp->view->fn->deactivate(rp->view);
|
||||||
if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) {
|
if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) {
|
||||||
/*
|
/*
|
||||||
@ -1304,7 +1261,7 @@ static int raw3270_pm_start(struct ccw_device *cdev)
|
|||||||
return 0;
|
return 0;
|
||||||
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
|
||||||
clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
|
clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags);
|
||||||
if (rp->view)
|
if (rp->view && rp->view->fn->activate)
|
||||||
rp->view->fn->activate(rp->view);
|
rp->view->fn->activate(rp->view);
|
||||||
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -141,6 +141,7 @@ struct raw3270_fn {
|
|||||||
struct raw3270_request *, struct irb *);
|
struct raw3270_request *, struct irb *);
|
||||||
void (*release)(struct raw3270_view *);
|
void (*release)(struct raw3270_view *);
|
||||||
void (*free)(struct raw3270_view *);
|
void (*free)(struct raw3270_view *);
|
||||||
|
void (*resize)(struct raw3270_view *, int, int, int);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/console.h>
|
#include <linux/console.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/bootmem.h>
|
#include <linux/bootmem.h>
|
||||||
@ -80,6 +81,8 @@ struct tty3270 {
|
|||||||
unsigned int highlight; /* Blink/reverse/underscore */
|
unsigned int highlight; /* Blink/reverse/underscore */
|
||||||
unsigned int f_color; /* Foreground color */
|
unsigned int f_color; /* Foreground color */
|
||||||
struct tty3270_line *screen;
|
struct tty3270_line *screen;
|
||||||
|
unsigned int n_model, n_cols, n_rows; /* New model & size */
|
||||||
|
struct work_struct resize_work;
|
||||||
|
|
||||||
/* Input stuff. */
|
/* Input stuff. */
|
||||||
struct string *prompt; /* Output string for input area. */
|
struct string *prompt; /* Output string for input area. */
|
||||||
@ -115,6 +118,7 @@ struct tty3270 {
|
|||||||
#define TTY_UPDATE_ALL 16 /* Recreate screen. */
|
#define TTY_UPDATE_ALL 16 /* Recreate screen. */
|
||||||
|
|
||||||
static void tty3270_update(struct tty3270 *);
|
static void tty3270_update(struct tty3270 *);
|
||||||
|
static void tty3270_resize_work(struct work_struct *work);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup timeout for a device. On timeout trigger an update.
|
* Setup timeout for a device. On timeout trigger an update.
|
||||||
@ -711,6 +715,7 @@ tty3270_alloc_view(void)
|
|||||||
tasklet_init(&tp->readlet,
|
tasklet_init(&tp->readlet,
|
||||||
(void (*)(unsigned long)) tty3270_read_tasklet,
|
(void (*)(unsigned long)) tty3270_read_tasklet,
|
||||||
(unsigned long) tp->read);
|
(unsigned long) tp->read);
|
||||||
|
INIT_WORK(&tp->resize_work, tty3270_resize_work);
|
||||||
|
|
||||||
return tp;
|
return tp;
|
||||||
|
|
||||||
@ -754,42 +759,96 @@ tty3270_free_view(struct tty3270 *tp)
|
|||||||
/*
|
/*
|
||||||
* Allocate tty3270 screen.
|
* Allocate tty3270 screen.
|
||||||
*/
|
*/
|
||||||
static int
|
static struct tty3270_line *
|
||||||
tty3270_alloc_screen(struct tty3270 *tp)
|
tty3270_alloc_screen(unsigned int rows, unsigned int cols)
|
||||||
{
|
{
|
||||||
|
struct tty3270_line *screen;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
int lines;
|
int lines;
|
||||||
|
|
||||||
size = sizeof(struct tty3270_line) * (tp->view.rows - 2);
|
size = sizeof(struct tty3270_line) * (rows - 2);
|
||||||
tp->screen = kzalloc(size, GFP_KERNEL);
|
screen = kzalloc(size, GFP_KERNEL);
|
||||||
if (!tp->screen)
|
if (!screen)
|
||||||
goto out_err;
|
goto out_err;
|
||||||
for (lines = 0; lines < tp->view.rows - 2; lines++) {
|
for (lines = 0; lines < rows - 2; lines++) {
|
||||||
size = sizeof(struct tty3270_cell) * tp->view.cols;
|
size = sizeof(struct tty3270_cell) * cols;
|
||||||
tp->screen[lines].cells = kzalloc(size, GFP_KERNEL);
|
screen[lines].cells = kzalloc(size, GFP_KERNEL);
|
||||||
if (!tp->screen[lines].cells)
|
if (!screen[lines].cells)
|
||||||
goto out_screen;
|
goto out_screen;
|
||||||
}
|
}
|
||||||
return 0;
|
return screen;
|
||||||
out_screen:
|
out_screen:
|
||||||
while (lines--)
|
while (lines--)
|
||||||
kfree(tp->screen[lines].cells);
|
kfree(screen[lines].cells);
|
||||||
kfree(tp->screen);
|
kfree(screen);
|
||||||
out_err:
|
out_err:
|
||||||
return -ENOMEM;
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free tty3270 screen.
|
* Free tty3270 screen.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
tty3270_free_screen(struct tty3270 *tp)
|
tty3270_free_screen(struct tty3270_line *screen, unsigned int rows)
|
||||||
{
|
{
|
||||||
int lines;
|
int lines;
|
||||||
|
|
||||||
for (lines = 0; lines < tp->view.rows - 2; lines++)
|
for (lines = 0; lines < rows - 2; lines++)
|
||||||
kfree(tp->screen[lines].cells);
|
kfree(screen[lines].cells);
|
||||||
kfree(tp->screen);
|
kfree(screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resize tty3270 screen
|
||||||
|
*/
|
||||||
|
static void tty3270_resize_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct tty3270 *tp = container_of(work, struct tty3270, resize_work);
|
||||||
|
struct tty3270_line *screen, *oscreen;
|
||||||
|
struct tty_struct *tty;
|
||||||
|
unsigned int orows;
|
||||||
|
struct winsize ws;
|
||||||
|
|
||||||
|
screen = tty3270_alloc_screen(tp->n_rows, tp->n_cols);
|
||||||
|
if (!screen)
|
||||||
|
return;
|
||||||
|
/* Switch to new output size */
|
||||||
|
spin_lock_bh(&tp->view.lock);
|
||||||
|
oscreen = tp->screen;
|
||||||
|
orows = tp->view.rows;
|
||||||
|
tp->view.model = tp->n_model;
|
||||||
|
tp->view.rows = tp->n_rows;
|
||||||
|
tp->view.cols = tp->n_cols;
|
||||||
|
tp->screen = screen;
|
||||||
|
free_string(&tp->freemem, tp->prompt);
|
||||||
|
free_string(&tp->freemem, tp->status);
|
||||||
|
tty3270_create_prompt(tp);
|
||||||
|
tty3270_create_status(tp);
|
||||||
|
tp->nr_up = 0;
|
||||||
|
while (tp->nr_lines < tp->view.rows - 2)
|
||||||
|
tty3270_blank_line(tp);
|
||||||
|
tp->update_flags = TTY_UPDATE_ALL;
|
||||||
|
spin_unlock_bh(&tp->view.lock);
|
||||||
|
tty3270_free_screen(oscreen, orows);
|
||||||
|
tty3270_set_timer(tp, 1);
|
||||||
|
/* Informat tty layer about new size */
|
||||||
|
tty = tty_port_tty_get(&tp->port);
|
||||||
|
if (!tty)
|
||||||
|
return;
|
||||||
|
ws.ws_row = tp->view.rows - 2;
|
||||||
|
ws.ws_col = tp->view.cols;
|
||||||
|
tty_do_resize(tty, &ws);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
tty3270_resize(struct raw3270_view *view, int model, int rows, int cols)
|
||||||
|
{
|
||||||
|
struct tty3270 *tp = container_of(view, struct tty3270, view);
|
||||||
|
|
||||||
|
tp->n_model = model;
|
||||||
|
tp->n_rows = rows;
|
||||||
|
tp->n_cols = cols;
|
||||||
|
schedule_work(&tp->resize_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -817,7 +876,8 @@ static void
|
|||||||
tty3270_free(struct raw3270_view *view)
|
tty3270_free(struct raw3270_view *view)
|
||||||
{
|
{
|
||||||
struct tty3270 *tp = container_of(view, struct tty3270, view);
|
struct tty3270 *tp = container_of(view, struct tty3270, view);
|
||||||
tty3270_free_screen(tp);
|
|
||||||
|
tty3270_free_screen(tp->screen, tp->view.rows);
|
||||||
tty3270_free_view(tp);
|
tty3270_free_view(tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,7 +901,8 @@ static struct raw3270_fn tty3270_fn = {
|
|||||||
.deactivate = tty3270_deactivate,
|
.deactivate = tty3270_deactivate,
|
||||||
.intv = (void *) tty3270_irq,
|
.intv = (void *) tty3270_irq,
|
||||||
.release = tty3270_release,
|
.release = tty3270_release,
|
||||||
.free = tty3270_free
|
.free = tty3270_free,
|
||||||
|
.resize = tty3270_resize
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -869,10 +930,6 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||||||
if (tty3270_max_index < tty->index)
|
if (tty3270_max_index < tty->index)
|
||||||
tty3270_max_index = tty->index;
|
tty3270_max_index = tty->index;
|
||||||
|
|
||||||
/* Quick exit if there is no device for tty->index. */
|
|
||||||
if (PTR_ERR(view) == -ENODEV)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
/* Allocate tty3270 structure on first open. */
|
/* Allocate tty3270 structure on first open. */
|
||||||
tp = tty3270_alloc_view();
|
tp = tty3270_alloc_view();
|
||||||
if (IS_ERR(tp))
|
if (IS_ERR(tp))
|
||||||
@ -884,10 +941,12 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = tty3270_alloc_screen(tp);
|
tp->screen = tty3270_alloc_screen(tp->view.cols, tp->view.rows);
|
||||||
if (rc) {
|
if (IS_ERR(tp->screen)) {
|
||||||
|
rc = PTR_ERR(tp->screen);
|
||||||
raw3270_put_view(&tp->view);
|
raw3270_put_view(&tp->view);
|
||||||
raw3270_del_view(&tp->view);
|
raw3270_del_view(&tp->view);
|
||||||
|
tty3270_free_view(tp);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2203,6 +2203,7 @@ done:
|
|||||||
mutex_unlock(&tty->termios_mutex);
|
mutex_unlock(&tty->termios_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(tty_do_resize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tiocswinsz - implement window size set ioctl
|
* tiocswinsz - implement window size set ioctl
|
||||||
|
Loading…
Reference in New Issue
Block a user