📄 raw3270.c
字号:
if (!oldview || oldview->fn->activate(oldview) != 0) { /* Didn't work as well. Try any other view. */ list_for_each_entry(nv, &rp->view_list, list) if (nv != view && nv != oldview) { rp->view = nv; if (nv->fn->activate(nv) == 0) break; rp->view = 0; } } } } spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); return rc;}/* * Deactivate current view. */voidraw3270_deactivate_view(struct raw3270_view *view){ unsigned long flags; struct raw3270 *rp; rp = view->dev; if (!rp) return; spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); if (rp->view == view) { view->fn->deactivate(view); rp->view = 0; /* Move deactivated view to end of list. */ list_del_init(&view->list); list_add_tail(&view->list, &rp->view_list); /* Try to activate another view. */ if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { list_for_each_entry(view, &rp->view_list, list) { rp->view = view; if (view->fn->activate(view) == 0) break; rp->view = 0; } } } spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);}/* * Add view to device with minor "minor". */intraw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor){ unsigned long flags; struct raw3270 *rp; int rc; if (minor <= 0) return -ENODEV; down(&raw3270_sem); rc = -ENODEV; list_for_each_entry(rp, &raw3270_devices, list) { if (rp->minor != minor) continue; spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { atomic_set(&view->ref_count, 2); view->dev = rp; view->fn = fn; view->model = rp->model; view->rows = rp->rows; view->cols = rp->cols; view->ascebc = rp->ascebc; spin_lock_init(&view->lock); list_add(&view->list, &rp->view_list); rc = 0; } spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); break; } up(&raw3270_sem); return rc;}/* * Find specific view of device with minor "minor". */struct raw3270_view *raw3270_find_view(struct raw3270_fn *fn, int minor){ struct raw3270 *rp; struct raw3270_view *view, *tmp; unsigned long flags; down(&raw3270_sem); view = ERR_PTR(-ENODEV); list_for_each_entry(rp, &raw3270_devices, list) { if (rp->minor != minor) continue; spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { view = ERR_PTR(-ENOENT); list_for_each_entry(tmp, &rp->view_list, list) { if (tmp->fn == fn) { raw3270_get_view(tmp); view = tmp; break; } } } spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); break; } up(&raw3270_sem); return view;}/* * Remove view from device and free view structure via call to view->fn->free. */voidraw3270_del_view(struct raw3270_view *view){ unsigned long flags; struct raw3270 *rp; struct raw3270_view *nv; rp = view->dev; spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); if (rp->view == view) { view->fn->deactivate(view); rp->view = 0; } list_del_init(&view->list); if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) { /* Try to activate another view. */ list_for_each_entry(nv, &rp->view_list, list) { if (nv->fn->activate(nv) == 0) { rp->view = nv; break; } } } spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); /* Wait for reference counter to drop to zero. */ atomic_dec(&view->ref_count); wait_event(raw3270_wait_queue, atomic_read(&view->ref_count) == 0); if (view->fn->free) view->fn->free(view);}/* * Remove a 3270 device structure. */static voidraw3270_delete_device(struct raw3270 *rp){ struct ccw_device *cdev; /* Remove from device chain. */ down(&raw3270_sem); if (rp->clttydev) class_device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor)); if (rp->cltubdev) class_device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, rp->minor)); list_del_init(&rp->list); up(&raw3270_sem); /* Disconnect from ccw_device. */ cdev = rp->cdev; rp->cdev = 0; cdev->dev.driver_data = 0; cdev->handler = 0; /* Put ccw_device structure. */ put_device(&cdev->dev); /* Now free raw3270 structure. */ kfree(rp->ascebc); kfree(rp);}static intraw3270_probe (struct ccw_device *cdev){ return 0;}/* * Additional attributes for a 3270 device */static ssize_traw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf){ return snprintf(buf, PAGE_SIZE, "%i\n", ((struct raw3270 *) dev->driver_data)->model);}static DEVICE_ATTR(model, 0444, raw3270_model_show, 0);static ssize_traw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf){ return snprintf(buf, PAGE_SIZE, "%i\n", ((struct raw3270 *) dev->driver_data)->rows);}static DEVICE_ATTR(rows, 0444, raw3270_rows_show, 0);static ssize_traw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf){ return snprintf(buf, PAGE_SIZE, "%i\n", ((struct raw3270 *) dev->driver_data)->cols);}static DEVICE_ATTR(columns, 0444, raw3270_columns_show, 0);static struct attribute * raw3270_attrs[] = { &dev_attr_model.attr, &dev_attr_rows.attr, &dev_attr_columns.attr, NULL,};static struct attribute_group raw3270_attr_group = { .attrs = raw3270_attrs,};static voidraw3270_create_attributes(struct raw3270 *rp){ //FIXME: check return code sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group); rp->clttydev = class_device_create(class3270, NULL, MKDEV(IBM_TTY3270_MAJOR, rp->minor), &rp->cdev->dev, "tty%s", rp->cdev->dev.bus_id); rp->cltubdev = class_device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, rp->minor), &rp->cdev->dev, "tub%s", rp->cdev->dev.bus_id);}/* * 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. */static intraw3270_set_online (struct ccw_device *cdev){ struct raw3270 *rp; struct raw3270_notifier *np; int rc; rp = raw3270_create_device(cdev); if (IS_ERR(rp)) return PTR_ERR(rp); rc = raw3270_reset_device(rp); if (rc) goto failure; rc = raw3270_size_device(rp); if (rc) goto failure; rc = raw3270_reset_device(rp); if (rc) goto failure; raw3270_create_attributes(rp); 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;failure: raw3270_delete_device(rp); return rc;}/* * Remove 3270 device structure. */static voidraw3270_remove (struct ccw_device *cdev){ unsigned long flags; struct raw3270 *rp; struct raw3270_view *v; struct raw3270_notifier *np; rp = cdev->dev.driver_data; /* * _remove is the opposite of _probe; it's probe that * should set up rp. raw3270_remove gets entered for * devices even if they haven't been varied online. * Thus, rp may validly be NULL here. */ if (rp == NULL) return; clear_bit(RAW3270_FLAGS_READY, &rp->flags); sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group); /* Deactivate current view and remove all views. */ spin_lock_irqsave(get_ccwdev_lock(cdev), flags); if (rp->view) { rp->view->fn->deactivate(rp->view); rp->view = 0; } while (!list_empty(&rp->view_list)) { v = list_entry(rp->view_list.next, struct raw3270_view, list); if (v->fn->release) v->fn->release(v); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); raw3270_del_view(v); spin_lock_irqsave(get_ccwdev_lock(cdev), flags); } spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); down(&raw3270_sem); list_for_each_entry(np, &raw3270_notifier, list) np->notifier(rp->minor, 0); up(&raw3270_sem); /* Reset 3270 device. */ raw3270_reset_device(rp); /* And finally remove it. */ raw3270_delete_device(rp);}/* * Set 3270 device offline. */static intraw3270_set_offline (struct ccw_device *cdev){ struct raw3270 *rp; rp = cdev->dev.driver_data; if (test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) return -EBUSY; raw3270_remove(cdev); return 0;}static struct ccw_device_id raw3270_id[] = { { CCW_DEVICE(0x3270, 0) }, { CCW_DEVICE(0x3271, 0) }, { CCW_DEVICE(0x3272, 0) }, { CCW_DEVICE(0x3273, 0) }, { CCW_DEVICE(0x3274, 0) }, { CCW_DEVICE(0x3275, 0) }, { CCW_DEVICE(0x3276, 0) }, { CCW_DEVICE(0x3277, 0) }, { CCW_DEVICE(0x3278, 0) }, { CCW_DEVICE(0x3279, 0) }, { CCW_DEVICE(0x3174, 0) }, { /* end of list */ },};static struct ccw_driver raw3270_ccw_driver = { .name = "3270", .owner = THIS_MODULE, .ids = raw3270_id, .probe = &raw3270_probe, .remove = &raw3270_remove, .set_online = &raw3270_set_online, .set_offline = &raw3270_set_offline,};static intraw3270_init(void){ struct raw3270 *rp; int rc; if (raw3270_registered) return 0; raw3270_registered = 1; rc = ccw_driver_register(&raw3270_ccw_driver); if (rc == 0) { /* Create attributes for early (= console) device. */ down(&raw3270_sem); class3270 = class_create(THIS_MODULE, "3270"); list_for_each_entry(rp, &raw3270_devices, list) { get_device(&rp->cdev->dev); raw3270_create_attributes(rp); } up(&raw3270_sem); } return rc;}static voidraw3270_exit(void){ ccw_driver_unregister(&raw3270_ccw_driver); class_destroy(class3270);}MODULE_LICENSE("GPL");module_init(raw3270_init);module_exit(raw3270_exit);EXPORT_SYMBOL(raw3270_request_alloc);EXPORT_SYMBOL(raw3270_request_free);EXPORT_SYMBOL(raw3270_request_reset);EXPORT_SYMBOL(raw3270_request_set_cmd);EXPORT_SYMBOL(raw3270_request_add_data);EXPORT_SYMBOL(raw3270_request_set_data);EXPORT_SYMBOL(raw3270_request_set_idal);EXPORT_SYMBOL(raw3270_buffer_address);EXPORT_SYMBOL(raw3270_add_view);EXPORT_SYMBOL(raw3270_del_view);EXPORT_SYMBOL(raw3270_find_view);EXPORT_SYMBOL(raw3270_activate_view);EXPORT_SYMBOL(raw3270_deactivate_view);EXPORT_SYMBOL(raw3270_start);EXPORT_SYMBOL(raw3270_start_locked);EXPORT_SYMBOL(raw3270_start_irq);EXPORT_SYMBOL(raw3270_reset);EXPORT_SYMBOL(raw3270_register_notifier);EXPORT_SYMBOL(raw3270_unregister_notifier);EXPORT_SYMBOL(raw3270_wait_queue);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -