diff options
Diffstat (limited to 'drivers/s390/char/raw3270.c')
-rw-r--r-- | drivers/s390/char/raw3270.c | 100 |
1 files changed, 88 insertions, 12 deletions
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 328d9cbc56a3..d66946443dfc 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
@@ -25,6 +25,12 @@ | |||
25 | 25 | ||
26 | #include "raw3270.h" | 26 | #include "raw3270.h" |
27 | 27 | ||
28 | #include <linux/major.h> | ||
29 | #include <linux/kdev_t.h> | ||
30 | #include <linux/device.h> | ||
31 | |||
32 | struct class *class3270; | ||
33 | |||
28 | /* The main 3270 data structure. */ | 34 | /* The main 3270 data structure. */ |
29 | struct raw3270 { | 35 | struct raw3270 { |
30 | struct list_head list; | 36 | struct list_head list; |
@@ -41,6 +47,8 @@ struct raw3270 { | |||
41 | struct timer_list timer; /* Device timer. */ | 47 | struct timer_list timer; /* Device timer. */ |
42 | 48 | ||
43 | unsigned char *ascebc; /* ascii -> ebcdic table */ | 49 | unsigned char *ascebc; /* ascii -> ebcdic table */ |
50 | struct class_device *clttydev; /* 3270-class tty device ptr */ | ||
51 | struct class_device *cltubdev; /* 3270-class tub device ptr */ | ||
44 | }; | 52 | }; |
45 | 53 | ||
46 | /* raw3270->flags */ | 54 | /* raw3270->flags */ |
@@ -317,6 +325,22 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq) | |||
317 | } | 325 | } |
318 | 326 | ||
319 | int | 327 | int |
328 | raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq) | ||
329 | { | ||
330 | struct raw3270 *rp; | ||
331 | int rc; | ||
332 | |||
333 | rp = view->dev; | ||
334 | if (!rp || rp->view != view) | ||
335 | rc = -EACCES; | ||
336 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) | ||
337 | rc = -ENODEV; | ||
338 | else | ||
339 | rc = __raw3270_start(rp, view, rq); | ||
340 | return rc; | ||
341 | } | ||
342 | |||
343 | int | ||
320 | raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq) | 344 | raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq) |
321 | { | 345 | { |
322 | struct raw3270 *rp; | 346 | struct raw3270 *rp; |
@@ -744,6 +768,22 @@ raw3270_reset_device(struct raw3270 *rp) | |||
744 | return rc; | 768 | return rc; |
745 | } | 769 | } |
746 | 770 | ||
771 | int | ||
772 | raw3270_reset(struct raw3270_view *view) | ||
773 | { | ||
774 | struct raw3270 *rp; | ||
775 | int rc; | ||
776 | |||
777 | rp = view->dev; | ||
778 | if (!rp || rp->view != view) | ||
779 | rc = -EACCES; | ||
780 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) | ||
781 | rc = -ENODEV; | ||
782 | else | ||
783 | rc = raw3270_reset_device(view->dev); | ||
784 | return rc; | ||
785 | } | ||
786 | |||
747 | /* | 787 | /* |
748 | * Setup new 3270 device. | 788 | * Setup new 3270 device. |
749 | */ | 789 | */ |
@@ -774,11 +814,12 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc) | |||
774 | 814 | ||
775 | /* | 815 | /* |
776 | * Add device to list and find the smallest unused minor | 816 | * Add device to list and find the smallest unused minor |
777 | * number for it. | 817 | * number for it. Note: there is no device with minor 0, |
818 | * see special case for fs3270.c:fs3270_open(). | ||
778 | */ | 819 | */ |
779 | down(&raw3270_sem); | 820 | down(&raw3270_sem); |
780 | /* Keep the list sorted. */ | 821 | /* Keep the list sorted. */ |
781 | minor = 0; | 822 | minor = RAW3270_FIRSTMINOR; |
782 | rp->minor = -1; | 823 | rp->minor = -1; |
783 | list_for_each(l, &raw3270_devices) { | 824 | list_for_each(l, &raw3270_devices) { |
784 | tmp = list_entry(l, struct raw3270, list); | 825 | tmp = list_entry(l, struct raw3270, list); |
@@ -789,7 +830,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc) | |||
789 | } | 830 | } |
790 | minor++; | 831 | minor++; |
791 | } | 832 | } |
792 | if (rp->minor == -1 && minor < RAW3270_MAXDEVS) { | 833 | if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) { |
793 | rp->minor = minor; | 834 | rp->minor = minor; |
794 | list_add_tail(&rp->list, &raw3270_devices); | 835 | list_add_tail(&rp->list, &raw3270_devices); |
795 | } | 836 | } |
@@ -941,11 +982,12 @@ raw3270_deactivate_view(struct raw3270_view *view) | |||
941 | list_add_tail(&view->list, &rp->view_list); | 982 | list_add_tail(&view->list, &rp->view_list); |
942 | /* Try to activate another view. */ | 983 | /* Try to activate another view. */ |
943 | if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { | 984 | if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { |
944 | list_for_each_entry(view, &rp->view_list, list) | 985 | list_for_each_entry(view, &rp->view_list, list) { |
945 | if (view->fn->activate(view) == 0) { | 986 | rp->view = view; |
946 | rp->view = view; | 987 | if (view->fn->activate(view) == 0) |
947 | break; | 988 | break; |
948 | } | 989 | rp->view = 0; |
990 | } | ||
949 | } | 991 | } |
950 | } | 992 | } |
951 | spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); | 993 | spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); |
@@ -961,6 +1003,8 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor) | |||
961 | struct raw3270 *rp; | 1003 | struct raw3270 *rp; |
962 | int rc; | 1004 | int rc; |
963 | 1005 | ||
1006 | if (minor <= 0) | ||
1007 | return -ENODEV; | ||
964 | down(&raw3270_sem); | 1008 | down(&raw3270_sem); |
965 | rc = -ENODEV; | 1009 | rc = -ENODEV; |
966 | list_for_each_entry(rp, &raw3270_devices, list) { | 1010 | list_for_each_entry(rp, &raw3270_devices, list) { |
@@ -976,7 +1020,7 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor) | |||
976 | view->cols = rp->cols; | 1020 | view->cols = rp->cols; |
977 | view->ascebc = rp->ascebc; | 1021 | view->ascebc = rp->ascebc; |
978 | spin_lock_init(&view->lock); | 1022 | spin_lock_init(&view->lock); |
979 | list_add_tail(&view->list, &rp->view_list); | 1023 | list_add(&view->list, &rp->view_list); |
980 | rc = 0; | 1024 | rc = 0; |
981 | } | 1025 | } |
982 | spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); | 1026 | spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); |
@@ -1039,7 +1083,7 @@ raw3270_del_view(struct raw3270_view *view) | |||
1039 | if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) { | 1083 | if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) { |
1040 | /* Try to activate another view. */ | 1084 | /* Try to activate another view. */ |
1041 | list_for_each_entry(nv, &rp->view_list, list) { | 1085 | list_for_each_entry(nv, &rp->view_list, list) { |
1042 | if (nv->fn->activate(view) == 0) { | 1086 | if (nv->fn->activate(nv) == 0) { |
1043 | rp->view = nv; | 1087 | rp->view = nv; |
1044 | break; | 1088 | break; |
1045 | } | 1089 | } |
@@ -1063,6 +1107,12 @@ raw3270_delete_device(struct raw3270 *rp) | |||
1063 | 1107 | ||
1064 | /* Remove from device chain. */ | 1108 | /* Remove from device chain. */ |
1065 | down(&raw3270_sem); | 1109 | down(&raw3270_sem); |
1110 | if (rp->clttydev) | ||
1111 | class_device_destroy(class3270, | ||
1112 | MKDEV(IBM_TTY3270_MAJOR, rp->minor)); | ||
1113 | if (rp->cltubdev) | ||
1114 | class_device_destroy(class3270, | ||
1115 | MKDEV(IBM_FS3270_MAJOR, rp->minor)); | ||
1066 | list_del_init(&rp->list); | 1116 | list_del_init(&rp->list); |
1067 | up(&raw3270_sem); | 1117 | up(&raw3270_sem); |
1068 | 1118 | ||
@@ -1129,6 +1179,16 @@ raw3270_create_attributes(struct raw3270 *rp) | |||
1129 | { | 1179 | { |
1130 | //FIXME: check return code | 1180 | //FIXME: check return code |
1131 | sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group); | 1181 | sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group); |
1182 | rp->clttydev = | ||
1183 | class_device_create(class3270, | ||
1184 | MKDEV(IBM_TTY3270_MAJOR, rp->minor), | ||
1185 | &rp->cdev->dev, "tty%s", | ||
1186 | rp->cdev->dev.bus_id); | ||
1187 | rp->cltubdev = | ||
1188 | class_device_create(class3270, | ||
1189 | MKDEV(IBM_FS3270_MAJOR, rp->minor), | ||
1190 | &rp->cdev->dev, "tub%s", | ||
1191 | rp->cdev->dev.bus_id); | ||
1132 | } | 1192 | } |
1133 | 1193 | ||
1134 | /* | 1194 | /* |
@@ -1189,13 +1249,13 @@ raw3270_set_online (struct ccw_device *cdev) | |||
1189 | return PTR_ERR(rp); | 1249 | return PTR_ERR(rp); |
1190 | rc = raw3270_reset_device(rp); | 1250 | rc = raw3270_reset_device(rp); |
1191 | if (rc) | 1251 | if (rc) |
1192 | return rc; | 1252 | goto failure; |
1193 | rc = raw3270_size_device(rp); | 1253 | rc = raw3270_size_device(rp); |
1194 | if (rc) | 1254 | if (rc) |
1195 | return rc; | 1255 | goto failure; |
1196 | rc = raw3270_reset_device(rp); | 1256 | rc = raw3270_reset_device(rp); |
1197 | if (rc) | 1257 | if (rc) |
1198 | return rc; | 1258 | goto failure; |
1199 | raw3270_create_attributes(rp); | 1259 | raw3270_create_attributes(rp); |
1200 | set_bit(RAW3270_FLAGS_READY, &rp->flags); | 1260 | set_bit(RAW3270_FLAGS_READY, &rp->flags); |
1201 | down(&raw3270_sem); | 1261 | down(&raw3270_sem); |
@@ -1203,6 +1263,10 @@ raw3270_set_online (struct ccw_device *cdev) | |||
1203 | np->notifier(rp->minor, 1); | 1263 | np->notifier(rp->minor, 1); |
1204 | up(&raw3270_sem); | 1264 | up(&raw3270_sem); |
1205 | return 0; | 1265 | return 0; |
1266 | |||
1267 | failure: | ||
1268 | raw3270_delete_device(rp); | ||
1269 | return rc; | ||
1206 | } | 1270 | } |
1207 | 1271 | ||
1208 | /* | 1272 | /* |
@@ -1217,6 +1281,14 @@ raw3270_remove (struct ccw_device *cdev) | |||
1217 | struct raw3270_notifier *np; | 1281 | struct raw3270_notifier *np; |
1218 | 1282 | ||
1219 | rp = cdev->dev.driver_data; | 1283 | rp = cdev->dev.driver_data; |
1284 | /* | ||
1285 | * _remove is the opposite of _probe; it's probe that | ||
1286 | * should set up rp. raw3270_remove gets entered for | ||
1287 | * devices even if they haven't been varied online. | ||
1288 | * Thus, rp may validly be NULL here. | ||
1289 | */ | ||
1290 | if (rp == NULL) | ||
1291 | return; | ||
1220 | clear_bit(RAW3270_FLAGS_READY, &rp->flags); | 1292 | clear_bit(RAW3270_FLAGS_READY, &rp->flags); |
1221 | 1293 | ||
1222 | sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group); | 1294 | sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group); |
@@ -1301,6 +1373,7 @@ raw3270_init(void) | |||
1301 | if (rc == 0) { | 1373 | if (rc == 0) { |
1302 | /* Create attributes for early (= console) device. */ | 1374 | /* Create attributes for early (= console) device. */ |
1303 | down(&raw3270_sem); | 1375 | down(&raw3270_sem); |
1376 | class3270 = class_create(THIS_MODULE, "3270"); | ||
1304 | list_for_each_entry(rp, &raw3270_devices, list) { | 1377 | list_for_each_entry(rp, &raw3270_devices, list) { |
1305 | get_device(&rp->cdev->dev); | 1378 | get_device(&rp->cdev->dev); |
1306 | raw3270_create_attributes(rp); | 1379 | raw3270_create_attributes(rp); |
@@ -1314,6 +1387,7 @@ static void | |||
1314 | raw3270_exit(void) | 1387 | raw3270_exit(void) |
1315 | { | 1388 | { |
1316 | ccw_driver_unregister(&raw3270_ccw_driver); | 1389 | ccw_driver_unregister(&raw3270_ccw_driver); |
1390 | class_destroy(class3270); | ||
1317 | } | 1391 | } |
1318 | 1392 | ||
1319 | MODULE_LICENSE("GPL"); | 1393 | MODULE_LICENSE("GPL"); |
@@ -1335,7 +1409,9 @@ EXPORT_SYMBOL(raw3270_find_view); | |||
1335 | EXPORT_SYMBOL(raw3270_activate_view); | 1409 | EXPORT_SYMBOL(raw3270_activate_view); |
1336 | EXPORT_SYMBOL(raw3270_deactivate_view); | 1410 | EXPORT_SYMBOL(raw3270_deactivate_view); |
1337 | EXPORT_SYMBOL(raw3270_start); | 1411 | EXPORT_SYMBOL(raw3270_start); |
1412 | EXPORT_SYMBOL(raw3270_start_locked); | ||
1338 | EXPORT_SYMBOL(raw3270_start_irq); | 1413 | EXPORT_SYMBOL(raw3270_start_irq); |
1414 | EXPORT_SYMBOL(raw3270_reset); | ||
1339 | EXPORT_SYMBOL(raw3270_register_notifier); | 1415 | EXPORT_SYMBOL(raw3270_register_notifier); |
1340 | EXPORT_SYMBOL(raw3270_unregister_notifier); | 1416 | EXPORT_SYMBOL(raw3270_unregister_notifier); |
1341 | EXPORT_SYMBOL(raw3270_wait_queue); | 1417 | EXPORT_SYMBOL(raw3270_wait_queue); |