⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 raw3270.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  drivers/s390/char/raw3270.c *    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 (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation */#include <linux/config.h>#include <linux/bootmem.h>#include <linux/module.h>#include <linux/err.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/wait.h>#include <asm/ccwdev.h>#include <asm/cio.h>#include <asm/ebcdic.h>#include "raw3270.h"#include <linux/major.h>#include <linux/kdev_t.h>#include <linux/device.h>struct class *class3270;/* The main 3270 data structure. */struct raw3270 {	struct list_head list;	struct ccw_device *cdev;	int minor;	short model, rows, cols;	unsigned long flags;	struct list_head req_queue;	/* Request queue. */	struct list_head view_list;	/* List of available views. */	struct raw3270_view *view;	/* Active view. */	struct timer_list timer;	/* Device timer. */	unsigned char *ascebc;		/* ascii -> ebcdic table */	struct class_device *clttydev;	/* 3270-class tty device ptr */	struct class_device *cltubdev;	/* 3270-class tub device ptr */};/* raw3270->flags */#define RAW3270_FLAGS_14BITADDR	0	/* 14-bit buffer addresses */#define RAW3270_FLAGS_BUSY	1	/* Device busy, leave it alone */#define RAW3270_FLAGS_ATTN	2	/* Device sent an ATTN interrupt */#define RAW3270_FLAGS_READY	4	/* Device is useable by views */#define RAW3270_FLAGS_CONSOLE	8	/* Device is the console. *//* Semaphore to protect global data of raw3270 (devices, views, etc). */static DECLARE_MUTEX(raw3270_sem);/* List of 3270 devices. */static struct list_head raw3270_devices = LIST_HEAD_INIT(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). */static int raw3270_registered;/* Module parameters */static int tubxcorrect = 0;module_param(tubxcorrect, bool, 0);/* * Wait queue for device init/delete, view delete. */DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);/* * Encode array for 12 bit 3270 addresses. */unsigned char raw3270_ebcgraf[64] =	{	0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,	0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,	0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,	0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,	0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,	0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,	0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f};voidraw3270_buffer_address(struct raw3270 *rp, char *cp, unsigned short addr){	if (test_bit(RAW3270_FLAGS_14BITADDR, &rp->flags)) {		cp[0] = (addr >> 8) & 0x3f;		cp[1] = addr & 0xff;	} else {		cp[0] = raw3270_ebcgraf[(addr >> 6) & 0x3f];		cp[1] = raw3270_ebcgraf[addr & 0x3f];	}}/* * Allocate a new 3270 ccw request */struct raw3270_request *raw3270_request_alloc(size_t size){	struct raw3270_request *rq;	/* Allocate request structure */	rq = kmalloc(sizeof(struct raw3270_request), GFP_KERNEL | GFP_DMA);	if (!rq)		return ERR_PTR(-ENOMEM);	memset(rq, 0, sizeof(struct raw3270_request));	/* alloc output buffer. */	if (size > 0) {		rq->buffer = kmalloc(size, GFP_KERNEL | GFP_DMA);		if (!rq->buffer) {			kfree(rq);			return ERR_PTR(-ENOMEM);		}	}	rq->size = size;	INIT_LIST_HEAD(&rq->list);	/*	 * Setup ccw.	 */	rq->ccw.cda = __pa(rq->buffer);	rq->ccw.flags = CCW_FLAG_SLI;	return rq;}#ifdef CONFIG_TN3270_CONSOLE/* * Allocate a new 3270 ccw request from bootmem. Only works very * early in the boot process. Only con3270.c should be using this. */struct raw3270_request *raw3270_request_alloc_bootmem(size_t size){	struct raw3270_request *rq;	rq = alloc_bootmem_low(sizeof(struct raw3270));	if (!rq)		return ERR_PTR(-ENOMEM);	memset(rq, 0, sizeof(struct raw3270_request));	/* alloc output buffer. */	if (size > 0) {		rq->buffer = alloc_bootmem_low(size);		if (!rq->buffer) {			free_bootmem((unsigned long) rq,				     sizeof(struct raw3270));			return ERR_PTR(-ENOMEM);		}	}	rq->size = size;	INIT_LIST_HEAD(&rq->list);	/*	 * Setup ccw.	 */	rq->ccw.cda = __pa(rq->buffer);	rq->ccw.flags = CCW_FLAG_SLI;	return rq;}#endif/* * Free 3270 ccw request */voidraw3270_request_free (struct raw3270_request *rq){	kfree(rq->buffer);	kfree(rq);}/* * Reset request to initial state. */voidraw3270_request_reset(struct raw3270_request *rq){	BUG_ON(!list_empty(&rq->list));	rq->ccw.cmd_code = 0;	rq->ccw.count = 0;	rq->ccw.cda = __pa(rq->buffer);	rq->ccw.flags = CCW_FLAG_SLI;	rq->rescnt = 0;	rq->rc = 0;}/* * Set command code to ccw of a request. */voidraw3270_request_set_cmd(struct raw3270_request *rq, u8 cmd){	rq->ccw.cmd_code = cmd;}/* * Add data fragment to output buffer. */intraw3270_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;}/* * Set address/length pair to ccw of a request. */voidraw3270_request_set_data(struct raw3270_request *rq, void *data, size_t size){	rq->ccw.cda = __pa(data);	rq->ccw.count = size;}/* * Set idal buffer to ccw of a request. */voidraw3270_request_set_idal(struct raw3270_request *rq, struct idal_buffer *ib){	rq->ccw.cda = __pa(ib->data);	rq->ccw.count = ib->size;	rq->ccw.flags |= CCW_FLAG_IDA;}/* * Stop running ccw. */static intraw3270_halt_io_nolock(struct raw3270 *rp, struct raw3270_request *rq){	int retries;	int rc;	if (raw3270_request_final(rq))		return 0;	/* Check if interrupt has already been processed */	for (retries = 0; retries < 5; retries++) {		if (retries < 2)			rc = ccw_device_halt(rp->cdev, (long) rq);		else			rc = ccw_device_clear(rp->cdev, (long) rq);		if (rc == 0)			break;		/* termination successful */	}	return rc;}static intraw3270_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 * 3270 device is idle. Return without waiting for end of i/o. */static int__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,					       (unsigned long) rq, 0, 0);		if (rq->rc) {			raw3270_put_view(view);			return rq->rc;		}	}	list_add_tail(&rq->list, &rp->req_queue);	return 0;}intraw3270_start(struct raw3270_view *view, struct raw3270_request *rq){	unsigned long flags;	struct raw3270 *rp;	int rc;	spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);	rp = view->dev;	if (!rp || rp->view != view)		rc = -EACCES;	else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))		rc = -ENODEV;	else		rc =  __raw3270_start(rp, view, rq);	spin_unlock_irqrestore(get_ccwdev_lock(view->dev->cdev), flags);	return rc;}intraw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq){	struct raw3270 *rp;	int rc;	rp = view->dev;	if (!rp || rp->view != view)		rc = -EACCES;	else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))		rc = -ENODEV;	else		rc =  __raw3270_start(rp, view, rq);	return rc;}intraw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq){	struct raw3270 *rp;	rp = view->dev;	rq->view = view;	raw3270_get_view(view);	list_add_tail(&rq->list, &rp->req_queue);	return 0;}/* * 3270 interrupt routine, called from the ccw_device layer */static voidraw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb){	struct raw3270 *rp;	struct raw3270_view *view;	struct raw3270_request *rq;	int rc;	rp = (struct raw3270 *) cdev->dev.driver_data;	if (!rp)		return;	rq = (struct raw3270_request *) intparm;	view = rq ? rq->view : rp->view;	if (IS_ERR(irb))		rc = RAW3270_IO_RETRY;	else if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) {		rq->rc = -EIO;		rc = RAW3270_IO_DONE;	} else if (irb->scsw.dstat ==  (DEV_STAT_CHN_END | DEV_STAT_DEV_END |					DEV_STAT_UNIT_EXCEP)) {		/* Handle CE-DE-UE and subsequent UDE */		set_bit(RAW3270_FLAGS_BUSY, &rp->flags);		rc = RAW3270_IO_BUSY;	} else if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) {		/* Wait for UDE if busy flag is set. */		if (irb->scsw.dstat & DEV_STAT_DEV_END) {			clear_bit(RAW3270_FLAGS_BUSY, &rp->flags);			/* Got it, now retry. */			rc = RAW3270_IO_RETRY;		} else			rc = RAW3270_IO_BUSY;	} else if (view)		rc = view->fn->intv(view, rq, irb);	else		rc = RAW3270_IO_DONE;	switch (rc) {	case RAW3270_IO_DONE:		break;	case RAW3270_IO_BUSY:		/* 		 * Intervention required by the operator. We have to wait		 * for unsolicited device end.		 */		return;	case RAW3270_IO_RETRY:		if (!rq)			break;		rq->rc = ccw_device_start(rp->cdev, &rq->ccw,					  (unsigned long) rq, 0, 0);		if (rq->rc == 0)			return;	/* Sucessfully restarted. */		break;	case RAW3270_IO_STOP:		if (!rq)			break;		raw3270_halt_io_nolock(rp, rq);		rq->rc = -EIO;		break;	default:		BUG();	}	if (rq) {		BUG_ON(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,					  (unsigned long) 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);	}}/* * Size sensing. */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;	} __attribute__ ((packed)) uab;	struct {	/* Alternate Usable Area Self-Defining Parameter */		char  l;	/* Length of this Self-Defining Parm */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -