18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2005 Mike Isely <isely@pobox.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "pvrusb2-ctrl.h" 88c2ecf20Sopenharmony_ci#include "pvrusb2-hdw-internal.h" 98c2ecf20Sopenharmony_ci#include <linux/errno.h> 108c2ecf20Sopenharmony_ci#include <linux/string.h> 118c2ecf20Sopenharmony_ci#include <linux/mutex.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci if (cptr->info->check_value) { 178c2ecf20Sopenharmony_ci if (!cptr->info->check_value(cptr,val)) return -ERANGE; 188c2ecf20Sopenharmony_ci } else if (cptr->info->type == pvr2_ctl_enum) { 198c2ecf20Sopenharmony_ci if (val < 0) return -ERANGE; 208c2ecf20Sopenharmony_ci if (val >= cptr->info->def.type_enum.count) return -ERANGE; 218c2ecf20Sopenharmony_ci } else { 228c2ecf20Sopenharmony_ci int lim; 238c2ecf20Sopenharmony_ci lim = cptr->info->def.type_int.min_value; 248c2ecf20Sopenharmony_ci if (cptr->info->get_min_value) { 258c2ecf20Sopenharmony_ci cptr->info->get_min_value(cptr,&lim); 268c2ecf20Sopenharmony_ci } 278c2ecf20Sopenharmony_ci if (val < lim) return -ERANGE; 288c2ecf20Sopenharmony_ci lim = cptr->info->def.type_int.max_value; 298c2ecf20Sopenharmony_ci if (cptr->info->get_max_value) { 308c2ecf20Sopenharmony_ci cptr->info->get_max_value(cptr,&lim); 318c2ecf20Sopenharmony_ci } 328c2ecf20Sopenharmony_ci if (val > lim) return -ERANGE; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci return 0; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* Set the given control. */ 398c2ecf20Sopenharmony_ciint pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci return pvr2_ctrl_set_mask_value(cptr,~0,val); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* Set/clear specific bits of the given control. */ 468c2ecf20Sopenharmony_ciint pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci int ret = 0; 498c2ecf20Sopenharmony_ci if (!cptr) return -EINVAL; 508c2ecf20Sopenharmony_ci LOCK_TAKE(cptr->hdw->big_lock); do { 518c2ecf20Sopenharmony_ci if (cptr->info->set_value) { 528c2ecf20Sopenharmony_ci if (cptr->info->type == pvr2_ctl_bitmask) { 538c2ecf20Sopenharmony_ci mask &= cptr->info->def.type_bitmask.valid_bits; 548c2ecf20Sopenharmony_ci } else if ((cptr->info->type == pvr2_ctl_int)|| 558c2ecf20Sopenharmony_ci (cptr->info->type == pvr2_ctl_enum)) { 568c2ecf20Sopenharmony_ci ret = pvr2_ctrl_range_check(cptr,val); 578c2ecf20Sopenharmony_ci if (ret < 0) break; 588c2ecf20Sopenharmony_ci } else if (cptr->info->type != pvr2_ctl_bool) { 598c2ecf20Sopenharmony_ci break; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci ret = cptr->info->set_value(cptr,mask,val); 628c2ecf20Sopenharmony_ci } else { 638c2ecf20Sopenharmony_ci ret = -EPERM; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(cptr->hdw->big_lock); 668c2ecf20Sopenharmony_ci return ret; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Get the current value of the given control. */ 718c2ecf20Sopenharmony_ciint pvr2_ctrl_get_value(struct pvr2_ctrl *cptr,int *valptr) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci int ret = 0; 748c2ecf20Sopenharmony_ci if (!cptr) return -EINVAL; 758c2ecf20Sopenharmony_ci LOCK_TAKE(cptr->hdw->big_lock); do { 768c2ecf20Sopenharmony_ci ret = cptr->info->get_value(cptr,valptr); 778c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(cptr->hdw->big_lock); 788c2ecf20Sopenharmony_ci return ret; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* Retrieve control's type */ 838c2ecf20Sopenharmony_cienum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *cptr) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci if (!cptr) return pvr2_ctl_int; 868c2ecf20Sopenharmony_ci return cptr->info->type; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* Retrieve control's maximum value (int type) */ 918c2ecf20Sopenharmony_ciint pvr2_ctrl_get_max(struct pvr2_ctrl *cptr) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci int ret = 0; 948c2ecf20Sopenharmony_ci if (!cptr) return 0; 958c2ecf20Sopenharmony_ci LOCK_TAKE(cptr->hdw->big_lock); do { 968c2ecf20Sopenharmony_ci if (cptr->info->get_max_value) { 978c2ecf20Sopenharmony_ci cptr->info->get_max_value(cptr,&ret); 988c2ecf20Sopenharmony_ci } else if (cptr->info->type == pvr2_ctl_int) { 998c2ecf20Sopenharmony_ci ret = cptr->info->def.type_int.max_value; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(cptr->hdw->big_lock); 1028c2ecf20Sopenharmony_ci return ret; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* Retrieve control's minimum value (int type) */ 1078c2ecf20Sopenharmony_ciint pvr2_ctrl_get_min(struct pvr2_ctrl *cptr) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int ret = 0; 1108c2ecf20Sopenharmony_ci if (!cptr) return 0; 1118c2ecf20Sopenharmony_ci LOCK_TAKE(cptr->hdw->big_lock); do { 1128c2ecf20Sopenharmony_ci if (cptr->info->get_min_value) { 1138c2ecf20Sopenharmony_ci cptr->info->get_min_value(cptr,&ret); 1148c2ecf20Sopenharmony_ci } else if (cptr->info->type == pvr2_ctl_int) { 1158c2ecf20Sopenharmony_ci ret = cptr->info->def.type_int.min_value; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(cptr->hdw->big_lock); 1188c2ecf20Sopenharmony_ci return ret; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/* Retrieve control's default value (any type) */ 1238c2ecf20Sopenharmony_ciint pvr2_ctrl_get_def(struct pvr2_ctrl *cptr, int *valptr) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci int ret = 0; 1268c2ecf20Sopenharmony_ci if (!cptr) return -EINVAL; 1278c2ecf20Sopenharmony_ci LOCK_TAKE(cptr->hdw->big_lock); do { 1288c2ecf20Sopenharmony_ci if (cptr->info->get_def_value) { 1298c2ecf20Sopenharmony_ci ret = cptr->info->get_def_value(cptr, valptr); 1308c2ecf20Sopenharmony_ci } else { 1318c2ecf20Sopenharmony_ci *valptr = cptr->info->default_value; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(cptr->hdw->big_lock); 1348c2ecf20Sopenharmony_ci return ret; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Retrieve control's enumeration count (enum only) */ 1398c2ecf20Sopenharmony_ciint pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci int ret = 0; 1428c2ecf20Sopenharmony_ci if (!cptr) return 0; 1438c2ecf20Sopenharmony_ci LOCK_TAKE(cptr->hdw->big_lock); do { 1448c2ecf20Sopenharmony_ci if (cptr->info->type == pvr2_ctl_enum) { 1458c2ecf20Sopenharmony_ci ret = cptr->info->def.type_enum.count; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(cptr->hdw->big_lock); 1488c2ecf20Sopenharmony_ci return ret; 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* Retrieve control's valid mask bits (bit mask only) */ 1538c2ecf20Sopenharmony_ciint pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci int ret = 0; 1568c2ecf20Sopenharmony_ci if (!cptr) return 0; 1578c2ecf20Sopenharmony_ci LOCK_TAKE(cptr->hdw->big_lock); do { 1588c2ecf20Sopenharmony_ci if (cptr->info->type == pvr2_ctl_bitmask) { 1598c2ecf20Sopenharmony_ci ret = cptr->info->def.type_bitmask.valid_bits; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(cptr->hdw->big_lock); 1628c2ecf20Sopenharmony_ci return ret; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/* Retrieve the control's name */ 1678c2ecf20Sopenharmony_ciconst char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci if (!cptr) return NULL; 1708c2ecf20Sopenharmony_ci return cptr->info->name; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/* Retrieve the control's desc */ 1758c2ecf20Sopenharmony_ciconst char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci if (!cptr) return NULL; 1788c2ecf20Sopenharmony_ci return cptr->info->desc; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* Retrieve a control enumeration or bit mask value */ 1838c2ecf20Sopenharmony_ciint pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val, 1848c2ecf20Sopenharmony_ci char *bptr,unsigned int bmax, 1858c2ecf20Sopenharmony_ci unsigned int *blen) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci int ret = -EINVAL; 1888c2ecf20Sopenharmony_ci if (!cptr) return 0; 1898c2ecf20Sopenharmony_ci *blen = 0; 1908c2ecf20Sopenharmony_ci LOCK_TAKE(cptr->hdw->big_lock); do { 1918c2ecf20Sopenharmony_ci if (cptr->info->type == pvr2_ctl_enum) { 1928c2ecf20Sopenharmony_ci const char * const *names; 1938c2ecf20Sopenharmony_ci names = cptr->info->def.type_enum.value_names; 1948c2ecf20Sopenharmony_ci if (pvr2_ctrl_range_check(cptr,val) == 0) { 1958c2ecf20Sopenharmony_ci if (names[val]) { 1968c2ecf20Sopenharmony_ci *blen = scnprintf( 1978c2ecf20Sopenharmony_ci bptr,bmax,"%s", 1988c2ecf20Sopenharmony_ci names[val]); 1998c2ecf20Sopenharmony_ci } else { 2008c2ecf20Sopenharmony_ci *blen = 0; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci ret = 0; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci } else if (cptr->info->type == pvr2_ctl_bitmask) { 2058c2ecf20Sopenharmony_ci const char **names; 2068c2ecf20Sopenharmony_ci unsigned int idx; 2078c2ecf20Sopenharmony_ci int msk; 2088c2ecf20Sopenharmony_ci names = cptr->info->def.type_bitmask.bit_names; 2098c2ecf20Sopenharmony_ci val &= cptr->info->def.type_bitmask.valid_bits; 2108c2ecf20Sopenharmony_ci for (idx = 0, msk = 1; val; idx++, msk <<= 1) { 2118c2ecf20Sopenharmony_ci if (val & msk) { 2128c2ecf20Sopenharmony_ci *blen = scnprintf(bptr,bmax,"%s", 2138c2ecf20Sopenharmony_ci names[idx]); 2148c2ecf20Sopenharmony_ci ret = 0; 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(cptr->hdw->big_lock); 2208c2ecf20Sopenharmony_ci return ret; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* Return V4L ID for this control or zero if none */ 2258c2ecf20Sopenharmony_ciint pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci if (!cptr) return 0; 2288c2ecf20Sopenharmony_ci return cptr->info->v4l_id; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ciunsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci unsigned int flags = 0; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (cptr->info->get_v4lflags) { 2378c2ecf20Sopenharmony_ci flags = cptr->info->get_v4lflags(cptr); 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (cptr->info->set_value) { 2418c2ecf20Sopenharmony_ci flags &= ~V4L2_CTRL_FLAG_READ_ONLY; 2428c2ecf20Sopenharmony_ci } else { 2438c2ecf20Sopenharmony_ci flags |= V4L2_CTRL_FLAG_READ_ONLY; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return flags; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* Return true if control is writable */ 2518c2ecf20Sopenharmony_ciint pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci if (!cptr) return 0; 2548c2ecf20Sopenharmony_ci return cptr->info->set_value != NULL; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/* Return true if control has custom symbolic representation */ 2598c2ecf20Sopenharmony_ciint pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci if (!cptr) return 0; 2628c2ecf20Sopenharmony_ci if (!cptr->info->val_to_sym) return 0; 2638c2ecf20Sopenharmony_ci if (!cptr->info->sym_to_val) return 0; 2648c2ecf20Sopenharmony_ci return !0; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* Convert a given mask/val to a custom symbolic value */ 2698c2ecf20Sopenharmony_ciint pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr, 2708c2ecf20Sopenharmony_ci int mask,int val, 2718c2ecf20Sopenharmony_ci char *buf,unsigned int maxlen, 2728c2ecf20Sopenharmony_ci unsigned int *len) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci if (!cptr) return -EINVAL; 2758c2ecf20Sopenharmony_ci if (!cptr->info->val_to_sym) return -EINVAL; 2768c2ecf20Sopenharmony_ci return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci/* Convert a symbolic value to a mask/value pair */ 2818c2ecf20Sopenharmony_ciint pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr, 2828c2ecf20Sopenharmony_ci const char *buf,unsigned int len, 2838c2ecf20Sopenharmony_ci int *maskptr,int *valptr) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci if (!cptr) return -EINVAL; 2868c2ecf20Sopenharmony_ci if (!cptr->info->sym_to_val) return -EINVAL; 2878c2ecf20Sopenharmony_ci return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic unsigned int gen_bitmask_string(int msk,int val,int msk_only, 2928c2ecf20Sopenharmony_ci const char **names, 2938c2ecf20Sopenharmony_ci char *ptr,unsigned int len) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci unsigned int idx; 2968c2ecf20Sopenharmony_ci long sm,um; 2978c2ecf20Sopenharmony_ci int spcFl; 2988c2ecf20Sopenharmony_ci unsigned int uc,cnt; 2998c2ecf20Sopenharmony_ci const char *idStr; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci spcFl = 0; 3028c2ecf20Sopenharmony_ci uc = 0; 3038c2ecf20Sopenharmony_ci um = 0; 3048c2ecf20Sopenharmony_ci for (idx = 0, sm = 1; msk; idx++, sm <<= 1) { 3058c2ecf20Sopenharmony_ci if (sm & msk) { 3068c2ecf20Sopenharmony_ci msk &= ~sm; 3078c2ecf20Sopenharmony_ci idStr = names[idx]; 3088c2ecf20Sopenharmony_ci if (idStr) { 3098c2ecf20Sopenharmony_ci cnt = scnprintf(ptr,len,"%s%s%s", 3108c2ecf20Sopenharmony_ci (spcFl ? " " : ""), 3118c2ecf20Sopenharmony_ci (msk_only ? "" : 3128c2ecf20Sopenharmony_ci ((val & sm) ? "+" : "-")), 3138c2ecf20Sopenharmony_ci idStr); 3148c2ecf20Sopenharmony_ci ptr += cnt; len -= cnt; uc += cnt; 3158c2ecf20Sopenharmony_ci spcFl = !0; 3168c2ecf20Sopenharmony_ci } else { 3178c2ecf20Sopenharmony_ci um |= sm; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci if (um) { 3228c2ecf20Sopenharmony_ci if (msk_only) { 3238c2ecf20Sopenharmony_ci cnt = scnprintf(ptr,len,"%s0x%lx", 3248c2ecf20Sopenharmony_ci (spcFl ? " " : ""), 3258c2ecf20Sopenharmony_ci um); 3268c2ecf20Sopenharmony_ci ptr += cnt; len -= cnt; uc += cnt; 3278c2ecf20Sopenharmony_ci spcFl = !0; 3288c2ecf20Sopenharmony_ci } else if (um & val) { 3298c2ecf20Sopenharmony_ci cnt = scnprintf(ptr,len,"%s+0x%lx", 3308c2ecf20Sopenharmony_ci (spcFl ? " " : ""), 3318c2ecf20Sopenharmony_ci um & val); 3328c2ecf20Sopenharmony_ci ptr += cnt; len -= cnt; uc += cnt; 3338c2ecf20Sopenharmony_ci spcFl = !0; 3348c2ecf20Sopenharmony_ci } else if (um & ~val) { 3358c2ecf20Sopenharmony_ci cnt = scnprintf(ptr,len,"%s+0x%lx", 3368c2ecf20Sopenharmony_ci (spcFl ? " " : ""), 3378c2ecf20Sopenharmony_ci um & ~val); 3388c2ecf20Sopenharmony_ci ptr += cnt; len -= cnt; uc += cnt; 3398c2ecf20Sopenharmony_ci spcFl = !0; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci return uc; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic const char *boolNames[] = { 3478c2ecf20Sopenharmony_ci "false", 3488c2ecf20Sopenharmony_ci "true", 3498c2ecf20Sopenharmony_ci "no", 3508c2ecf20Sopenharmony_ci "yes", 3518c2ecf20Sopenharmony_ci}; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int parse_token(const char *ptr,unsigned int len, 3558c2ecf20Sopenharmony_ci int *valptr, 3568c2ecf20Sopenharmony_ci const char * const *names, unsigned int namecnt) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci char buf[33]; 3598c2ecf20Sopenharmony_ci unsigned int slen; 3608c2ecf20Sopenharmony_ci unsigned int idx; 3618c2ecf20Sopenharmony_ci int negfl; 3628c2ecf20Sopenharmony_ci char *p2; 3638c2ecf20Sopenharmony_ci *valptr = 0; 3648c2ecf20Sopenharmony_ci if (!names) namecnt = 0; 3658c2ecf20Sopenharmony_ci for (idx = 0; idx < namecnt; idx++) { 3668c2ecf20Sopenharmony_ci if (!names[idx]) continue; 3678c2ecf20Sopenharmony_ci slen = strlen(names[idx]); 3688c2ecf20Sopenharmony_ci if (slen != len) continue; 3698c2ecf20Sopenharmony_ci if (memcmp(names[idx],ptr,slen)) continue; 3708c2ecf20Sopenharmony_ci *valptr = idx; 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci negfl = 0; 3748c2ecf20Sopenharmony_ci if ((*ptr == '-') || (*ptr == '+')) { 3758c2ecf20Sopenharmony_ci negfl = (*ptr == '-'); 3768c2ecf20Sopenharmony_ci ptr++; len--; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci if (len >= sizeof(buf)) return -EINVAL; 3798c2ecf20Sopenharmony_ci memcpy(buf,ptr,len); 3808c2ecf20Sopenharmony_ci buf[len] = 0; 3818c2ecf20Sopenharmony_ci *valptr = simple_strtol(buf,&p2,0); 3828c2ecf20Sopenharmony_ci if (negfl) *valptr = -(*valptr); 3838c2ecf20Sopenharmony_ci if (*p2) return -EINVAL; 3848c2ecf20Sopenharmony_ci return 1; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic int parse_mtoken(const char *ptr,unsigned int len, 3898c2ecf20Sopenharmony_ci int *valptr, 3908c2ecf20Sopenharmony_ci const char **names,int valid_bits) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci char buf[33]; 3938c2ecf20Sopenharmony_ci unsigned int slen; 3948c2ecf20Sopenharmony_ci unsigned int idx; 3958c2ecf20Sopenharmony_ci char *p2; 3968c2ecf20Sopenharmony_ci int msk; 3978c2ecf20Sopenharmony_ci *valptr = 0; 3988c2ecf20Sopenharmony_ci for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) { 3998c2ecf20Sopenharmony_ci if (!(msk & valid_bits)) continue; 4008c2ecf20Sopenharmony_ci valid_bits &= ~msk; 4018c2ecf20Sopenharmony_ci if (!names[idx]) continue; 4028c2ecf20Sopenharmony_ci slen = strlen(names[idx]); 4038c2ecf20Sopenharmony_ci if (slen != len) continue; 4048c2ecf20Sopenharmony_ci if (memcmp(names[idx],ptr,slen)) continue; 4058c2ecf20Sopenharmony_ci *valptr = msk; 4068c2ecf20Sopenharmony_ci return 0; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci if (len >= sizeof(buf)) return -EINVAL; 4098c2ecf20Sopenharmony_ci memcpy(buf,ptr,len); 4108c2ecf20Sopenharmony_ci buf[len] = 0; 4118c2ecf20Sopenharmony_ci *valptr = simple_strtol(buf,&p2,0); 4128c2ecf20Sopenharmony_ci if (*p2) return -EINVAL; 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int parse_tlist(const char *ptr,unsigned int len, 4188c2ecf20Sopenharmony_ci int *maskptr,int *valptr, 4198c2ecf20Sopenharmony_ci const char **names,int valid_bits) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci unsigned int cnt; 4228c2ecf20Sopenharmony_ci int mask,val,kv,mode,ret; 4238c2ecf20Sopenharmony_ci mask = 0; 4248c2ecf20Sopenharmony_ci val = 0; 4258c2ecf20Sopenharmony_ci ret = 0; 4268c2ecf20Sopenharmony_ci while (len) { 4278c2ecf20Sopenharmony_ci cnt = 0; 4288c2ecf20Sopenharmony_ci while ((cnt < len) && 4298c2ecf20Sopenharmony_ci ((ptr[cnt] <= 32) || 4308c2ecf20Sopenharmony_ci (ptr[cnt] >= 127))) cnt++; 4318c2ecf20Sopenharmony_ci ptr += cnt; 4328c2ecf20Sopenharmony_ci len -= cnt; 4338c2ecf20Sopenharmony_ci mode = 0; 4348c2ecf20Sopenharmony_ci if ((*ptr == '-') || (*ptr == '+')) { 4358c2ecf20Sopenharmony_ci mode = (*ptr == '-') ? -1 : 1; 4368c2ecf20Sopenharmony_ci ptr++; 4378c2ecf20Sopenharmony_ci len--; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci cnt = 0; 4408c2ecf20Sopenharmony_ci while (cnt < len) { 4418c2ecf20Sopenharmony_ci if (ptr[cnt] <= 32) break; 4428c2ecf20Sopenharmony_ci if (ptr[cnt] >= 127) break; 4438c2ecf20Sopenharmony_ci cnt++; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci if (!cnt) break; 4468c2ecf20Sopenharmony_ci if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) { 4478c2ecf20Sopenharmony_ci ret = -EINVAL; 4488c2ecf20Sopenharmony_ci break; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci ptr += cnt; 4518c2ecf20Sopenharmony_ci len -= cnt; 4528c2ecf20Sopenharmony_ci switch (mode) { 4538c2ecf20Sopenharmony_ci case 0: 4548c2ecf20Sopenharmony_ci mask = valid_bits; 4558c2ecf20Sopenharmony_ci val |= kv; 4568c2ecf20Sopenharmony_ci break; 4578c2ecf20Sopenharmony_ci case -1: 4588c2ecf20Sopenharmony_ci mask |= kv; 4598c2ecf20Sopenharmony_ci val &= ~kv; 4608c2ecf20Sopenharmony_ci break; 4618c2ecf20Sopenharmony_ci case 1: 4628c2ecf20Sopenharmony_ci mask |= kv; 4638c2ecf20Sopenharmony_ci val |= kv; 4648c2ecf20Sopenharmony_ci break; 4658c2ecf20Sopenharmony_ci default: 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci *maskptr = mask; 4708c2ecf20Sopenharmony_ci *valptr = val; 4718c2ecf20Sopenharmony_ci return ret; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* Convert a symbolic value to a mask/value pair */ 4768c2ecf20Sopenharmony_ciint pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr, 4778c2ecf20Sopenharmony_ci const char *ptr,unsigned int len, 4788c2ecf20Sopenharmony_ci int *maskptr,int *valptr) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci int ret = -EINVAL; 4818c2ecf20Sopenharmony_ci unsigned int cnt; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci *maskptr = 0; 4848c2ecf20Sopenharmony_ci *valptr = 0; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci cnt = 0; 4878c2ecf20Sopenharmony_ci while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++; 4888c2ecf20Sopenharmony_ci len -= cnt; ptr += cnt; 4898c2ecf20Sopenharmony_ci cnt = 0; 4908c2ecf20Sopenharmony_ci while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) || 4918c2ecf20Sopenharmony_ci (ptr[len-(cnt+1)] >= 127))) cnt++; 4928c2ecf20Sopenharmony_ci len -= cnt; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (!len) return -EINVAL; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci LOCK_TAKE(cptr->hdw->big_lock); do { 4978c2ecf20Sopenharmony_ci if (cptr->info->type == pvr2_ctl_int) { 4988c2ecf20Sopenharmony_ci ret = parse_token(ptr,len,valptr,NULL,0); 4998c2ecf20Sopenharmony_ci if (ret >= 0) { 5008c2ecf20Sopenharmony_ci ret = pvr2_ctrl_range_check(cptr,*valptr); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci *maskptr = ~0; 5038c2ecf20Sopenharmony_ci } else if (cptr->info->type == pvr2_ctl_bool) { 5048c2ecf20Sopenharmony_ci ret = parse_token(ptr,len,valptr,boolNames, 5058c2ecf20Sopenharmony_ci ARRAY_SIZE(boolNames)); 5068c2ecf20Sopenharmony_ci if (ret == 1) { 5078c2ecf20Sopenharmony_ci *valptr = *valptr ? !0 : 0; 5088c2ecf20Sopenharmony_ci } else if (ret == 0) { 5098c2ecf20Sopenharmony_ci *valptr = (*valptr & 1) ? !0 : 0; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci *maskptr = 1; 5128c2ecf20Sopenharmony_ci } else if (cptr->info->type == pvr2_ctl_enum) { 5138c2ecf20Sopenharmony_ci ret = parse_token( 5148c2ecf20Sopenharmony_ci ptr,len,valptr, 5158c2ecf20Sopenharmony_ci cptr->info->def.type_enum.value_names, 5168c2ecf20Sopenharmony_ci cptr->info->def.type_enum.count); 5178c2ecf20Sopenharmony_ci if (ret >= 0) { 5188c2ecf20Sopenharmony_ci ret = pvr2_ctrl_range_check(cptr,*valptr); 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci *maskptr = ~0; 5218c2ecf20Sopenharmony_ci } else if (cptr->info->type == pvr2_ctl_bitmask) { 5228c2ecf20Sopenharmony_ci ret = parse_tlist( 5238c2ecf20Sopenharmony_ci ptr,len,maskptr,valptr, 5248c2ecf20Sopenharmony_ci cptr->info->def.type_bitmask.bit_names, 5258c2ecf20Sopenharmony_ci cptr->info->def.type_bitmask.valid_bits); 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(cptr->hdw->big_lock); 5288c2ecf20Sopenharmony_ci return ret; 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci/* Convert a given mask/val to a symbolic value */ 5338c2ecf20Sopenharmony_ciint pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr, 5348c2ecf20Sopenharmony_ci int mask,int val, 5358c2ecf20Sopenharmony_ci char *buf,unsigned int maxlen, 5368c2ecf20Sopenharmony_ci unsigned int *len) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci int ret = -EINVAL; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci *len = 0; 5418c2ecf20Sopenharmony_ci if (cptr->info->type == pvr2_ctl_int) { 5428c2ecf20Sopenharmony_ci *len = scnprintf(buf,maxlen,"%d",val); 5438c2ecf20Sopenharmony_ci ret = 0; 5448c2ecf20Sopenharmony_ci } else if (cptr->info->type == pvr2_ctl_bool) { 5458c2ecf20Sopenharmony_ci *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false"); 5468c2ecf20Sopenharmony_ci ret = 0; 5478c2ecf20Sopenharmony_ci } else if (cptr->info->type == pvr2_ctl_enum) { 5488c2ecf20Sopenharmony_ci const char * const *names; 5498c2ecf20Sopenharmony_ci names = cptr->info->def.type_enum.value_names; 5508c2ecf20Sopenharmony_ci if ((val >= 0) && 5518c2ecf20Sopenharmony_ci (val < cptr->info->def.type_enum.count)) { 5528c2ecf20Sopenharmony_ci if (names[val]) { 5538c2ecf20Sopenharmony_ci *len = scnprintf( 5548c2ecf20Sopenharmony_ci buf,maxlen,"%s", 5558c2ecf20Sopenharmony_ci names[val]); 5568c2ecf20Sopenharmony_ci } else { 5578c2ecf20Sopenharmony_ci *len = 0; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci ret = 0; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci } else if (cptr->info->type == pvr2_ctl_bitmask) { 5628c2ecf20Sopenharmony_ci *len = gen_bitmask_string( 5638c2ecf20Sopenharmony_ci val & mask & cptr->info->def.type_bitmask.valid_bits, 5648c2ecf20Sopenharmony_ci ~0,!0, 5658c2ecf20Sopenharmony_ci cptr->info->def.type_bitmask.bit_names, 5668c2ecf20Sopenharmony_ci buf,maxlen); 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci return ret; 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci/* Convert a given mask/val to a symbolic value */ 5738c2ecf20Sopenharmony_ciint pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr, 5748c2ecf20Sopenharmony_ci int mask,int val, 5758c2ecf20Sopenharmony_ci char *buf,unsigned int maxlen, 5768c2ecf20Sopenharmony_ci unsigned int *len) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci int ret; 5798c2ecf20Sopenharmony_ci LOCK_TAKE(cptr->hdw->big_lock); do { 5808c2ecf20Sopenharmony_ci ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val, 5818c2ecf20Sopenharmony_ci buf,maxlen,len); 5828c2ecf20Sopenharmony_ci } while(0); LOCK_GIVE(cptr->hdw->big_lock); 5838c2ecf20Sopenharmony_ci return ret; 5848c2ecf20Sopenharmony_ci} 585