18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for s390 chsc subchannels 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2008, 2011 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/compat.h> 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 168c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel_stat.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <asm/cio.h> 208c2ecf20Sopenharmony_ci#include <asm/chsc.h> 218c2ecf20Sopenharmony_ci#include <asm/isc.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "cio.h" 248c2ecf20Sopenharmony_ci#include "cio_debug.h" 258c2ecf20Sopenharmony_ci#include "css.h" 268c2ecf20Sopenharmony_ci#include "chsc_sch.h" 278c2ecf20Sopenharmony_ci#include "ioasm.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic debug_info_t *chsc_debug_msg_id; 308c2ecf20Sopenharmony_cistatic debug_info_t *chsc_debug_log_id; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic struct chsc_request *on_close_request; 338c2ecf20Sopenharmony_cistatic struct chsc_async_area *on_close_chsc_area; 348c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(on_close_mutex); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define CHSC_MSG(imp, args...) do { \ 378c2ecf20Sopenharmony_ci debug_sprintf_event(chsc_debug_msg_id, imp , ##args); \ 388c2ecf20Sopenharmony_ci } while (0) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define CHSC_LOG(imp, txt) do { \ 418c2ecf20Sopenharmony_ci debug_text_event(chsc_debug_log_id, imp , txt); \ 428c2ecf20Sopenharmony_ci } while (0) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic void CHSC_LOG_HEX(int level, void *data, int length) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci debug_event(chsc_debug_log_id, level, data, length); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciMODULE_AUTHOR("IBM Corporation"); 508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("driver for s390 chsc subchannels"); 518c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic void chsc_subchannel_irq(struct subchannel *sch) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct chsc_private *private = dev_get_drvdata(&sch->dev); 568c2ecf20Sopenharmony_ci struct chsc_request *request = private->request; 578c2ecf20Sopenharmony_ci struct irb *irb = this_cpu_ptr(&cio_irb); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci CHSC_LOG(4, "irb"); 608c2ecf20Sopenharmony_ci CHSC_LOG_HEX(4, irb, sizeof(*irb)); 618c2ecf20Sopenharmony_ci inc_irq_stat(IRQIO_CSC); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* Copy irb to provided request and set done. */ 648c2ecf20Sopenharmony_ci if (!request) { 658c2ecf20Sopenharmony_ci CHSC_MSG(0, "Interrupt on sch 0.%x.%04x with no request\n", 668c2ecf20Sopenharmony_ci sch->schid.ssid, sch->schid.sch_no); 678c2ecf20Sopenharmony_ci return; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci private->request = NULL; 708c2ecf20Sopenharmony_ci memcpy(&request->irb, irb, sizeof(*irb)); 718c2ecf20Sopenharmony_ci cio_update_schib(sch); 728c2ecf20Sopenharmony_ci complete(&request->completion); 738c2ecf20Sopenharmony_ci put_device(&sch->dev); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int chsc_subchannel_probe(struct subchannel *sch) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct chsc_private *private; 798c2ecf20Sopenharmony_ci int ret; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci CHSC_MSG(6, "Detected chsc subchannel 0.%x.%04x\n", 828c2ecf20Sopenharmony_ci sch->schid.ssid, sch->schid.sch_no); 838c2ecf20Sopenharmony_ci sch->isc = CHSC_SCH_ISC; 848c2ecf20Sopenharmony_ci private = kzalloc(sizeof(*private), GFP_KERNEL); 858c2ecf20Sopenharmony_ci if (!private) 868c2ecf20Sopenharmony_ci return -ENOMEM; 878c2ecf20Sopenharmony_ci dev_set_drvdata(&sch->dev, private); 888c2ecf20Sopenharmony_ci ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); 898c2ecf20Sopenharmony_ci if (ret) { 908c2ecf20Sopenharmony_ci CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n", 918c2ecf20Sopenharmony_ci sch->schid.ssid, sch->schid.sch_no, ret); 928c2ecf20Sopenharmony_ci dev_set_drvdata(&sch->dev, NULL); 938c2ecf20Sopenharmony_ci kfree(private); 948c2ecf20Sopenharmony_ci } else { 958c2ecf20Sopenharmony_ci if (dev_get_uevent_suppress(&sch->dev)) { 968c2ecf20Sopenharmony_ci dev_set_uevent_suppress(&sch->dev, 0); 978c2ecf20Sopenharmony_ci kobject_uevent(&sch->dev.kobj, KOBJ_ADD); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci return ret; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int chsc_subchannel_remove(struct subchannel *sch) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct chsc_private *private; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci cio_disable_subchannel(sch); 1088c2ecf20Sopenharmony_ci private = dev_get_drvdata(&sch->dev); 1098c2ecf20Sopenharmony_ci dev_set_drvdata(&sch->dev, NULL); 1108c2ecf20Sopenharmony_ci if (private->request) { 1118c2ecf20Sopenharmony_ci complete(&private->request->completion); 1128c2ecf20Sopenharmony_ci put_device(&sch->dev); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci kfree(private); 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void chsc_subchannel_shutdown(struct subchannel *sch) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci cio_disable_subchannel(sch); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic int chsc_subchannel_prepare(struct subchannel *sch) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci int cc; 1268c2ecf20Sopenharmony_ci struct schib schib; 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * Don't allow suspend while the subchannel is not idle 1298c2ecf20Sopenharmony_ci * since we don't have a way to clear the subchannel and 1308c2ecf20Sopenharmony_ci * cannot disable it with a request running. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_ci cc = stsch(sch->schid, &schib); 1338c2ecf20Sopenharmony_ci if (!cc && scsw_stctl(&schib.scsw)) 1348c2ecf20Sopenharmony_ci return -EAGAIN; 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int chsc_subchannel_freeze(struct subchannel *sch) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci return cio_disable_subchannel(sch); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int chsc_subchannel_restore(struct subchannel *sch) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci return cio_enable_subchannel(sch, (u32)(unsigned long)sch); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic struct css_device_id chsc_subchannel_ids[] = { 1498c2ecf20Sopenharmony_ci { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, }, 1508c2ecf20Sopenharmony_ci { /* end of list */ }, 1518c2ecf20Sopenharmony_ci}; 1528c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(css, chsc_subchannel_ids); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic struct css_driver chsc_subchannel_driver = { 1558c2ecf20Sopenharmony_ci .drv = { 1568c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1578c2ecf20Sopenharmony_ci .name = "chsc_subchannel", 1588c2ecf20Sopenharmony_ci }, 1598c2ecf20Sopenharmony_ci .subchannel_type = chsc_subchannel_ids, 1608c2ecf20Sopenharmony_ci .irq = chsc_subchannel_irq, 1618c2ecf20Sopenharmony_ci .probe = chsc_subchannel_probe, 1628c2ecf20Sopenharmony_ci .remove = chsc_subchannel_remove, 1638c2ecf20Sopenharmony_ci .shutdown = chsc_subchannel_shutdown, 1648c2ecf20Sopenharmony_ci .prepare = chsc_subchannel_prepare, 1658c2ecf20Sopenharmony_ci .freeze = chsc_subchannel_freeze, 1668c2ecf20Sopenharmony_ci .thaw = chsc_subchannel_restore, 1678c2ecf20Sopenharmony_ci .restore = chsc_subchannel_restore, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic int __init chsc_init_dbfs(void) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci chsc_debug_msg_id = debug_register("chsc_msg", 8, 1, 4 * sizeof(long)); 1738c2ecf20Sopenharmony_ci if (!chsc_debug_msg_id) 1748c2ecf20Sopenharmony_ci goto out; 1758c2ecf20Sopenharmony_ci debug_register_view(chsc_debug_msg_id, &debug_sprintf_view); 1768c2ecf20Sopenharmony_ci debug_set_level(chsc_debug_msg_id, 2); 1778c2ecf20Sopenharmony_ci chsc_debug_log_id = debug_register("chsc_log", 16, 1, 16); 1788c2ecf20Sopenharmony_ci if (!chsc_debug_log_id) 1798c2ecf20Sopenharmony_ci goto out; 1808c2ecf20Sopenharmony_ci debug_register_view(chsc_debug_log_id, &debug_hex_ascii_view); 1818c2ecf20Sopenharmony_ci debug_set_level(chsc_debug_log_id, 2); 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ciout: 1848c2ecf20Sopenharmony_ci debug_unregister(chsc_debug_msg_id); 1858c2ecf20Sopenharmony_ci return -ENOMEM; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void chsc_remove_dbfs(void) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci debug_unregister(chsc_debug_log_id); 1918c2ecf20Sopenharmony_ci debug_unregister(chsc_debug_msg_id); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int __init chsc_init_sch_driver(void) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci return css_driver_register(&chsc_subchannel_driver); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic void chsc_cleanup_sch_driver(void) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci css_driver_unregister(&chsc_subchannel_driver); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(chsc_lock); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int chsc_subchannel_match_next_free(struct device *dev, const void *data) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct subchannel *sch = to_subchannel(dev); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return sch->schib.pmcw.ena && !scsw_fctl(&sch->schib.scsw); 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic struct subchannel *chsc_get_next_subchannel(struct subchannel *sch) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct device *dev; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci dev = driver_find_device(&chsc_subchannel_driver.drv, 2188c2ecf20Sopenharmony_ci sch ? &sch->dev : NULL, NULL, 2198c2ecf20Sopenharmony_ci chsc_subchannel_match_next_free); 2208c2ecf20Sopenharmony_ci return dev ? to_subchannel(dev) : NULL; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/** 2248c2ecf20Sopenharmony_ci * chsc_async() - try to start a chsc request asynchronously 2258c2ecf20Sopenharmony_ci * @chsc_area: request to be started 2268c2ecf20Sopenharmony_ci * @request: request structure to associate 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * Tries to start a chsc request on one of the existing chsc subchannels. 2298c2ecf20Sopenharmony_ci * Returns: 2308c2ecf20Sopenharmony_ci * %0 if the request was performed synchronously 2318c2ecf20Sopenharmony_ci * %-EINPROGRESS if the request was successfully started 2328c2ecf20Sopenharmony_ci * %-EBUSY if all chsc subchannels are busy 2338c2ecf20Sopenharmony_ci * %-ENODEV if no chsc subchannels are available 2348c2ecf20Sopenharmony_ci * Context: 2358c2ecf20Sopenharmony_ci * interrupts disabled, chsc_lock held 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_cistatic int chsc_async(struct chsc_async_area *chsc_area, 2388c2ecf20Sopenharmony_ci struct chsc_request *request) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci int cc; 2418c2ecf20Sopenharmony_ci struct chsc_private *private; 2428c2ecf20Sopenharmony_ci struct subchannel *sch = NULL; 2438c2ecf20Sopenharmony_ci int ret = -ENODEV; 2448c2ecf20Sopenharmony_ci char dbf[10]; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci chsc_area->header.key = PAGE_DEFAULT_KEY >> 4; 2478c2ecf20Sopenharmony_ci while ((sch = chsc_get_next_subchannel(sch))) { 2488c2ecf20Sopenharmony_ci spin_lock(sch->lock); 2498c2ecf20Sopenharmony_ci private = dev_get_drvdata(&sch->dev); 2508c2ecf20Sopenharmony_ci if (private->request) { 2518c2ecf20Sopenharmony_ci spin_unlock(sch->lock); 2528c2ecf20Sopenharmony_ci ret = -EBUSY; 2538c2ecf20Sopenharmony_ci continue; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci chsc_area->header.sid = sch->schid; 2568c2ecf20Sopenharmony_ci CHSC_LOG(2, "schid"); 2578c2ecf20Sopenharmony_ci CHSC_LOG_HEX(2, &sch->schid, sizeof(sch->schid)); 2588c2ecf20Sopenharmony_ci cc = chsc(chsc_area); 2598c2ecf20Sopenharmony_ci snprintf(dbf, sizeof(dbf), "cc:%d", cc); 2608c2ecf20Sopenharmony_ci CHSC_LOG(2, dbf); 2618c2ecf20Sopenharmony_ci switch (cc) { 2628c2ecf20Sopenharmony_ci case 0: 2638c2ecf20Sopenharmony_ci ret = 0; 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci case 1: 2668c2ecf20Sopenharmony_ci sch->schib.scsw.cmd.fctl |= SCSW_FCTL_START_FUNC; 2678c2ecf20Sopenharmony_ci ret = -EINPROGRESS; 2688c2ecf20Sopenharmony_ci private->request = request; 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci case 2: 2718c2ecf20Sopenharmony_ci ret = -EBUSY; 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci default: 2748c2ecf20Sopenharmony_ci ret = -ENODEV; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci spin_unlock(sch->lock); 2778c2ecf20Sopenharmony_ci CHSC_MSG(2, "chsc on 0.%x.%04x returned cc=%d\n", 2788c2ecf20Sopenharmony_ci sch->schid.ssid, sch->schid.sch_no, cc); 2798c2ecf20Sopenharmony_ci if (ret == -EINPROGRESS) 2808c2ecf20Sopenharmony_ci return -EINPROGRESS; 2818c2ecf20Sopenharmony_ci put_device(&sch->dev); 2828c2ecf20Sopenharmony_ci if (ret == 0) 2838c2ecf20Sopenharmony_ci return 0; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic void chsc_log_command(void *chsc_area) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci char dbf[10]; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci snprintf(dbf, sizeof(dbf), "CHSC:%x", ((uint16_t *)chsc_area)[1]); 2938c2ecf20Sopenharmony_ci CHSC_LOG(0, dbf); 2948c2ecf20Sopenharmony_ci CHSC_LOG_HEX(0, chsc_area, 32); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int chsc_examine_irb(struct chsc_request *request) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci int backed_up; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (!(scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND)) 3028c2ecf20Sopenharmony_ci return -EIO; 3038c2ecf20Sopenharmony_ci backed_up = scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHAIN_CHECK; 3048c2ecf20Sopenharmony_ci request->irb.scsw.cmd.cstat &= ~SCHN_STAT_CHAIN_CHECK; 3058c2ecf20Sopenharmony_ci if (scsw_cstat(&request->irb.scsw) == 0) 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci if (!backed_up) 3088c2ecf20Sopenharmony_ci return 0; 3098c2ecf20Sopenharmony_ci if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROG_CHECK) 3108c2ecf20Sopenharmony_ci return -EIO; 3118c2ecf20Sopenharmony_ci if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROT_CHECK) 3128c2ecf20Sopenharmony_ci return -EPERM; 3138c2ecf20Sopenharmony_ci if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_DATA_CHK) 3148c2ecf20Sopenharmony_ci return -EAGAIN; 3158c2ecf20Sopenharmony_ci if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_CTRL_CHK) 3168c2ecf20Sopenharmony_ci return -EAGAIN; 3178c2ecf20Sopenharmony_ci return -EIO; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int chsc_ioctl_start(void __user *user_area) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct chsc_request *request; 3238c2ecf20Sopenharmony_ci struct chsc_async_area *chsc_area; 3248c2ecf20Sopenharmony_ci int ret; 3258c2ecf20Sopenharmony_ci char dbf[10]; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!css_general_characteristics.dynio) 3288c2ecf20Sopenharmony_ci /* It makes no sense to try. */ 3298c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 3308c2ecf20Sopenharmony_ci chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL); 3318c2ecf20Sopenharmony_ci if (!chsc_area) 3328c2ecf20Sopenharmony_ci return -ENOMEM; 3338c2ecf20Sopenharmony_ci request = kzalloc(sizeof(*request), GFP_KERNEL); 3348c2ecf20Sopenharmony_ci if (!request) { 3358c2ecf20Sopenharmony_ci ret = -ENOMEM; 3368c2ecf20Sopenharmony_ci goto out_free; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci init_completion(&request->completion); 3398c2ecf20Sopenharmony_ci if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) { 3408c2ecf20Sopenharmony_ci ret = -EFAULT; 3418c2ecf20Sopenharmony_ci goto out_free; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci chsc_log_command(chsc_area); 3448c2ecf20Sopenharmony_ci spin_lock_irq(&chsc_lock); 3458c2ecf20Sopenharmony_ci ret = chsc_async(chsc_area, request); 3468c2ecf20Sopenharmony_ci spin_unlock_irq(&chsc_lock); 3478c2ecf20Sopenharmony_ci if (ret == -EINPROGRESS) { 3488c2ecf20Sopenharmony_ci wait_for_completion(&request->completion); 3498c2ecf20Sopenharmony_ci ret = chsc_examine_irb(request); 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci /* copy area back to user */ 3528c2ecf20Sopenharmony_ci if (!ret) 3538c2ecf20Sopenharmony_ci if (copy_to_user(user_area, chsc_area, PAGE_SIZE)) 3548c2ecf20Sopenharmony_ci ret = -EFAULT; 3558c2ecf20Sopenharmony_ciout_free: 3568c2ecf20Sopenharmony_ci snprintf(dbf, sizeof(dbf), "ret:%d", ret); 3578c2ecf20Sopenharmony_ci CHSC_LOG(0, dbf); 3588c2ecf20Sopenharmony_ci kfree(request); 3598c2ecf20Sopenharmony_ci free_page((unsigned long)chsc_area); 3608c2ecf20Sopenharmony_ci return ret; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int chsc_ioctl_on_close_set(void __user *user_area) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci char dbf[13]; 3668c2ecf20Sopenharmony_ci int ret; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci mutex_lock(&on_close_mutex); 3698c2ecf20Sopenharmony_ci if (on_close_chsc_area) { 3708c2ecf20Sopenharmony_ci ret = -EBUSY; 3718c2ecf20Sopenharmony_ci goto out_unlock; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci on_close_request = kzalloc(sizeof(*on_close_request), GFP_KERNEL); 3748c2ecf20Sopenharmony_ci if (!on_close_request) { 3758c2ecf20Sopenharmony_ci ret = -ENOMEM; 3768c2ecf20Sopenharmony_ci goto out_unlock; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci on_close_chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL); 3798c2ecf20Sopenharmony_ci if (!on_close_chsc_area) { 3808c2ecf20Sopenharmony_ci ret = -ENOMEM; 3818c2ecf20Sopenharmony_ci goto out_free_request; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci if (copy_from_user(on_close_chsc_area, user_area, PAGE_SIZE)) { 3848c2ecf20Sopenharmony_ci ret = -EFAULT; 3858c2ecf20Sopenharmony_ci goto out_free_chsc; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci ret = 0; 3888c2ecf20Sopenharmony_ci goto out_unlock; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ciout_free_chsc: 3918c2ecf20Sopenharmony_ci free_page((unsigned long)on_close_chsc_area); 3928c2ecf20Sopenharmony_ci on_close_chsc_area = NULL; 3938c2ecf20Sopenharmony_ciout_free_request: 3948c2ecf20Sopenharmony_ci kfree(on_close_request); 3958c2ecf20Sopenharmony_ci on_close_request = NULL; 3968c2ecf20Sopenharmony_ciout_unlock: 3978c2ecf20Sopenharmony_ci mutex_unlock(&on_close_mutex); 3988c2ecf20Sopenharmony_ci snprintf(dbf, sizeof(dbf), "ocsret:%d", ret); 3998c2ecf20Sopenharmony_ci CHSC_LOG(0, dbf); 4008c2ecf20Sopenharmony_ci return ret; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic int chsc_ioctl_on_close_remove(void) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci char dbf[13]; 4068c2ecf20Sopenharmony_ci int ret; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci mutex_lock(&on_close_mutex); 4098c2ecf20Sopenharmony_ci if (!on_close_chsc_area) { 4108c2ecf20Sopenharmony_ci ret = -ENOENT; 4118c2ecf20Sopenharmony_ci goto out_unlock; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci free_page((unsigned long)on_close_chsc_area); 4148c2ecf20Sopenharmony_ci on_close_chsc_area = NULL; 4158c2ecf20Sopenharmony_ci kfree(on_close_request); 4168c2ecf20Sopenharmony_ci on_close_request = NULL; 4178c2ecf20Sopenharmony_ci ret = 0; 4188c2ecf20Sopenharmony_ciout_unlock: 4198c2ecf20Sopenharmony_ci mutex_unlock(&on_close_mutex); 4208c2ecf20Sopenharmony_ci snprintf(dbf, sizeof(dbf), "ocrret:%d", ret); 4218c2ecf20Sopenharmony_ci CHSC_LOG(0, dbf); 4228c2ecf20Sopenharmony_ci return ret; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int chsc_ioctl_start_sync(void __user *user_area) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct chsc_sync_area *chsc_area; 4288c2ecf20Sopenharmony_ci int ret, ccode; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci chsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); 4318c2ecf20Sopenharmony_ci if (!chsc_area) 4328c2ecf20Sopenharmony_ci return -ENOMEM; 4338c2ecf20Sopenharmony_ci if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) { 4348c2ecf20Sopenharmony_ci ret = -EFAULT; 4358c2ecf20Sopenharmony_ci goto out_free; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci if (chsc_area->header.code & 0x4000) { 4388c2ecf20Sopenharmony_ci ret = -EINVAL; 4398c2ecf20Sopenharmony_ci goto out_free; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci chsc_log_command(chsc_area); 4428c2ecf20Sopenharmony_ci ccode = chsc(chsc_area); 4438c2ecf20Sopenharmony_ci if (ccode != 0) { 4448c2ecf20Sopenharmony_ci ret = -EIO; 4458c2ecf20Sopenharmony_ci goto out_free; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci if (copy_to_user(user_area, chsc_area, PAGE_SIZE)) 4488c2ecf20Sopenharmony_ci ret = -EFAULT; 4498c2ecf20Sopenharmony_ci else 4508c2ecf20Sopenharmony_ci ret = 0; 4518c2ecf20Sopenharmony_ciout_free: 4528c2ecf20Sopenharmony_ci free_page((unsigned long)chsc_area); 4538c2ecf20Sopenharmony_ci return ret; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic int chsc_ioctl_info_channel_path(void __user *user_cd) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct chsc_chp_cd *cd; 4598c2ecf20Sopenharmony_ci int ret, ccode; 4608c2ecf20Sopenharmony_ci struct { 4618c2ecf20Sopenharmony_ci struct chsc_header request; 4628c2ecf20Sopenharmony_ci u32 : 2; 4638c2ecf20Sopenharmony_ci u32 m : 1; 4648c2ecf20Sopenharmony_ci u32 : 1; 4658c2ecf20Sopenharmony_ci u32 fmt1 : 4; 4668c2ecf20Sopenharmony_ci u32 cssid : 8; 4678c2ecf20Sopenharmony_ci u32 : 8; 4688c2ecf20Sopenharmony_ci u32 first_chpid : 8; 4698c2ecf20Sopenharmony_ci u32 : 24; 4708c2ecf20Sopenharmony_ci u32 last_chpid : 8; 4718c2ecf20Sopenharmony_ci u32 : 32; 4728c2ecf20Sopenharmony_ci struct chsc_header response; 4738c2ecf20Sopenharmony_ci u8 data[PAGE_SIZE - 20]; 4748c2ecf20Sopenharmony_ci } __attribute__ ((packed)) *scpcd_area; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci scpcd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); 4778c2ecf20Sopenharmony_ci if (!scpcd_area) 4788c2ecf20Sopenharmony_ci return -ENOMEM; 4798c2ecf20Sopenharmony_ci cd = kzalloc(sizeof(*cd), GFP_KERNEL); 4808c2ecf20Sopenharmony_ci if (!cd) { 4818c2ecf20Sopenharmony_ci ret = -ENOMEM; 4828c2ecf20Sopenharmony_ci goto out_free; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci if (copy_from_user(cd, user_cd, sizeof(*cd))) { 4858c2ecf20Sopenharmony_ci ret = -EFAULT; 4868c2ecf20Sopenharmony_ci goto out_free; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci scpcd_area->request.length = 0x0010; 4898c2ecf20Sopenharmony_ci scpcd_area->request.code = 0x0028; 4908c2ecf20Sopenharmony_ci scpcd_area->m = cd->m; 4918c2ecf20Sopenharmony_ci scpcd_area->fmt1 = cd->fmt; 4928c2ecf20Sopenharmony_ci scpcd_area->cssid = cd->chpid.cssid; 4938c2ecf20Sopenharmony_ci scpcd_area->first_chpid = cd->chpid.id; 4948c2ecf20Sopenharmony_ci scpcd_area->last_chpid = cd->chpid.id; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci ccode = chsc(scpcd_area); 4978c2ecf20Sopenharmony_ci if (ccode != 0) { 4988c2ecf20Sopenharmony_ci ret = -EIO; 4998c2ecf20Sopenharmony_ci goto out_free; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci if (scpcd_area->response.code != 0x0001) { 5028c2ecf20Sopenharmony_ci ret = -EIO; 5038c2ecf20Sopenharmony_ci CHSC_MSG(0, "scpcd: response code=%x\n", 5048c2ecf20Sopenharmony_ci scpcd_area->response.code); 5058c2ecf20Sopenharmony_ci goto out_free; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci memcpy(&cd->cpcb, &scpcd_area->response, scpcd_area->response.length); 5088c2ecf20Sopenharmony_ci if (copy_to_user(user_cd, cd, sizeof(*cd))) 5098c2ecf20Sopenharmony_ci ret = -EFAULT; 5108c2ecf20Sopenharmony_ci else 5118c2ecf20Sopenharmony_ci ret = 0; 5128c2ecf20Sopenharmony_ciout_free: 5138c2ecf20Sopenharmony_ci kfree(cd); 5148c2ecf20Sopenharmony_ci free_page((unsigned long)scpcd_area); 5158c2ecf20Sopenharmony_ci return ret; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic int chsc_ioctl_info_cu(void __user *user_cd) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct chsc_cu_cd *cd; 5218c2ecf20Sopenharmony_ci int ret, ccode; 5228c2ecf20Sopenharmony_ci struct { 5238c2ecf20Sopenharmony_ci struct chsc_header request; 5248c2ecf20Sopenharmony_ci u32 : 2; 5258c2ecf20Sopenharmony_ci u32 m : 1; 5268c2ecf20Sopenharmony_ci u32 : 1; 5278c2ecf20Sopenharmony_ci u32 fmt1 : 4; 5288c2ecf20Sopenharmony_ci u32 cssid : 8; 5298c2ecf20Sopenharmony_ci u32 : 8; 5308c2ecf20Sopenharmony_ci u32 first_cun : 8; 5318c2ecf20Sopenharmony_ci u32 : 24; 5328c2ecf20Sopenharmony_ci u32 last_cun : 8; 5338c2ecf20Sopenharmony_ci u32 : 32; 5348c2ecf20Sopenharmony_ci struct chsc_header response; 5358c2ecf20Sopenharmony_ci u8 data[PAGE_SIZE - 20]; 5368c2ecf20Sopenharmony_ci } __attribute__ ((packed)) *scucd_area; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci scucd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); 5398c2ecf20Sopenharmony_ci if (!scucd_area) 5408c2ecf20Sopenharmony_ci return -ENOMEM; 5418c2ecf20Sopenharmony_ci cd = kzalloc(sizeof(*cd), GFP_KERNEL); 5428c2ecf20Sopenharmony_ci if (!cd) { 5438c2ecf20Sopenharmony_ci ret = -ENOMEM; 5448c2ecf20Sopenharmony_ci goto out_free; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci if (copy_from_user(cd, user_cd, sizeof(*cd))) { 5478c2ecf20Sopenharmony_ci ret = -EFAULT; 5488c2ecf20Sopenharmony_ci goto out_free; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci scucd_area->request.length = 0x0010; 5518c2ecf20Sopenharmony_ci scucd_area->request.code = 0x0026; 5528c2ecf20Sopenharmony_ci scucd_area->m = cd->m; 5538c2ecf20Sopenharmony_ci scucd_area->fmt1 = cd->fmt; 5548c2ecf20Sopenharmony_ci scucd_area->cssid = cd->cssid; 5558c2ecf20Sopenharmony_ci scucd_area->first_cun = cd->cun; 5568c2ecf20Sopenharmony_ci scucd_area->last_cun = cd->cun; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ccode = chsc(scucd_area); 5598c2ecf20Sopenharmony_ci if (ccode != 0) { 5608c2ecf20Sopenharmony_ci ret = -EIO; 5618c2ecf20Sopenharmony_ci goto out_free; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci if (scucd_area->response.code != 0x0001) { 5648c2ecf20Sopenharmony_ci ret = -EIO; 5658c2ecf20Sopenharmony_ci CHSC_MSG(0, "scucd: response code=%x\n", 5668c2ecf20Sopenharmony_ci scucd_area->response.code); 5678c2ecf20Sopenharmony_ci goto out_free; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci memcpy(&cd->cucb, &scucd_area->response, scucd_area->response.length); 5708c2ecf20Sopenharmony_ci if (copy_to_user(user_cd, cd, sizeof(*cd))) 5718c2ecf20Sopenharmony_ci ret = -EFAULT; 5728c2ecf20Sopenharmony_ci else 5738c2ecf20Sopenharmony_ci ret = 0; 5748c2ecf20Sopenharmony_ciout_free: 5758c2ecf20Sopenharmony_ci kfree(cd); 5768c2ecf20Sopenharmony_ci free_page((unsigned long)scucd_area); 5778c2ecf20Sopenharmony_ci return ret; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic int chsc_ioctl_info_sch_cu(void __user *user_cud) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci struct chsc_sch_cud *cud; 5838c2ecf20Sopenharmony_ci int ret, ccode; 5848c2ecf20Sopenharmony_ci struct { 5858c2ecf20Sopenharmony_ci struct chsc_header request; 5868c2ecf20Sopenharmony_ci u32 : 2; 5878c2ecf20Sopenharmony_ci u32 m : 1; 5888c2ecf20Sopenharmony_ci u32 : 5; 5898c2ecf20Sopenharmony_ci u32 fmt1 : 4; 5908c2ecf20Sopenharmony_ci u32 : 2; 5918c2ecf20Sopenharmony_ci u32 ssid : 2; 5928c2ecf20Sopenharmony_ci u32 first_sch : 16; 5938c2ecf20Sopenharmony_ci u32 : 8; 5948c2ecf20Sopenharmony_ci u32 cssid : 8; 5958c2ecf20Sopenharmony_ci u32 last_sch : 16; 5968c2ecf20Sopenharmony_ci u32 : 32; 5978c2ecf20Sopenharmony_ci struct chsc_header response; 5988c2ecf20Sopenharmony_ci u8 data[PAGE_SIZE - 20]; 5998c2ecf20Sopenharmony_ci } __attribute__ ((packed)) *sscud_area; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci sscud_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); 6028c2ecf20Sopenharmony_ci if (!sscud_area) 6038c2ecf20Sopenharmony_ci return -ENOMEM; 6048c2ecf20Sopenharmony_ci cud = kzalloc(sizeof(*cud), GFP_KERNEL); 6058c2ecf20Sopenharmony_ci if (!cud) { 6068c2ecf20Sopenharmony_ci ret = -ENOMEM; 6078c2ecf20Sopenharmony_ci goto out_free; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci if (copy_from_user(cud, user_cud, sizeof(*cud))) { 6108c2ecf20Sopenharmony_ci ret = -EFAULT; 6118c2ecf20Sopenharmony_ci goto out_free; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci sscud_area->request.length = 0x0010; 6148c2ecf20Sopenharmony_ci sscud_area->request.code = 0x0006; 6158c2ecf20Sopenharmony_ci sscud_area->m = cud->schid.m; 6168c2ecf20Sopenharmony_ci sscud_area->fmt1 = cud->fmt; 6178c2ecf20Sopenharmony_ci sscud_area->ssid = cud->schid.ssid; 6188c2ecf20Sopenharmony_ci sscud_area->first_sch = cud->schid.sch_no; 6198c2ecf20Sopenharmony_ci sscud_area->cssid = cud->schid.cssid; 6208c2ecf20Sopenharmony_ci sscud_area->last_sch = cud->schid.sch_no; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci ccode = chsc(sscud_area); 6238c2ecf20Sopenharmony_ci if (ccode != 0) { 6248c2ecf20Sopenharmony_ci ret = -EIO; 6258c2ecf20Sopenharmony_ci goto out_free; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci if (sscud_area->response.code != 0x0001) { 6288c2ecf20Sopenharmony_ci ret = -EIO; 6298c2ecf20Sopenharmony_ci CHSC_MSG(0, "sscud: response code=%x\n", 6308c2ecf20Sopenharmony_ci sscud_area->response.code); 6318c2ecf20Sopenharmony_ci goto out_free; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci memcpy(&cud->scub, &sscud_area->response, sscud_area->response.length); 6348c2ecf20Sopenharmony_ci if (copy_to_user(user_cud, cud, sizeof(*cud))) 6358c2ecf20Sopenharmony_ci ret = -EFAULT; 6368c2ecf20Sopenharmony_ci else 6378c2ecf20Sopenharmony_ci ret = 0; 6388c2ecf20Sopenharmony_ciout_free: 6398c2ecf20Sopenharmony_ci kfree(cud); 6408c2ecf20Sopenharmony_ci free_page((unsigned long)sscud_area); 6418c2ecf20Sopenharmony_ci return ret; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic int chsc_ioctl_conf_info(void __user *user_ci) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci struct chsc_conf_info *ci; 6478c2ecf20Sopenharmony_ci int ret, ccode; 6488c2ecf20Sopenharmony_ci struct { 6498c2ecf20Sopenharmony_ci struct chsc_header request; 6508c2ecf20Sopenharmony_ci u32 : 2; 6518c2ecf20Sopenharmony_ci u32 m : 1; 6528c2ecf20Sopenharmony_ci u32 : 1; 6538c2ecf20Sopenharmony_ci u32 fmt1 : 4; 6548c2ecf20Sopenharmony_ci u32 cssid : 8; 6558c2ecf20Sopenharmony_ci u32 : 6; 6568c2ecf20Sopenharmony_ci u32 ssid : 2; 6578c2ecf20Sopenharmony_ci u32 : 8; 6588c2ecf20Sopenharmony_ci u64 : 64; 6598c2ecf20Sopenharmony_ci struct chsc_header response; 6608c2ecf20Sopenharmony_ci u8 data[PAGE_SIZE - 20]; 6618c2ecf20Sopenharmony_ci } __attribute__ ((packed)) *sci_area; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci sci_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); 6648c2ecf20Sopenharmony_ci if (!sci_area) 6658c2ecf20Sopenharmony_ci return -ENOMEM; 6668c2ecf20Sopenharmony_ci ci = kzalloc(sizeof(*ci), GFP_KERNEL); 6678c2ecf20Sopenharmony_ci if (!ci) { 6688c2ecf20Sopenharmony_ci ret = -ENOMEM; 6698c2ecf20Sopenharmony_ci goto out_free; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci if (copy_from_user(ci, user_ci, sizeof(*ci))) { 6728c2ecf20Sopenharmony_ci ret = -EFAULT; 6738c2ecf20Sopenharmony_ci goto out_free; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci sci_area->request.length = 0x0010; 6768c2ecf20Sopenharmony_ci sci_area->request.code = 0x0012; 6778c2ecf20Sopenharmony_ci sci_area->m = ci->id.m; 6788c2ecf20Sopenharmony_ci sci_area->fmt1 = ci->fmt; 6798c2ecf20Sopenharmony_ci sci_area->cssid = ci->id.cssid; 6808c2ecf20Sopenharmony_ci sci_area->ssid = ci->id.ssid; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci ccode = chsc(sci_area); 6838c2ecf20Sopenharmony_ci if (ccode != 0) { 6848c2ecf20Sopenharmony_ci ret = -EIO; 6858c2ecf20Sopenharmony_ci goto out_free; 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci if (sci_area->response.code != 0x0001) { 6888c2ecf20Sopenharmony_ci ret = -EIO; 6898c2ecf20Sopenharmony_ci CHSC_MSG(0, "sci: response code=%x\n", 6908c2ecf20Sopenharmony_ci sci_area->response.code); 6918c2ecf20Sopenharmony_ci goto out_free; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci memcpy(&ci->scid, &sci_area->response, sci_area->response.length); 6948c2ecf20Sopenharmony_ci if (copy_to_user(user_ci, ci, sizeof(*ci))) 6958c2ecf20Sopenharmony_ci ret = -EFAULT; 6968c2ecf20Sopenharmony_ci else 6978c2ecf20Sopenharmony_ci ret = 0; 6988c2ecf20Sopenharmony_ciout_free: 6998c2ecf20Sopenharmony_ci kfree(ci); 7008c2ecf20Sopenharmony_ci free_page((unsigned long)sci_area); 7018c2ecf20Sopenharmony_ci return ret; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic int chsc_ioctl_conf_comp_list(void __user *user_ccl) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci struct chsc_comp_list *ccl; 7078c2ecf20Sopenharmony_ci int ret, ccode; 7088c2ecf20Sopenharmony_ci struct { 7098c2ecf20Sopenharmony_ci struct chsc_header request; 7108c2ecf20Sopenharmony_ci u32 ctype : 8; 7118c2ecf20Sopenharmony_ci u32 : 4; 7128c2ecf20Sopenharmony_ci u32 fmt : 4; 7138c2ecf20Sopenharmony_ci u32 : 16; 7148c2ecf20Sopenharmony_ci u64 : 64; 7158c2ecf20Sopenharmony_ci u32 list_parm[2]; 7168c2ecf20Sopenharmony_ci u64 : 64; 7178c2ecf20Sopenharmony_ci struct chsc_header response; 7188c2ecf20Sopenharmony_ci u8 data[PAGE_SIZE - 36]; 7198c2ecf20Sopenharmony_ci } __attribute__ ((packed)) *sccl_area; 7208c2ecf20Sopenharmony_ci struct { 7218c2ecf20Sopenharmony_ci u32 m : 1; 7228c2ecf20Sopenharmony_ci u32 : 31; 7238c2ecf20Sopenharmony_ci u32 cssid : 8; 7248c2ecf20Sopenharmony_ci u32 : 16; 7258c2ecf20Sopenharmony_ci u32 chpid : 8; 7268c2ecf20Sopenharmony_ci } __attribute__ ((packed)) *chpid_parm; 7278c2ecf20Sopenharmony_ci struct { 7288c2ecf20Sopenharmony_ci u32 f_cssid : 8; 7298c2ecf20Sopenharmony_ci u32 l_cssid : 8; 7308c2ecf20Sopenharmony_ci u32 : 16; 7318c2ecf20Sopenharmony_ci u32 res; 7328c2ecf20Sopenharmony_ci } __attribute__ ((packed)) *cssids_parm; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci sccl_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); 7358c2ecf20Sopenharmony_ci if (!sccl_area) 7368c2ecf20Sopenharmony_ci return -ENOMEM; 7378c2ecf20Sopenharmony_ci ccl = kzalloc(sizeof(*ccl), GFP_KERNEL); 7388c2ecf20Sopenharmony_ci if (!ccl) { 7398c2ecf20Sopenharmony_ci ret = -ENOMEM; 7408c2ecf20Sopenharmony_ci goto out_free; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci if (copy_from_user(ccl, user_ccl, sizeof(*ccl))) { 7438c2ecf20Sopenharmony_ci ret = -EFAULT; 7448c2ecf20Sopenharmony_ci goto out_free; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci sccl_area->request.length = 0x0020; 7478c2ecf20Sopenharmony_ci sccl_area->request.code = 0x0030; 7488c2ecf20Sopenharmony_ci sccl_area->fmt = ccl->req.fmt; 7498c2ecf20Sopenharmony_ci sccl_area->ctype = ccl->req.ctype; 7508c2ecf20Sopenharmony_ci switch (sccl_area->ctype) { 7518c2ecf20Sopenharmony_ci case CCL_CU_ON_CHP: 7528c2ecf20Sopenharmony_ci case CCL_IOP_CHP: 7538c2ecf20Sopenharmony_ci chpid_parm = (void *)&sccl_area->list_parm; 7548c2ecf20Sopenharmony_ci chpid_parm->m = ccl->req.chpid.m; 7558c2ecf20Sopenharmony_ci chpid_parm->cssid = ccl->req.chpid.chp.cssid; 7568c2ecf20Sopenharmony_ci chpid_parm->chpid = ccl->req.chpid.chp.id; 7578c2ecf20Sopenharmony_ci break; 7588c2ecf20Sopenharmony_ci case CCL_CSS_IMG: 7598c2ecf20Sopenharmony_ci case CCL_CSS_IMG_CONF_CHAR: 7608c2ecf20Sopenharmony_ci cssids_parm = (void *)&sccl_area->list_parm; 7618c2ecf20Sopenharmony_ci cssids_parm->f_cssid = ccl->req.cssids.f_cssid; 7628c2ecf20Sopenharmony_ci cssids_parm->l_cssid = ccl->req.cssids.l_cssid; 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci ccode = chsc(sccl_area); 7668c2ecf20Sopenharmony_ci if (ccode != 0) { 7678c2ecf20Sopenharmony_ci ret = -EIO; 7688c2ecf20Sopenharmony_ci goto out_free; 7698c2ecf20Sopenharmony_ci } 7708c2ecf20Sopenharmony_ci if (sccl_area->response.code != 0x0001) { 7718c2ecf20Sopenharmony_ci ret = -EIO; 7728c2ecf20Sopenharmony_ci CHSC_MSG(0, "sccl: response code=%x\n", 7738c2ecf20Sopenharmony_ci sccl_area->response.code); 7748c2ecf20Sopenharmony_ci goto out_free; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci memcpy(&ccl->sccl, &sccl_area->response, sccl_area->response.length); 7778c2ecf20Sopenharmony_ci if (copy_to_user(user_ccl, ccl, sizeof(*ccl))) 7788c2ecf20Sopenharmony_ci ret = -EFAULT; 7798c2ecf20Sopenharmony_ci else 7808c2ecf20Sopenharmony_ci ret = 0; 7818c2ecf20Sopenharmony_ciout_free: 7828c2ecf20Sopenharmony_ci kfree(ccl); 7838c2ecf20Sopenharmony_ci free_page((unsigned long)sccl_area); 7848c2ecf20Sopenharmony_ci return ret; 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_cistatic int chsc_ioctl_chpd(void __user *user_chpd) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct chsc_scpd *scpd_area; 7908c2ecf20Sopenharmony_ci struct chsc_cpd_info *chpd; 7918c2ecf20Sopenharmony_ci int ret; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci chpd = kzalloc(sizeof(*chpd), GFP_KERNEL); 7948c2ecf20Sopenharmony_ci scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); 7958c2ecf20Sopenharmony_ci if (!scpd_area || !chpd) { 7968c2ecf20Sopenharmony_ci ret = -ENOMEM; 7978c2ecf20Sopenharmony_ci goto out_free; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) { 8008c2ecf20Sopenharmony_ci ret = -EFAULT; 8018c2ecf20Sopenharmony_ci goto out_free; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt, 8048c2ecf20Sopenharmony_ci chpd->rfmt, chpd->c, chpd->m, 8058c2ecf20Sopenharmony_ci scpd_area); 8068c2ecf20Sopenharmony_ci if (ret) 8078c2ecf20Sopenharmony_ci goto out_free; 8088c2ecf20Sopenharmony_ci memcpy(&chpd->chpdb, &scpd_area->response, scpd_area->response.length); 8098c2ecf20Sopenharmony_ci if (copy_to_user(user_chpd, chpd, sizeof(*chpd))) 8108c2ecf20Sopenharmony_ci ret = -EFAULT; 8118c2ecf20Sopenharmony_ciout_free: 8128c2ecf20Sopenharmony_ci kfree(chpd); 8138c2ecf20Sopenharmony_ci free_page((unsigned long)scpd_area); 8148c2ecf20Sopenharmony_ci return ret; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic int chsc_ioctl_dcal(void __user *user_dcal) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci struct chsc_dcal *dcal; 8208c2ecf20Sopenharmony_ci int ret, ccode; 8218c2ecf20Sopenharmony_ci struct { 8228c2ecf20Sopenharmony_ci struct chsc_header request; 8238c2ecf20Sopenharmony_ci u32 atype : 8; 8248c2ecf20Sopenharmony_ci u32 : 4; 8258c2ecf20Sopenharmony_ci u32 fmt : 4; 8268c2ecf20Sopenharmony_ci u32 : 16; 8278c2ecf20Sopenharmony_ci u32 res0[2]; 8288c2ecf20Sopenharmony_ci u32 list_parm[2]; 8298c2ecf20Sopenharmony_ci u32 res1[2]; 8308c2ecf20Sopenharmony_ci struct chsc_header response; 8318c2ecf20Sopenharmony_ci u8 data[PAGE_SIZE - 36]; 8328c2ecf20Sopenharmony_ci } __attribute__ ((packed)) *sdcal_area; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci sdcal_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); 8358c2ecf20Sopenharmony_ci if (!sdcal_area) 8368c2ecf20Sopenharmony_ci return -ENOMEM; 8378c2ecf20Sopenharmony_ci dcal = kzalloc(sizeof(*dcal), GFP_KERNEL); 8388c2ecf20Sopenharmony_ci if (!dcal) { 8398c2ecf20Sopenharmony_ci ret = -ENOMEM; 8408c2ecf20Sopenharmony_ci goto out_free; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci if (copy_from_user(dcal, user_dcal, sizeof(*dcal))) { 8438c2ecf20Sopenharmony_ci ret = -EFAULT; 8448c2ecf20Sopenharmony_ci goto out_free; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci sdcal_area->request.length = 0x0020; 8478c2ecf20Sopenharmony_ci sdcal_area->request.code = 0x0034; 8488c2ecf20Sopenharmony_ci sdcal_area->atype = dcal->req.atype; 8498c2ecf20Sopenharmony_ci sdcal_area->fmt = dcal->req.fmt; 8508c2ecf20Sopenharmony_ci memcpy(&sdcal_area->list_parm, &dcal->req.list_parm, 8518c2ecf20Sopenharmony_ci sizeof(sdcal_area->list_parm)); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci ccode = chsc(sdcal_area); 8548c2ecf20Sopenharmony_ci if (ccode != 0) { 8558c2ecf20Sopenharmony_ci ret = -EIO; 8568c2ecf20Sopenharmony_ci goto out_free; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci if (sdcal_area->response.code != 0x0001) { 8598c2ecf20Sopenharmony_ci ret = -EIO; 8608c2ecf20Sopenharmony_ci CHSC_MSG(0, "sdcal: response code=%x\n", 8618c2ecf20Sopenharmony_ci sdcal_area->response.code); 8628c2ecf20Sopenharmony_ci goto out_free; 8638c2ecf20Sopenharmony_ci } 8648c2ecf20Sopenharmony_ci memcpy(&dcal->sdcal, &sdcal_area->response, 8658c2ecf20Sopenharmony_ci sdcal_area->response.length); 8668c2ecf20Sopenharmony_ci if (copy_to_user(user_dcal, dcal, sizeof(*dcal))) 8678c2ecf20Sopenharmony_ci ret = -EFAULT; 8688c2ecf20Sopenharmony_ci else 8698c2ecf20Sopenharmony_ci ret = 0; 8708c2ecf20Sopenharmony_ciout_free: 8718c2ecf20Sopenharmony_ci kfree(dcal); 8728c2ecf20Sopenharmony_ci free_page((unsigned long)sdcal_area); 8738c2ecf20Sopenharmony_ci return ret; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic long chsc_ioctl(struct file *filp, unsigned int cmd, 8778c2ecf20Sopenharmony_ci unsigned long arg) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci void __user *argp; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci CHSC_MSG(2, "chsc_ioctl called, cmd=%x\n", cmd); 8828c2ecf20Sopenharmony_ci if (is_compat_task()) 8838c2ecf20Sopenharmony_ci argp = compat_ptr(arg); 8848c2ecf20Sopenharmony_ci else 8858c2ecf20Sopenharmony_ci argp = (void __user *)arg; 8868c2ecf20Sopenharmony_ci switch (cmd) { 8878c2ecf20Sopenharmony_ci case CHSC_START: 8888c2ecf20Sopenharmony_ci return chsc_ioctl_start(argp); 8898c2ecf20Sopenharmony_ci case CHSC_START_SYNC: 8908c2ecf20Sopenharmony_ci return chsc_ioctl_start_sync(argp); 8918c2ecf20Sopenharmony_ci case CHSC_INFO_CHANNEL_PATH: 8928c2ecf20Sopenharmony_ci return chsc_ioctl_info_channel_path(argp); 8938c2ecf20Sopenharmony_ci case CHSC_INFO_CU: 8948c2ecf20Sopenharmony_ci return chsc_ioctl_info_cu(argp); 8958c2ecf20Sopenharmony_ci case CHSC_INFO_SCH_CU: 8968c2ecf20Sopenharmony_ci return chsc_ioctl_info_sch_cu(argp); 8978c2ecf20Sopenharmony_ci case CHSC_INFO_CI: 8988c2ecf20Sopenharmony_ci return chsc_ioctl_conf_info(argp); 8998c2ecf20Sopenharmony_ci case CHSC_INFO_CCL: 9008c2ecf20Sopenharmony_ci return chsc_ioctl_conf_comp_list(argp); 9018c2ecf20Sopenharmony_ci case CHSC_INFO_CPD: 9028c2ecf20Sopenharmony_ci return chsc_ioctl_chpd(argp); 9038c2ecf20Sopenharmony_ci case CHSC_INFO_DCAL: 9048c2ecf20Sopenharmony_ci return chsc_ioctl_dcal(argp); 9058c2ecf20Sopenharmony_ci case CHSC_ON_CLOSE_SET: 9068c2ecf20Sopenharmony_ci return chsc_ioctl_on_close_set(argp); 9078c2ecf20Sopenharmony_ci case CHSC_ON_CLOSE_REMOVE: 9088c2ecf20Sopenharmony_ci return chsc_ioctl_on_close_remove(); 9098c2ecf20Sopenharmony_ci default: /* unknown ioctl number */ 9108c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci} 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_cistatic atomic_t chsc_ready_for_use = ATOMIC_INIT(1); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic int chsc_open(struct inode *inode, struct file *file) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci if (!atomic_dec_and_test(&chsc_ready_for_use)) { 9198c2ecf20Sopenharmony_ci atomic_inc(&chsc_ready_for_use); 9208c2ecf20Sopenharmony_ci return -EBUSY; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci return nonseekable_open(inode, file); 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic int chsc_release(struct inode *inode, struct file *filp) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci char dbf[13]; 9288c2ecf20Sopenharmony_ci int ret; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci mutex_lock(&on_close_mutex); 9318c2ecf20Sopenharmony_ci if (!on_close_chsc_area) 9328c2ecf20Sopenharmony_ci goto out_unlock; 9338c2ecf20Sopenharmony_ci init_completion(&on_close_request->completion); 9348c2ecf20Sopenharmony_ci CHSC_LOG(0, "on_close"); 9358c2ecf20Sopenharmony_ci chsc_log_command(on_close_chsc_area); 9368c2ecf20Sopenharmony_ci spin_lock_irq(&chsc_lock); 9378c2ecf20Sopenharmony_ci ret = chsc_async(on_close_chsc_area, on_close_request); 9388c2ecf20Sopenharmony_ci spin_unlock_irq(&chsc_lock); 9398c2ecf20Sopenharmony_ci if (ret == -EINPROGRESS) { 9408c2ecf20Sopenharmony_ci wait_for_completion(&on_close_request->completion); 9418c2ecf20Sopenharmony_ci ret = chsc_examine_irb(on_close_request); 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci snprintf(dbf, sizeof(dbf), "relret:%d", ret); 9448c2ecf20Sopenharmony_ci CHSC_LOG(0, dbf); 9458c2ecf20Sopenharmony_ci free_page((unsigned long)on_close_chsc_area); 9468c2ecf20Sopenharmony_ci on_close_chsc_area = NULL; 9478c2ecf20Sopenharmony_ci kfree(on_close_request); 9488c2ecf20Sopenharmony_ci on_close_request = NULL; 9498c2ecf20Sopenharmony_ciout_unlock: 9508c2ecf20Sopenharmony_ci mutex_unlock(&on_close_mutex); 9518c2ecf20Sopenharmony_ci atomic_inc(&chsc_ready_for_use); 9528c2ecf20Sopenharmony_ci return 0; 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic const struct file_operations chsc_fops = { 9568c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 9578c2ecf20Sopenharmony_ci .open = chsc_open, 9588c2ecf20Sopenharmony_ci .release = chsc_release, 9598c2ecf20Sopenharmony_ci .unlocked_ioctl = chsc_ioctl, 9608c2ecf20Sopenharmony_ci .compat_ioctl = chsc_ioctl, 9618c2ecf20Sopenharmony_ci .llseek = no_llseek, 9628c2ecf20Sopenharmony_ci}; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cistatic struct miscdevice chsc_misc_device = { 9658c2ecf20Sopenharmony_ci .minor = MISC_DYNAMIC_MINOR, 9668c2ecf20Sopenharmony_ci .name = "chsc", 9678c2ecf20Sopenharmony_ci .fops = &chsc_fops, 9688c2ecf20Sopenharmony_ci}; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic int __init chsc_misc_init(void) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci return misc_register(&chsc_misc_device); 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_cistatic void chsc_misc_cleanup(void) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci misc_deregister(&chsc_misc_device); 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic int __init chsc_sch_init(void) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci int ret; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci ret = chsc_init_dbfs(); 9858c2ecf20Sopenharmony_ci if (ret) 9868c2ecf20Sopenharmony_ci return ret; 9878c2ecf20Sopenharmony_ci isc_register(CHSC_SCH_ISC); 9888c2ecf20Sopenharmony_ci ret = chsc_init_sch_driver(); 9898c2ecf20Sopenharmony_ci if (ret) 9908c2ecf20Sopenharmony_ci goto out_dbf; 9918c2ecf20Sopenharmony_ci ret = chsc_misc_init(); 9928c2ecf20Sopenharmony_ci if (ret) 9938c2ecf20Sopenharmony_ci goto out_driver; 9948c2ecf20Sopenharmony_ci return ret; 9958c2ecf20Sopenharmony_ciout_driver: 9968c2ecf20Sopenharmony_ci chsc_cleanup_sch_driver(); 9978c2ecf20Sopenharmony_ciout_dbf: 9988c2ecf20Sopenharmony_ci isc_unregister(CHSC_SCH_ISC); 9998c2ecf20Sopenharmony_ci chsc_remove_dbfs(); 10008c2ecf20Sopenharmony_ci return ret; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic void __exit chsc_sch_exit(void) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci chsc_misc_cleanup(); 10068c2ecf20Sopenharmony_ci chsc_cleanup_sch_driver(); 10078c2ecf20Sopenharmony_ci isc_unregister(CHSC_SCH_ISC); 10088c2ecf20Sopenharmony_ci chsc_remove_dbfs(); 10098c2ecf20Sopenharmony_ci} 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cimodule_init(chsc_sch_init); 10128c2ecf20Sopenharmony_cimodule_exit(chsc_sch_exit); 1013