Commit a863aaa3 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: console changes.

s390 console fixes for 3215 and sclp.
parent fefe4ef5
...@@ -151,7 +151,7 @@ static int tty_fasync(int fd, struct file * filp, int on); ...@@ -151,7 +151,7 @@ static int tty_fasync(int fd, struct file * filp, int on);
extern int vme_scc_init (void); extern int vme_scc_init (void);
extern int serial167_init(void); extern int serial167_init(void);
extern int rs_8xx_init(void); extern int rs_8xx_init(void);
extern void hwc_tty_init(void); extern void sclp_tty_init(void);
extern void tty3215_init(void); extern void tty3215_init(void);
extern void tub3270_init(void); extern void tub3270_init(void);
extern void rs_360_init(void); extern void rs_360_init(void);
......
...@@ -872,7 +872,7 @@ con3215_consetup(struct console *co, char *options) ...@@ -872,7 +872,7 @@ con3215_consetup(struct console *co, char *options)
* The console structure for the 3215 console * The console structure for the 3215 console
*/ */
static struct console con3215 = { static struct console con3215 = {
.name = "tty3215", .name = "ttyS",
.write = con3215_write, .write = con3215_write,
.device = con3215_device, .device = con3215_device,
.unblank = con3215_unblank, .unblank = con3215_unblank,
...@@ -884,7 +884,7 @@ static struct console con3215 = { ...@@ -884,7 +884,7 @@ static struct console con3215 = {
* 3215 console initialization code called from console_init(). * 3215 console initialization code called from console_init().
* NOTE: This is called before kmalloc is available. * NOTE: This is called before kmalloc is available.
*/ */
static void __init static int __init
con3215_init(void) con3215_init(void)
{ {
struct ccw_device *cdev; struct ccw_device *cdev;
...@@ -894,7 +894,7 @@ con3215_init(void) ...@@ -894,7 +894,7 @@ con3215_init(void)
/* Check if 3215 is to be the console */ /* Check if 3215 is to be the console */
if (!CONSOLE_IS_3215) if (!CONSOLE_IS_3215)
return; return -ENODEV;
/* Set the console mode for VM */ /* Set the console mode for VM */
if (MACHINE_IS_VM) { if (MACHINE_IS_VM) {
...@@ -913,7 +913,7 @@ con3215_init(void) ...@@ -913,7 +913,7 @@ con3215_init(void)
cdev = ccw_device_probe_console(); cdev = ccw_device_probe_console();
if (!cdev) if (!cdev)
return; return -ENODEV;
raw3215[0] = raw = (struct raw3215_info *) raw3215[0] = raw = (struct raw3215_info *)
alloc_bootmem_low(sizeof(struct raw3215_info)); alloc_bootmem_low(sizeof(struct raw3215_info));
...@@ -938,10 +938,12 @@ con3215_init(void) ...@@ -938,10 +938,12 @@ con3215_init(void)
free_bootmem((unsigned long) raw, sizeof(struct raw3215_info)); free_bootmem((unsigned long) raw, sizeof(struct raw3215_info));
raw3215[0] = NULL; raw3215[0] = NULL;
printk("Couldn't find a 3215 console device\n"); printk("Couldn't find a 3215 console device\n");
return; return -ENODEV;
} }
register_console(&con3215); register_console(&con3215);
return 0;
} }
console_initcall(con3215_init);
#endif #endif
/* /*
...@@ -1122,7 +1124,6 @@ tty3215_unthrottle(struct tty_struct * tty) ...@@ -1122,7 +1124,6 @@ tty3215_unthrottle(struct tty_struct * tty)
spin_unlock_irqrestore(raw->lock, flags); spin_unlock_irqrestore(raw->lock, flags);
} }
} }
console_initcall(con3215_init);
/* /*
* Disable writing to a 3215 tty * Disable writing to a 3215 tty
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
...@@ -25,14 +24,6 @@ ...@@ -25,14 +24,6 @@
#define SCLP_CORE_PRINT_HEADER "sclp low level driver: " #define SCLP_CORE_PRINT_HEADER "sclp low level driver: "
/*
* decides whether we make use of the macro MACHINE_IS_VM to
* configure the driver for VM at run time (a little bit
* different behaviour); otherwise we use the default
* settings in sclp_data.init_ioctls
*/
#define USE_VM_DETECTION
/* Structure for register_early_external_interrupt. */ /* Structure for register_early_external_interrupt. */
static ext_int_info_t ext_int_info_hwc; static ext_int_info_t ext_int_info_hwc;
...@@ -111,30 +102,32 @@ __service_call(sclp_cmdw_t command, void *sccb) ...@@ -111,30 +102,32 @@ __service_call(sclp_cmdw_t command, void *sccb)
} }
static int static int
__sclp_start_request(void) sclp_start_request(void)
{ {
struct sclp_req *req; struct sclp_req *req;
int rc; int rc;
unsigned long flags;
/* quick exit if sclp is already in use */ /* quick exit if sclp is already in use */
if (test_bit(SCLP_RUNNING, &sclp_status)) if (test_bit(SCLP_RUNNING, &sclp_status))
return -EBUSY; return -EBUSY;
/* quick exit if queue is empty */ spin_lock_irqsave(&sclp_lock, flags);
if (list_empty(&sclp_req_queue)) /* Get first request on queue if available */
return -EINVAL; req = NULL;
/* try to start the first request on the request queue. */ if (!list_empty(&sclp_req_queue))
req = list_entry(sclp_req_queue.next, struct sclp_req, list); req = list_entry(sclp_req_queue.next, struct sclp_req, list);
if (req) {
rc = __service_call(req->command, req->sccb); rc = __service_call(req->command, req->sccb);
switch (rc) { if (rc) {
case 0:
req->status = SCLP_REQ_RUNNING;
break;
case -EIO:
req->status = SCLP_REQ_FAILED; req->status = SCLP_REQ_FAILED;
if (req->callback != NULL) list_del(&req->list);
} else
req->status = SCLP_REQ_RUNNING;
} else
rc = -EINVAL;
spin_unlock_irqrestore(&sclp_lock, flags);
if (rc == -EIO && req->callback != NULL)
req->callback(req, req->callback_data); req->callback(req, req->callback_data);
break;
}
return rc; return rc;
} }
...@@ -156,8 +149,12 @@ sclp_process_evbufs(struct sccb_header *sccb) ...@@ -156,8 +149,12 @@ sclp_process_evbufs(struct sccb_header *sccb)
list_for_each(l, &sclp_reg_list) { list_for_each(l, &sclp_reg_list) {
t = list_entry(l, struct sclp_register, list); t = list_entry(l, struct sclp_register, list);
if (t->receive_mask & (1 << (32 - evbuf->type))) { if (t->receive_mask & (1 << (32 - evbuf->type))) {
if (t->receiver_fn != NULL) if (t->receiver_fn != NULL) {
spin_unlock_irqrestore(&sclp_lock,
flags);
t->receiver_fn(evbuf); t->receiver_fn(evbuf);
spin_lock_irqsave(&sclp_lock, flags);
}
break; break;
} }
else else
...@@ -230,7 +227,7 @@ sclp_unconditional_read_cb(struct sclp_req *read_req, void *data) ...@@ -230,7 +227,7 @@ sclp_unconditional_read_cb(struct sclp_req *read_req, void *data)
} }
/* /*
* Function to issue Read Event Data/Unconditional Read * Function to queue Read Event Data/Unconditional Read
*/ */
static void static void
__sclp_unconditional_read(void) __sclp_unconditional_read(void)
...@@ -278,19 +275,20 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code) ...@@ -278,19 +275,20 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
struct list_head *l; struct list_head *l;
struct sclp_req *req, *tmp; struct sclp_req *req, *tmp;
/*
* Only process interrupt if sclp is initialized.
* This avoids strange effects for a pending request
* from before the last re-ipl.
*/
if (!test_bit(SCLP_INIT, &sclp_status))
return;
ext_int_param = S390_lowcore.ext_params; ext_int_param = S390_lowcore.ext_params;
finished_sccb = ext_int_param & EXT_INT_SCCB_MASK; finished_sccb = ext_int_param & EXT_INT_SCCB_MASK;
evbuf_pending = ext_int_param & (EXT_INT_EVBUF_PENDING | evbuf_pending = ext_int_param & (EXT_INT_EVBUF_PENDING |
EXT_INT_STATECHANGE_PENDING); EXT_INT_STATECHANGE_PENDING);
irq_enter(); irq_enter();
/*
* Only do request callbacks if sclp is initialized.
* This avoids strange effects for a pending request
* from before the last re-ipl.
*/
if (test_bit(SCLP_INIT, &sclp_status)) {
spin_lock(&sclp_lock);
req = NULL; req = NULL;
spin_lock(&sclp_lock);
if (finished_sccb != 0U) { if (finished_sccb != 0U) {
list_for_each(l, &sclp_req_queue) { list_for_each(l, &sclp_req_queue) {
tmp = list_entry(l, struct sclp_req, list); tmp = list_entry(l, struct sclp_req, list);
...@@ -301,22 +299,20 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code) ...@@ -301,22 +299,20 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
} }
} }
} }
/* Head queue a read sccb if an event buffer is pending */
if (evbuf_pending)
__sclp_unconditional_read();
spin_unlock(&sclp_lock); spin_unlock(&sclp_lock);
/* Perform callback */
if (req != NULL) { if (req != NULL) {
req->status = SCLP_REQ_DONE; req->status = SCLP_REQ_DONE;
if (req->callback != NULL) if (req->callback != NULL)
req->callback(req, req->callback_data); req->callback(req, req->callback_data);
} }
}
spin_lock(&sclp_lock);
/* Head queue a read sccb if an event buffer is pending */
if (evbuf_pending)
__sclp_unconditional_read();
/* Now clear the running bit */ /* Now clear the running bit */
clear_bit(SCLP_RUNNING, &sclp_status); clear_bit(SCLP_RUNNING, &sclp_status);
/* and start next request on the queue */ /* and start next request on the queue */
__sclp_start_request(); sclp_start_request();
spin_unlock(&sclp_lock);
irq_exit(); irq_exit();
} }
...@@ -368,15 +364,19 @@ sclp_add_request(struct sclp_req *req) ...@@ -368,15 +364,19 @@ sclp_add_request(struct sclp_req *req)
{ {
unsigned long flags; unsigned long flags;
if (!test_bit(SCLP_INIT, &sclp_status)) if (!test_bit(SCLP_INIT, &sclp_status)) {
req->status = SCLP_REQ_FAILED;
if (req->callback != NULL)
req->callback(req, req->callback_data);
return; return;
}
spin_lock_irqsave(&sclp_lock, flags); spin_lock_irqsave(&sclp_lock, flags);
/* queue the request */ /* queue the request */
req->status = SCLP_REQ_QUEUED; req->status = SCLP_REQ_QUEUED;
list_add_tail(&req->list, &sclp_req_queue); list_add_tail(&req->list, &sclp_req_queue);
/* try to start the first request on the queue */
__sclp_start_request();
spin_unlock_irqrestore(&sclp_lock, flags); spin_unlock_irqrestore(&sclp_lock, flags);
/* try to start the first request on the queue */
sclp_start_request();
} }
/* state change notification */ /* state change notification */
...@@ -566,10 +566,9 @@ sclp_init_mask(void) ...@@ -566,10 +566,9 @@ sclp_init_mask(void)
if (test_bit(SCLP_INIT, &sclp_status)) { if (test_bit(SCLP_INIT, &sclp_status)) {
/* add request to sclp queue */ /* add request to sclp queue */
list_add_tail(&req->list, &sclp_req_queue); list_add_tail(&req->list, &sclp_req_queue);
/* and start if SCLP is idle */
if (!test_bit(SCLP_RUNNING, &sclp_status))
__sclp_start_request();
spin_unlock_irqrestore(&sclp_lock, flags); spin_unlock_irqrestore(&sclp_lock, flags);
/* and start if SCLP is idle */
sclp_start_request();
/* now wait for completion */ /* now wait for completion */
while (req->status != SCLP_REQ_DONE && while (req->status != SCLP_REQ_DONE &&
req->status != SCLP_REQ_FAILED) req->status != SCLP_REQ_FAILED)
...@@ -730,7 +729,41 @@ sclp_unregister(struct sclp_register *reg) ...@@ -730,7 +729,41 @@ sclp_unregister(struct sclp_register *reg)
sclp_init_mask(); sclp_init_mask();
} }
#define SCLP_EVBUF_PROCESSED 0x80
/*
* Traverse array of event buffers contained in SCCB and remove all buffers
* with a set "processed" flag. Return the number of unprocessed buffers.
*/
int
sclp_remove_processed(struct sccb_header *sccb)
{
struct evbuf_header *evbuf;
int unprocessed;
u16 remaining;
evbuf = (struct evbuf_header *) (sccb + 1);
unprocessed = 0;
remaining = sccb->length - sizeof(struct sccb_header);
while (remaining > 0) {
remaining -= evbuf->length;
if (evbuf->flags & SCLP_EVBUF_PROCESSED) {
sccb->length -= evbuf->length;
memcpy((void *) evbuf,
(void *) ((addr_t) evbuf + evbuf->length),
remaining);
} else {
unprocessed++;
evbuf = (struct evbuf_header *)
((addr_t) evbuf + evbuf->length);
}
}
return unprocessed;
}
EXPORT_SYMBOL(sclp_add_request); EXPORT_SYMBOL(sclp_add_request);
EXPORT_SYMBOL(sclp_sync_wait); EXPORT_SYMBOL(sclp_sync_wait);
EXPORT_SYMBOL(sclp_register); EXPORT_SYMBOL(sclp_register);
EXPORT_SYMBOL(sclp_unregister); EXPORT_SYMBOL(sclp_unregister);
EXPORT_SYMBOL(sclp_error_message);
...@@ -126,6 +126,7 @@ void sclp_sync_wait(void); ...@@ -126,6 +126,7 @@ void sclp_sync_wait(void);
int sclp_register(struct sclp_register *reg); int sclp_register(struct sclp_register *reg);
void sclp_unregister(struct sclp_register *reg); void sclp_unregister(struct sclp_register *reg);
char *sclp_error_message(u16 response_code); char *sclp_error_message(u16 response_code);
int sclp_remove_processed(struct sccb_header *sccb);
/* useful inlines */ /* useful inlines */
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/version.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/console.h> #include <linux/console.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -24,7 +23,7 @@ ...@@ -24,7 +23,7 @@
#define sclp_console_major 4 /* TTYAUX_MAJOR */ #define sclp_console_major 4 /* TTYAUX_MAJOR */
#define sclp_console_minor 64 #define sclp_console_minor 64
#define sclp_console_name "console" #define sclp_console_name "ttyS"
/* Lock to guard over changes to global variables */ /* Lock to guard over changes to global variables */
static spinlock_t sclp_con_lock; static spinlock_t sclp_con_lock;
...@@ -193,28 +192,29 @@ static struct console sclp_console = ...@@ -193,28 +192,29 @@ static struct console sclp_console =
.write = sclp_console_write, .write = sclp_console_write,
.device = sclp_console_device, .device = sclp_console_device,
.unblank = sclp_console_unblank, .unblank = sclp_console_unblank,
.flags = CON_PRINTBUFFER .flags = CON_PRINTBUFFER,
.index = 0 /* ttyS0 */
}; };
/* /*
* called by console_init() in drivers/char/tty_io.c at boot-time. * called by console_init() in drivers/char/tty_io.c at boot-time.
*/ */
void __init static int __init
sclp_console_init(void) sclp_console_init(void)
{ {
void *page; void *page;
int i; int i;
if (!CONSOLE_IS_SCLP) if (!CONSOLE_IS_SCLP)
return; return 0;
if (sclp_rw_init() != 0) if (sclp_rw_init() != 0)
return; return 0;
/* Allocate pages for output buffering */ /* Allocate pages for output buffering */
INIT_LIST_HEAD(&sclp_con_pages); INIT_LIST_HEAD(&sclp_con_pages);
for (i = 0; i < MAX_CONSOLE_PAGES; i++) { for (i = 0; i < MAX_CONSOLE_PAGES; i++) {
page = alloc_bootmem_low_pages(PAGE_SIZE); page = alloc_bootmem_low_pages(PAGE_SIZE);
if (page == NULL) if (page == NULL)
return; return 0;
list_add_tail((struct list_head *) page, &sclp_con_pages); list_add_tail((struct list_head *) page, &sclp_con_pages);
} }
INIT_LIST_HEAD(&sclp_con_outqueue); INIT_LIST_HEAD(&sclp_con_outqueue);
...@@ -236,6 +236,7 @@ sclp_console_init(void) ...@@ -236,6 +236,7 @@ sclp_console_init(void)
/* enable printk-access to this driver */ /* enable printk-access to this driver */
register_console(&sclp_console); register_console(&sclp_console);
return 0;
} }
console_initcall(sclp_console_init); console_initcall(sclp_console_init);
...@@ -130,7 +130,7 @@ cpi_prepare_req(void) ...@@ -130,7 +130,7 @@ cpi_prepare_req(void)
req = (struct sclp_req *) kmalloc(sizeof(struct sclp_req), GFP_KERNEL); req = (struct sclp_req *) kmalloc(sizeof(struct sclp_req), GFP_KERNEL);
if (req == NULL) if (req == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL); sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA);
if (sccb == NULL) { if (sccb == NULL) {
kfree(req); kfree(req);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/version.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -374,39 +373,6 @@ sclp_rw_init(void) ...@@ -374,39 +373,6 @@ sclp_rw_init(void)
return rc; return rc;
} }
#define SCLP_EVBUF_PROCESSED 0x80
/*
* Traverse array of event buffers contained in SCCB and remove all buffers
* with a set "processed" flag. Return the number of unprocessed buffers.
*/
static int
sclp_remove_processed(struct sccb_header *sccb)
{
struct evbuf_header *evbuf;
int unprocessed;
u16 remaining;
evbuf = (struct evbuf_header *) (sccb + 1);
unprocessed = 0;
remaining = sccb->length - sizeof(struct sccb_header);
while (remaining > 0) {
remaining -= evbuf->length;
if (evbuf->flags & SCLP_EVBUF_PROCESSED) {
sccb->length -= evbuf->length;
memcpy((void *) evbuf,
(void *) ((addr_t) evbuf + evbuf->length),
remaining);
} else {
unprocessed++;
evbuf = (struct evbuf_header *)
((addr_t) evbuf + evbuf->length);
}
}
return unprocessed;
}
static void static void
sclp_buffer_retry(unsigned long data) sclp_buffer_retry(unsigned long data)
{ {
...@@ -480,10 +446,6 @@ sclp_writedata_callback(struct sclp_req *request, void *data) ...@@ -480,10 +446,6 @@ sclp_writedata_callback(struct sclp_req *request, void *data)
rc = -ENOMEM; rc = -ENOMEM;
else else
rc = -EINVAL; rc = -EINVAL;
printk(KERN_WARNING SCLP_RW_PRINT_HEADER
"sclp_writedata_callback: %s (response code=0x%x).\n",
sclp_error_message(sccb->header.response_code),
sccb->header.response_code);
break; break;
} }
if (buffer->callback != NULL) if (buffer->callback != NULL)
...@@ -505,8 +467,11 @@ sclp_emit_buffer(struct sclp_buffer *buffer, ...@@ -505,8 +467,11 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
sclp_finalize_mto(buffer); sclp_finalize_mto(buffer);
/* Are there messages in the output buffer ? */ /* Are there messages in the output buffer ? */
if (buffer->mto_number == 0) if (buffer->mto_number == 0) {
if (callback != NULL)
callback(buffer, 0);
return; return;
}
sccb = buffer->sccb; sccb = buffer->sccb;
if (sclp_rw_event.sclp_send_mask & EvTyp_Msg_Mask) if (sclp_rw_event.sclp_send_mask & EvTyp_Msg_Mask)
...@@ -516,6 +481,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer, ...@@ -516,6 +481,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
/* Use write priority message */ /* Use write priority message */
sccb->msg_buf.header.type = EvTyp_PMsgCmd; sccb->msg_buf.header.type = EvTyp_PMsgCmd;
else { else {
if (callback != NULL)
callback(buffer, -ENOSYS); callback(buffer, -ENOSYS);
return; return;
} }
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/version.h> #include <linux/module.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/tty_driver.h> #include <linux/tty_driver.h>
...@@ -81,9 +81,6 @@ static struct sclp_ioctls sclp_ioctls_init = ...@@ -81,9 +81,6 @@ static struct sclp_ioctls sclp_ioctls_init =
static int static int
sclp_tty_open(struct tty_struct *tty, struct file *filp) sclp_tty_open(struct tty_struct *tty, struct file *filp)
{ {
/* only 1 SCLP terminal supported */
if (minor(tty->device) != tty->driver.minor_start)
return -ENODEV;
sclp_tty = tty; sclp_tty = tty;
tty->driver_data = NULL; tty->driver_data = NULL;
tty->low_latency = 0; tty->low_latency = 0;
...@@ -94,9 +91,6 @@ sclp_tty_open(struct tty_struct *tty, struct file *filp) ...@@ -94,9 +91,6 @@ sclp_tty_open(struct tty_struct *tty, struct file *filp)
static void static void
sclp_tty_close(struct tty_struct *tty, struct file *filp) sclp_tty_close(struct tty_struct *tty, struct file *filp)
{ {
/* only 1 SCLP terminal supported */
if (minor(tty->device) != tty->driver.minor_start)
return;
if (tty->count > 1) if (tty->count > 1)
return; return;
sclp_tty = NULL; sclp_tty = NULL;
...@@ -294,8 +288,15 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc) ...@@ -294,8 +288,15 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
static inline void static inline void
__sclp_ttybuf_emit(struct sclp_buffer *buffer) __sclp_ttybuf_emit(struct sclp_buffer *buffer)
{ {
unsigned long flags;
int count;
spin_lock_irqsave(&sclp_tty_lock, flags);
list_add_tail(&buffer->list, &sclp_tty_outqueue); list_add_tail(&buffer->list, &sclp_tty_outqueue);
if (sclp_tty_buffer_count++ == 0) count = sclp_tty_buffer_count++;
spin_unlock_irqrestore(&sclp_tty_lock, flags);
if (count == 0)
sclp_emit_buffer(buffer, sclp_ttybuf_callback); sclp_emit_buffer(buffer, sclp_ttybuf_callback);
} }
...@@ -307,13 +308,16 @@ static void ...@@ -307,13 +308,16 @@ static void
sclp_tty_timeout(unsigned long data) sclp_tty_timeout(unsigned long data)
{ {
unsigned long flags; unsigned long flags;
struct sclp_buffer *buf;
spin_lock_irqsave(&sclp_tty_lock, flags); spin_lock_irqsave(&sclp_tty_lock, flags);
if (sclp_ttybuf != NULL) { buf = sclp_ttybuf;
__sclp_ttybuf_emit(sclp_ttybuf);
sclp_ttybuf = NULL; sclp_ttybuf = NULL;
}
spin_unlock_irqrestore(&sclp_tty_lock, flags); spin_unlock_irqrestore(&sclp_tty_lock, flags);
if (buf != NULL) {
__sclp_ttybuf_emit(buf);
}
} }
/* /*
...@@ -325,6 +329,7 @@ sclp_tty_write_string(const unsigned char *str, int count, int from_user) ...@@ -325,6 +329,7 @@ sclp_tty_write_string(const unsigned char *str, int count, int from_user)
unsigned long flags; unsigned long flags;
void *page; void *page;
int written; int written;
struct sclp_buffer *buf;
if (count <= 0) if (count <= 0)
return; return;
...@@ -353,8 +358,11 @@ sclp_tty_write_string(const unsigned char *str, int count, int from_user) ...@@ -353,8 +358,11 @@ sclp_tty_write_string(const unsigned char *str, int count, int from_user)
* output buffer. Emit the buffer, create a new buffer * output buffer. Emit the buffer, create a new buffer
* and then output the rest of the string. * and then output the rest of the string.
*/ */
__sclp_ttybuf_emit(sclp_ttybuf); buf = sclp_ttybuf;
sclp_ttybuf = NULL; sclp_ttybuf = NULL;
spin_unlock_irqrestore(&sclp_tty_lock, flags);
__sclp_ttybuf_emit(buf);
spin_lock_irqsave(&sclp_tty_lock, flags);
str += written; str += written;
count -= written; count -= written;
} while (count > 0); } while (count > 0);
...@@ -466,7 +474,8 @@ sclp_tty_flush_buffer(struct tty_struct *tty) ...@@ -466,7 +474,8 @@ sclp_tty_flush_buffer(struct tty_struct *tty)
/* /*
* push input to tty * push input to tty
*/ */
static void sclp_tty_input(unsigned char* buf, unsigned int count) static void
sclp_tty_input(unsigned char* buf, unsigned int count)
{ {
unsigned int cchar; unsigned int cchar;
...@@ -706,15 +715,21 @@ sclp_tty_init(void) ...@@ -706,15 +715,21 @@ sclp_tty_init(void)
{ {
void *page; void *page;
int i; int i;
int rc;
if (!CONSOLE_IS_SCLP) if (!CONSOLE_IS_SCLP)
return; return;
if (sclp_rw_init() != 0) rc = sclp_rw_init();
if (rc != 0) {
printk(KERN_ERR SCLP_TTY_PRINT_HEADER
"could not register tty - "
"sclp_rw_init returned %d\n", rc);
return; return;
}
/* Allocate pages for output buffering */ /* Allocate pages for output buffering */
INIT_LIST_HEAD(&sclp_tty_pages); INIT_LIST_HEAD(&sclp_tty_pages);
for (i = 0; i < MAX_KMEM_PAGES; i++) { for (i = 0; i < MAX_KMEM_PAGES; i++) {
page = (void *) get_zeroed_page(GFP_KERNEL); page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
if (page == NULL) if (page == NULL)
return; return;
list_add_tail((struct list_head *) page, &sclp_tty_pages); list_add_tail((struct list_head *) page, &sclp_tty_pages);
...@@ -744,7 +759,7 @@ sclp_tty_init(void) ...@@ -744,7 +759,7 @@ sclp_tty_init(void)
memset (&sclp_tty_driver, 0, sizeof(struct tty_driver)); memset (&sclp_tty_driver, 0, sizeof(struct tty_driver));
sclp_tty_driver.magic = TTY_DRIVER_MAGIC; sclp_tty_driver.magic = TTY_DRIVER_MAGIC;
sclp_tty_driver.owner = THIS_MODULE; sclp_tty_driver.owner = THIS_MODULE;
sclp_tty_driver.driver_name = "tty_sclp"; sclp_tty_driver.driver_name = "sclp_line";
sclp_tty_driver.name = "ttyS"; sclp_tty_driver.name = "ttyS";
sclp_tty_driver.name_base = 0; sclp_tty_driver.name_base = 0;
sclp_tty_driver.major = TTY_MAJOR; sclp_tty_driver.major = TTY_MAJOR;
...@@ -795,9 +810,9 @@ sclp_tty_init(void) ...@@ -795,9 +810,9 @@ sclp_tty_init(void)
sclp_tty_driver.read_proc = NULL; sclp_tty_driver.read_proc = NULL;
sclp_tty_driver.write_proc = NULL; sclp_tty_driver.write_proc = NULL;
if (tty_register_driver(&sclp_tty_driver)) rc = tty_register_driver(&sclp_tty_driver);
panic("Couldn't register sclp_tty driver\n"); if (rc != 0)
printk(KERN_ERR SCLP_TTY_PRINT_HEADER
"could not register tty - "
"sclp_drv_register returned %d\n", rc);
} }
console_initcall(sclp_tty_init);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment