Commit b42e64d4 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: 3270 console driver

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

3270 device driver change:
 - Don't allow activation of views while the initial size sensing is still
   in progress. Replace RAW3270_FLAGS_SHUTDOWN with RAW3270_FLAGS_READY.
 - Make 3270 views loadable as modules.
parent c6b04cd0
...@@ -178,6 +178,8 @@ CONFIG_UNIX98_PTY_COUNT=2048 ...@@ -178,6 +178,8 @@ CONFIG_UNIX98_PTY_COUNT=2048
# S/390 character device drivers # S/390 character device drivers
# #
CONFIG_TN3270=y CONFIG_TN3270=y
CONFIG_TN3270_TTY=y
CONFIG_TN3270_FS=m
CONFIG_TN3270_CONSOLE=y CONFIG_TN3270_CONSOLE=y
CONFIG_TN3215=y CONFIG_TN3215=y
CONFIG_TN3215_CONSOLE=y CONFIG_TN3215_CONSOLE=y
......
...@@ -54,17 +54,28 @@ config UNIX98_PTY_COUNT ...@@ -54,17 +54,28 @@ config UNIX98_PTY_COUNT
comment "S/390 character device drivers" comment "S/390 character device drivers"
config TN3270 config TN3270
tristate "Support for locally attached 3270 tubes" tristate "Support for locally attached 3270 terminals"
help help
Include support for IBM 3270 line-mode terminals. Include support for IBM 3270 terminals.
config TN3270_TTY
tristate "Support for tty input/output on 3270 terminals"
depends on TN3270
help
Include support for using an IBM 3270 terminal as a Linux tty.
config TN3270_FS
tristate "Support for fullscreen applications on 3270 terminals"
depends on TN3270
help
Include support for fullscreen applications on an IBM 3270 terminal.
config TN3270_CONSOLE config TN3270_CONSOLE
bool "Support for console on 3270 line mode terminal" bool "Support for console on 3270 terminal"
depends on TN3270=y depends on TN3270=y && TN3270_TTY=y
help help
Include support for using an IBM 3270 line-mode terminal as a Linux Include support for using an IBM 3270 terminal as a Linux system
system console. Available only if 3270 support is compiled in console. Available only if 3270 support is compiled in statically.
statically.
config TN3215 config TN3215
bool "Support for 3215 line mode terminal" bool "Support for 3215 line mode terminal"
......
...@@ -4,9 +4,10 @@ ...@@ -4,9 +4,10 @@
obj-y += ctrlchar.o keyboard.o defkeymap.o obj-y += ctrlchar.o keyboard.o defkeymap.o
tub3270-objs := raw3270.o tty3270.o fs3270.o obj-$(CONFIG_TN3270) += raw3270.o
obj-$(CONFIG_TN3270) += tub3270.o
obj-$(CONFIG_TN3270_CONSOLE) += con3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
obj-$(CONFIG_TN3270_TTY) += tty3270.o
obj-$(CONFIG_TN3270_FS) += fs3270.o
obj-$(CONFIG_TN3215) += con3215.o obj-$(CONFIG_TN3215) += con3215.o
......
...@@ -47,11 +47,11 @@ struct raw3270 { ...@@ -47,11 +47,11 @@ struct raw3270 {
#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_ATTN 2 /* Device sent an ATTN interrupt */
#define RAW3270_FLAGS_SHUTDOWN 4 /* Device is in offline processing */ #define RAW3270_FLAGS_READY 4 /* Device is useable by views */
#define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */ #define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */
/* Lock to protect global data of raw3270 (devices, views, etc). */ /* Semaphore to protect global data of raw3270 (devices, views, etc). */
static spinlock_t raw3270_lock = SPIN_LOCK_UNLOCKED; static DECLARE_MUTEX(raw3270_sem);
/* List of 3270 devices. */ /* List of 3270 devices. */
static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices); static struct list_head raw3270_devices = LIST_HEAD_INIT(raw3270_devices);
...@@ -308,7 +308,7 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq) ...@@ -308,7 +308,7 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
rp = view->dev; rp = view->dev;
if (!rp || rp->view != view) if (!rp || rp->view != view)
rc = -EACCES; rc = -EACCES;
else if (test_bit(RAW3270_FLAGS_SHUTDOWN, &rp->flags)) else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
rc = -ENODEV; rc = -ENODEV;
else else
rc = __raw3270_start(rp, view, rq); rc = __raw3270_start(rp, view, rq);
...@@ -603,7 +603,6 @@ __raw3270_size_device(struct raw3270 *rp) ...@@ -603,7 +603,6 @@ __raw3270_size_device(struct raw3270 *rp)
{ {
static const unsigned char wbuf[] = static const unsigned char wbuf[] =
{ 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 }; { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
unsigned long flags;
struct raw3270_ua *uap; struct raw3270_ua *uap;
unsigned short count; unsigned short count;
int rc; int rc;
...@@ -638,6 +637,8 @@ __raw3270_size_device(struct raw3270 *rp) ...@@ -638,6 +637,8 @@ __raw3270_size_device(struct raw3270 *rp)
/* Wait for attention interrupt. */ /* Wait for attention interrupt. */
#ifdef CONFIG_TN3270_CONSOLE #ifdef CONFIG_TN3270_CONSOLE
if (raw3270_registered == 0) { if (raw3270_registered == 0) {
unsigned long flags;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
while (!test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags)) while (!test_and_clear_bit(RAW3270_FLAGS_ATTN, &rp->flags))
wait_cons_dev(); wait_cons_dev();
...@@ -764,7 +765,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc) ...@@ -764,7 +765,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
* Add device to list and find the smallest unused minor * Add device to list and find the smallest unused minor
* number for it. * number for it.
*/ */
spin_lock(&raw3270_lock); down(&raw3270_sem);
/* Keep the list sorted. */ /* Keep the list sorted. */
minor = 0; minor = 0;
rp->minor = -1; rp->minor = -1;
...@@ -781,7 +782,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc) ...@@ -781,7 +782,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
rp->minor = minor; rp->minor = minor;
list_add_tail(&rp->list, &raw3270_devices); list_add_tail(&rp->list, &raw3270_devices);
} }
spin_unlock(&raw3270_lock); up(&raw3270_sem);
/* No free minor number? Then give up. */ /* No free minor number? Then give up. */
if (rp->minor == -1) if (rp->minor == -1)
return -EUSERS; return -EUSERS;
...@@ -811,6 +812,7 @@ raw3270_setup_console(struct ccw_device *cdev) ...@@ -811,6 +812,7 @@ raw3270_setup_console(struct ccw_device *cdev)
raw3270_reset_device(rp); raw3270_reset_device(rp);
raw3270_size_device(rp); raw3270_size_device(rp);
raw3270_reset_device(rp); raw3270_reset_device(rp);
set_bit(RAW3270_FLAGS_READY, &rp->flags);
return rp; return rp;
} }
...@@ -872,7 +874,7 @@ raw3270_activate_view(struct raw3270_view *view) ...@@ -872,7 +874,7 @@ 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_SHUTDOWN, &rp->flags)) else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
rc = -ENODEV; rc = -ENODEV;
else { else {
oldview = 0; oldview = 0;
...@@ -921,7 +923,7 @@ raw3270_deactivate_view(struct raw3270_view *view) ...@@ -921,7 +923,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_SHUTDOWN, &rp->flags)) { if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
list_for_each_entry(view, &rp->view_list, list) list_for_each_entry(view, &rp->view_list, list)
if (view->fn->activate(view) == 0) { if (view->fn->activate(view) == 0) {
rp->view = view; rp->view = view;
...@@ -942,13 +944,13 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor) ...@@ -942,13 +944,13 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
struct raw3270 *rp; struct raw3270 *rp;
int rc; int rc;
spin_lock(&raw3270_lock); down(&raw3270_sem);
rc = -ENODEV; rc = -ENODEV;
list_for_each_entry(rp, &raw3270_devices, list) { list_for_each_entry(rp, &raw3270_devices, list) {
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_SHUTDOWN, &rp->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;
...@@ -963,7 +965,7 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor) ...@@ -963,7 +965,7 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
break; break;
} }
spin_unlock(&raw3270_lock); up(&raw3270_sem);
return rc; return rc;
} }
...@@ -977,25 +979,26 @@ raw3270_find_view(struct raw3270_fn *fn, int minor) ...@@ -977,25 +979,26 @@ raw3270_find_view(struct raw3270_fn *fn, int minor)
struct raw3270_view *view, *tmp; struct raw3270_view *view, *tmp;
unsigned long flags; unsigned long flags;
spin_lock(&raw3270_lock); down(&raw3270_sem);
view = ERR_PTR(-ENODEV); view = ERR_PTR(-ENODEV);
list_for_each_entry(rp, &raw3270_devices, list) { list_for_each_entry(rp, &raw3270_devices, list) {
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_SHUTDOWN, &rp->flags)) { if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
view = ERR_PTR(-ENOENT);
list_for_each_entry(tmp, &rp->view_list, list) { list_for_each_entry(tmp, &rp->view_list, list) {
if (tmp->fn == fn) { if (tmp->fn == fn) {
raw3270_get_view(tmp); raw3270_get_view(tmp);
view = tmp; view = tmp;
break;
} }
} }
} else }
view = ERR_PTR(-ENOENT);
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
break; break;
} }
spin_unlock(&raw3270_lock); up(&raw3270_sem);
return view; return view;
} }
...@@ -1007,6 +1010,7 @@ raw3270_del_view(struct raw3270_view *view) ...@@ -1007,6 +1010,7 @@ raw3270_del_view(struct raw3270_view *view)
{ {
unsigned long flags; unsigned long flags;
struct raw3270 *rp; struct raw3270 *rp;
struct raw3270_view *nv;
rp = view->dev; rp = view->dev;
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
...@@ -1015,17 +1019,18 @@ raw3270_del_view(struct raw3270_view *view) ...@@ -1015,17 +1019,18 @@ raw3270_del_view(struct raw3270_view *view)
rp->view = 0; rp->view = 0;
} }
list_del_init(&view->list); list_del_init(&view->list);
if (!rp->view && !test_bit(RAW3270_FLAGS_SHUTDOWN, &rp->flags)) { if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
/* Try to activate another view. */ /* Try to activate another view. */
list_for_each_entry(view, &rp->view_list, list) list_for_each_entry(nv, &rp->view_list, list) {
if (view->fn->activate(view) == 0) { if (nv->fn->activate(view) == 0) {
rp->view = view; rp->view = nv;
break; break;
} }
}
} }
spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
/* Wait for reference counter to drop to zero. */ /* Wait for reference counter to drop to zero. */
atomic_dec(&view->ref_count); atomic_sub(2, &view->ref_count);
wait_event(raw3270_wait_queue, atomic_read(&view->ref_count) == 0); wait_event(raw3270_wait_queue, atomic_read(&view->ref_count) == 0);
if (view->fn->free) if (view->fn->free)
view->fn->free(view); view->fn->free(view);
...@@ -1040,9 +1045,9 @@ raw3270_delete_device(struct raw3270 *rp) ...@@ -1040,9 +1045,9 @@ raw3270_delete_device(struct raw3270 *rp)
struct ccw_device *cdev; struct ccw_device *cdev;
/* Remove from device chain. */ /* Remove from device chain. */
spin_lock(&raw3270_lock); down(&raw3270_sem);
list_del_init(&rp->list); list_del_init(&rp->list);
spin_unlock(&raw3270_lock); up(&raw3270_sem);
/* Disconnect from ccw_device. */ /* Disconnect from ccw_device. */
cdev = rp->cdev; cdev = rp->cdev;
...@@ -1109,8 +1114,48 @@ raw3270_create_attributes(struct raw3270 *rp) ...@@ -1109,8 +1114,48 @@ raw3270_create_attributes(struct raw3270 *rp)
sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group); sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
} }
/* Hackish. A notifier chain would be cleaner. */ /*
extern void tty3270_notifier(int index, int active); * Notifier for device addition/removal
*/
struct raw3270_notifier {
struct list_head list;
void (*notifier)(int, int);
};
static struct list_head raw3270_notifier = LIST_HEAD_INIT(raw3270_notifier);
int raw3270_register_notifier(void (*notifier)(int, int))
{
struct raw3270_notifier *np;
struct raw3270 *rp;
np = kmalloc(sizeof(struct raw3270_notifier), GFP_KERNEL);
if (!np)
return -ENOMEM;
np->notifier = notifier;
down(&raw3270_sem);
list_add_tail(&np->list, &raw3270_notifier);
list_for_each_entry(rp, &raw3270_devices, list) {
get_device(&rp->cdev->dev);
notifier(rp->minor, 1);
}
up(&raw3270_sem);
return 0;
}
void raw3270_unregister_notifier(void (*notifier)(int, int))
{
struct raw3270_notifier *np;
down(&raw3270_sem);
list_for_each_entry(np, &raw3270_notifier, list)
if (np->notifier == notifier) {
list_del(&np->list);
kfree(np);
break;
}
up(&raw3270_sem);
}
/* /*
* Set 3270 device online. * Set 3270 device online.
...@@ -1119,6 +1164,7 @@ static int ...@@ -1119,6 +1164,7 @@ static int
raw3270_set_online (struct ccw_device *cdev) raw3270_set_online (struct ccw_device *cdev)
{ {
struct raw3270 *rp; struct raw3270 *rp;
struct raw3270_notifier *np;
rp = raw3270_create_device(cdev); rp = raw3270_create_device(cdev);
if (IS_ERR(rp)) if (IS_ERR(rp))
...@@ -1127,7 +1173,11 @@ raw3270_set_online (struct ccw_device *cdev) ...@@ -1127,7 +1173,11 @@ raw3270_set_online (struct ccw_device *cdev)
raw3270_size_device(rp); raw3270_size_device(rp);
raw3270_reset_device(rp); raw3270_reset_device(rp);
raw3270_create_attributes(rp); raw3270_create_attributes(rp);
tty3270_notifier(rp->minor, 1); set_bit(RAW3270_FLAGS_READY, &rp->flags);
down(&raw3270_sem);
list_for_each_entry(np, &raw3270_notifier, list)
np->notifier(rp->minor, 1);
up(&raw3270_sem);
return 0; return 0;
} }
...@@ -1140,9 +1190,10 @@ raw3270_remove (struct ccw_device *cdev) ...@@ -1140,9 +1190,10 @@ raw3270_remove (struct ccw_device *cdev)
unsigned long flags; unsigned long flags;
struct raw3270 *rp; struct raw3270 *rp;
struct raw3270_view *v; struct raw3270_view *v;
struct raw3270_notifier *np;
rp = cdev->dev.driver_data; rp = cdev->dev.driver_data;
set_bit(RAW3270_FLAGS_SHUTDOWN, &rp->flags); 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);
...@@ -1162,7 +1213,10 @@ raw3270_remove (struct ccw_device *cdev) ...@@ -1162,7 +1213,10 @@ raw3270_remove (struct ccw_device *cdev)
} }
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
tty3270_notifier(rp->minor, 0); down(&raw3270_sem);
list_for_each_entry(np, &raw3270_notifier, list)
np->notifier(rp->minor, 0);
up(&raw3270_sem);
/* Reset 3270 device. */ /* Reset 3270 device. */
raw3270_reset_device(rp); raw3270_reset_device(rp);
...@@ -1210,7 +1264,7 @@ static struct ccw_driver raw3270_ccw_driver = { ...@@ -1210,7 +1264,7 @@ static struct ccw_driver raw3270_ccw_driver = {
.set_offline = &raw3270_set_offline, .set_offline = &raw3270_set_offline,
}; };
int static int
raw3270_init(void) raw3270_init(void)
{ {
struct raw3270 *rp; struct raw3270 *rp;
...@@ -1222,18 +1276,17 @@ raw3270_init(void) ...@@ -1222,18 +1276,17 @@ raw3270_init(void)
rc = ccw_driver_register(&raw3270_ccw_driver); rc = ccw_driver_register(&raw3270_ccw_driver);
if (rc == 0) { if (rc == 0) {
/* Create attributes for early (= console) device. */ /* Create attributes for early (= console) device. */
spin_lock(&raw3270_lock); down(&raw3270_sem);
list_for_each_entry(rp, &raw3270_devices, list) { list_for_each_entry(rp, &raw3270_devices, list) {
get_device(&rp->cdev->dev); get_device(&rp->cdev->dev);
raw3270_create_attributes(rp); raw3270_create_attributes(rp);
tty3270_notifier(rp->minor, 1);
} }
spin_unlock(&raw3270_lock); up(&raw3270_sem);
} }
return rc; return rc;
} }
void static void
raw3270_exit(void) raw3270_exit(void)
{ {
ccw_driver_unregister(&raw3270_ccw_driver); ccw_driver_unregister(&raw3270_ccw_driver);
...@@ -1241,8 +1294,9 @@ raw3270_exit(void) ...@@ -1241,8 +1294,9 @@ raw3270_exit(void)
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
EXPORT_SYMBOL(raw3270_init); module_init(raw3270_init);
EXPORT_SYMBOL(raw3270_exit); module_exit(raw3270_exit);
EXPORT_SYMBOL(raw3270_request_alloc); EXPORT_SYMBOL(raw3270_request_alloc);
EXPORT_SYMBOL(raw3270_request_free); EXPORT_SYMBOL(raw3270_request_free);
EXPORT_SYMBOL(raw3270_request_reset); EXPORT_SYMBOL(raw3270_request_reset);
...@@ -1258,3 +1312,6 @@ EXPORT_SYMBOL(raw3270_activate_view); ...@@ -1258,3 +1312,6 @@ EXPORT_SYMBOL(raw3270_activate_view);
EXPORT_SYMBOL(raw3270_deactivate_view); EXPORT_SYMBOL(raw3270_deactivate_view);
EXPORT_SYMBOL(raw3270_start); EXPORT_SYMBOL(raw3270_start);
EXPORT_SYMBOL(raw3270_start_irq); EXPORT_SYMBOL(raw3270_start_irq);
EXPORT_SYMBOL(raw3270_register_notifier);
EXPORT_SYMBOL(raw3270_unregister_notifier);
EXPORT_SYMBOL(raw3270_wait_queue);
...@@ -78,9 +78,6 @@ ...@@ -78,9 +78,6 @@
#define RAW3270_MAXDEVS 256 #define RAW3270_MAXDEVS 256
int raw3270_init(void);
void raw3270_exit(void);
/* For TUBGETMOD and TUBSETMOD. Should include. */ /* For TUBGETMOD and TUBSETMOD. Should include. */
struct raw3270_iocb { struct raw3270_iocb {
short model; short model;
...@@ -190,6 +187,10 @@ raw3270_put_view(struct raw3270_view *view) ...@@ -190,6 +187,10 @@ raw3270_put_view(struct raw3270_view *view)
struct raw3270 *raw3270_setup_console(struct ccw_device *cdev); struct raw3270 *raw3270_setup_console(struct ccw_device *cdev);
void raw3270_wait_cons_dev(struct raw3270 *); void raw3270_wait_cons_dev(struct raw3270 *);
/* Notifier for device addition/removal */
int raw3270_register_notifier(void (*notifier)(int, int));
void raw3270_unregister_notifier(void (*notifier)(int, int));
/* /*
* Little memory allocator for string objects. * Little memory allocator for string objects.
*/ */
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#define TTY3270_STRING_PAGES 5 #define TTY3270_STRING_PAGES 5
struct tty_driver *tty3270_driver; struct tty_driver *tty3270_driver;
static int tty3270_max_index;
struct raw3270_fn tty3270_fn; struct raw3270_fn tty3270_fn;
...@@ -836,6 +837,22 @@ tty3270_free(struct raw3270_view *view) ...@@ -836,6 +837,22 @@ tty3270_free(struct raw3270_view *view)
tty3270_free_view((struct tty3270 *) view); tty3270_free_view((struct tty3270 *) view);
} }
/*
* Delayed freeing of tty3270 views.
*/
static void
tty3270_del_views(void)
{
struct tty3270 *tp;
int i;
for (i = 0; i < tty3270_max_index; i++) {
tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, i);
if (!IS_ERR(tp))
raw3270_del_view(&tp->view);
}
}
struct raw3270_fn tty3270_fn = { struct raw3270_fn tty3270_fn = {
.activate = tty3270_activate, .activate = tty3270_activate,
.deactivate = tty3270_deactivate, .deactivate = tty3270_deactivate,
...@@ -867,6 +884,12 @@ tty3270_open(struct tty_struct *tty, struct file * filp) ...@@ -867,6 +884,12 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
tp->inattr = TF_INPUT; tp->inattr = TF_INPUT;
return 0; return 0;
} }
if (tty3270_max_index < tty->index + 1)
tty3270_max_index = tty->index + 1;
/* Quick exit if there is no device for tty->index. */
if (PTR_ERR(tp) == -ENODEV)
return -ENODEV;
/* Allocate tty3270 structure on first open. */ /* Allocate tty3270 structure on first open. */
tp = tty3270_alloc_view(); tp = tty3270_alloc_view();
...@@ -1778,9 +1801,6 @@ tty3270_init(void) ...@@ -1778,9 +1801,6 @@ tty3270_init(void)
struct tty_driver *driver; struct tty_driver *driver;
int ret; int ret;
ret = raw3270_init();
if (ret)
return ret;
driver = alloc_tty_driver(256); driver = alloc_tty_driver(256);
if (!driver) if (!driver)
return -ENOMEM; return -ENOMEM;
...@@ -1807,6 +1827,14 @@ tty3270_init(void) ...@@ -1807,6 +1827,14 @@ tty3270_init(void)
return ret; return ret;
} }
tty3270_driver = driver; tty3270_driver = driver;
ret = raw3270_register_notifier(tty3270_notifier);
if (ret) {
printk(KERN_ERR "tty3270 notifier registration failed "
"with %d\n", ret);
put_tty_driver(driver);
return ret;
}
return 0; return 0;
} }
...@@ -1815,10 +1843,11 @@ tty3270_exit(void) ...@@ -1815,10 +1843,11 @@ tty3270_exit(void)
{ {
struct tty_driver *driver; struct tty_driver *driver;
raw3270_unregister_notifier(tty3270_notifier);
driver = tty3270_driver; driver = tty3270_driver;
tty3270_driver = 0; tty3270_driver = 0;
tty_unregister_driver(driver); tty_unregister_driver(driver);
raw3270_exit(); tty3270_del_views();
} }
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
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