// SPDX-License-Identifier: GPL-2.0 /* * IBM/3270 Driver - core functions. * * Author(s): * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> * Copyright IBM Corp. 2003, 2009
*/
/* 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 */ #define RAW3270_FLAGS_14BITADDR 0 /* 14-bit buffer addresses */ #define RAW3270_FLAGS_BUSY 1 /* Device busy, leave it alone */ #define RAW3270_FLAGS_CONSOLE 2 /* Device is the console. */
/* Semaphore to protect global data of raw3270 (devices, views, etc). */ static DEFINE_MUTEX(raw3270_mutex);
/* List of 3270 devices. */ static LIST_HEAD(raw3270_devices);
/* * Flag to indicate if the driver has been registered. Some operations * like waiting for the end of i/o need to be done differently as long * as the kernel is still starting up (console support).
*/ staticint raw3270_registered;
/* * Set command code to ccw of a request.
*/ void raw3270_request_set_cmd(struct raw3270_request *rq, u8 cmd)
{
rq->ccw.cmd_code = cmd;
}
EXPORT_SYMBOL(raw3270_request_set_cmd);
/* * Add data fragment to output buffer.
*/ int raw3270_request_add_data(struct raw3270_request *rq, void *data, size_t size)
{ if (size + rq->ccw.count > rq->size) return -E2BIG;
memcpy(rq->buffer + rq->ccw.count, data, size);
rq->ccw.count += size; return 0;
}
EXPORT_SYMBOL(raw3270_request_add_data);
/* * Set address/length pair to ccw of a request.
*/ void raw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size)
{
rq->ccw.cda = virt_to_dma32(data);
rq->ccw.count = size;
}
EXPORT_SYMBOL(raw3270_request_set_data);
/* * Set idal buffer to ccw of a request.
*/ void raw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib)
{
rq->ccw.cda = virt_to_dma32(ib->data);
rq->ccw.count = ib->size;
rq->ccw.flags |= CCW_FLAG_IDA;
}
EXPORT_SYMBOL(raw3270_request_set_idal);
/* * 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.
*/ staticint __raw3270_start(struct raw3270 *rp, struct raw3270_view *view, struct raw3270_request *rq)
{
rq->view = view;
raw3270_get_view(view); if (list_empty(&rp->req_queue) &&
!test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) { /* No other requests are on the queue. Start this one. */
rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
(unsignedlong)rq, 0, 0); if (rq->rc) {
raw3270_put_view(view); return rq->rc;
}
}
list_add_tail(&rq->list, &rp->req_queue); return 0;
}
int raw3270_view_active(struct raw3270_view *view)
{ struct raw3270 *rp = view->dev;
return rp && rp->view == view;
}
int raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
{ unsignedlong flags; struct raw3270 *rp; int rc;
/* * 3270 interrupt routine, called from the ccw_device layer
*/ staticvoid raw3270_irq(struct ccw_device *cdev, unsignedlong intparm, struct irb *irb)
{ struct raw3270 *rp; struct raw3270_view *view; struct raw3270_request *rq;
rp = dev_get_drvdata(&cdev->dev); if (!rp) return;
rq = (struct raw3270_request *)intparm;
view = rq ? rq->view : rp->view;
if (!IS_ERR(irb)) { /* Handle CE-DE-UE and subsequent UDE */ if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END)
clear_bit(RAW3270_FLAGS_BUSY, &rp->flags); if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END |
DEV_STAT_DEV_END |
DEV_STAT_UNIT_EXCEP))
set_bit(RAW3270_FLAGS_BUSY, &rp->flags); /* Handle disconnected devices */ if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
(irb->ecw[0] & SNS0_INTERVENTION_REQ)) {
set_bit(RAW3270_FLAGS_BUSY, &rp->flags); if (rp->state > RAW3270_STATE_RESET)
__raw3270_disconnect(rp);
} /* Call interrupt handler of the view */ if (view)
view->fn->intv(view, rq, irb);
}
if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) /* Device busy, do not start I/O */ return;
if (rq && !list_empty(&rq->list)) { /* The request completed, remove from queue and do callback. */
list_del_init(&rq->list); if (rq->callback)
rq->callback(rq, rq->callback_data); /* Do put_device for get_device in raw3270_start. */
raw3270_put_view(view);
}
/* * Try to start each request on request queue until one is * started successful.
*/ while (!list_empty(&rp->req_queue)) {
rq = list_entry(rp->req_queue.next, struct raw3270_request, list);
rq->rc = ccw_device_start(rp->cdev, &rq->ccw,
(unsignedlong)rq, 0, 0); if (rq->rc == 0) break; /* Start failed. Remove request and do callback. */
list_del_init(&rq->list); if (rq->callback)
rq->callback(rq, rq->callback_data); /* Do put_device for get_device in raw3270_start. */
raw3270_put_view(view);
}
}
/* * 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 { /* Usable Area Query Reply Base */ short l; /* Length of this structured field */ char sfid; /* 0x81 if Query Reply */ char qcode; /* 0x81 if Usable Area */ char flags0; char flags1; short w; /* Width of usable area */ short h; /* Heigth of usavle area */ char units; /* 0x00:in; 0x01:mm */ int xr; int yr; char aw; char ah; short buffsz; /* Character buffer size, bytes */ char xmin; char ymin; char xmax; char ymax;
} __packed uab; struct { /* Alternate Usable Area Self-Defining Parameter */ char l; /* Length of this Self-Defining Parm */ char sdpid; /* 0x02 if Alternate Usable Area */ char res; char auaid; /* 0x01 is Id for the A U A */ short wauai; /* Width of AUAi */ short hauai; /* Height of AUAi */ char auaunits; /* 0x00:in, 0x01:mm */ int auaxr; int auayr; char awauai; char ahauai;
} __packed aua;
} __packed;
/* * Add device to list and find the smallest unused minor * number for it. Note: there is no device with minor 0, * see special case for fs3270.c:fs3270_open().
*/
mutex_lock(&raw3270_mutex); /* Keep the list sorted. */
minor = RAW3270_FIRSTMINOR;
rp->minor = -1;
list_for_each(l, &raw3270_devices) {
tmp = list_entry(l, struct raw3270, list); if (tmp->minor > minor) {
rp->minor = minor;
__list_add(&rp->list, l->prev, l); break;
}
minor++;
} if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) {
rp->minor = minor;
list_add_tail(&rp->list, &raw3270_devices);
}
mutex_unlock(&raw3270_mutex); /* No free minor number? Then give up. */ if (rp->minor == -1) return -EUSERS;
rp->cdev = cdev;
dev_set_drvdata(&cdev->dev, rp);
cdev->handler = raw3270_irq; return 0;
}
#ifdef CONFIG_TN3270_CONSOLE /* Tentative definition - see below for actual definition. */ staticstruct ccw_driver raw3270_ccw_driver;
rp = kzalloc(sizeof(*rp), GFP_KERNEL | GFP_DMA); if (!rp) return ERR_PTR(-ENOMEM);
ascebc = kmalloc(256, GFP_KERNEL); if (!ascebc) {
kfree(rp); return ERR_PTR(-ENOMEM);
}
rc = raw3270_setup_device(cdev, rp, ascebc); if (rc) {
kfree(rp->ascebc);
kfree(rp);
rp = ERR_PTR(rc);
} /* Get reference to ccw_device structure. */
get_device(&cdev->dev); return rp;
}
/* * This helper just validates that it is safe to activate a * view in the panic() context, due to locking restrictions.
*/ int raw3270_view_lock_unavailable(struct raw3270_view *view)
{ struct raw3270 *rp = view->dev;
if (!rp) return -ENODEV; if (spin_is_locked(get_ccwdev_lock(rp->cdev))) return -EBUSY; return 0;
}
rp = view->dev; if (!rp) return;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); if (rp->view == view) {
view->fn->deactivate(view);
rp->view = NULL; /* Move deactivated view to end of list. */
list_del_init(&view->list);
list_add_tail(&view->list, &rp->view_list); /* Try to activate another view. */ if (raw3270_state_ready(rp)) {
list_for_each_entry(view, &rp->view_list, list) {
rp->view = view; if (view->fn->activate(view) == 0) break;
rp->view = NULL;
}
}
}
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
}
EXPORT_SYMBOL(raw3270_deactivate_view);
/* * Add view to device with minor "minor".
*/ int raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor, int subclass)
{ unsignedlong flags; struct raw3270 *rp; int rc;
rp = dev_get_drvdata(&cdev->dev); /* * _remove is the opposite of _probe; it's probe that * should set up rp. raw3270_remove gets entered for * devices even if they haven't been varied online. * Thus, rp may validly be NULL here.
*/ if (!rp) return;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.