/*
* hvc_iucv.c - z/VM IUCV hypervisor console (HVC) device driver
*
* This HVC device driver provides terminal access using
* z/VM IUCV communication paths.
*
* Copyright IBM Corp. 2008, 2009
*
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
#define KMSG_COMPONENT "hvc_iucv"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
#include <linux/types.h>
#include <linux/slab.h>
#include <asm/ebcdic.h>
#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/mempool.h>
#include <linux/moduleparam.h>
#include <linux/tty.h>
#include <linux/wait.h>
#include <net/iucv/iucv.h>
#include "hvc_console.h"
/* General device driver settings */
#define HVC_IUCV_MAGIC 0xc9e4c3e5
#define MAX_HVC_IUCV_LINES HVC_ALLOC_TTY_ADAPTERS
#define MEMPOOL_MIN_NR (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4)
/* IUCV TTY message */
#define MSG_VERSION 0x02 /* Message version */
#define MSG_TYPE_ERROR 0x01 /* Error message */
#define MSG_TYPE_TERMENV 0x02 /* Terminal environment variable */
#define MSG_TYPE_TERMIOS 0x04 /* Terminal IO struct update */
#define MSG_TYPE_WINSIZE 0x08 /* Terminal window size update */
#define MSG_TYPE_DATA 0x10 /* Terminal data */
struct iucv_tty_msg {
u8 version; /* Message version */
u8 type; /* Message type */
#define MSG_MAX_DATALEN ((u16)(~0))
u16 datalen; /* Payload length */
u8 data[]; /* Payload buffer */
} __attribute__((packed));
#define MSG_SIZE(s) ((s) + offsetof(struct iucv_tty_msg, data))
enum iucv_state_t {
IUCV_DISCONN = 0,
IUCV_CONNECTED = 1,
IUCV_SEVERED = 2,
};
enum tty_state_t {
TTY_CLOSED = 0,
TTY_OPENED = 1,
};
struct hvc_iucv_private {
struct hvc_struct *hvc; /* HVC struct reference */
u8 srv_name[8]; /* IUCV service name (ebcdic) */
unsigned char is_console; /* Linux console usage flag */
enum iucv_state_t iucv_state; /* IUCV connection status */
enum tty_state_t tty_state; /* TTY status */
struct iucv_path *path; /* IUCV path pointer */
spinlock_t lock; /* hvc_iucv_private lock */
#define SNDBUF_SIZE (PAGE_SIZE) /* must be < MSG_MAX_DATALEN */
void *sndbuf; /* send buffer */
size_t sndbuf_len; /* length of send buffer */
#define QUEUE_SNDBUF_DELAY (HZ / 25)
struct delayed_work sndbuf_work; /* work: send iucv msg(s) */
wait_queue_head_t sndbuf_waitq; /* wait for send completion */
struct list_head tty_outqueue; /* outgoing IUCV messages */
struct list_head tty_inqueue; /* incoming IUCV messages */
struct device *dev; /* device structure */
};
struct iucv_tty_buffer {
struct list_head list; /* list pointer */
struct iucv_message msg; /* store an IUCV message */
size_t offset; /* data buffer offset */
struct iucv_tty_msg *mbuf; /* buffer to store input/output data */
};
/* IUCV callback handler */
stati