| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Copyright (C) 2005 Mike Isely <isely@pobox.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  *  it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  *  the Free Software Foundation; either version 2 of the License | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  *  GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  *  along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "pvrusb2-ctrl.h"
 | 
					
						
							|  |  |  | #include "pvrusb2-hdw-internal.h"
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | #include <linux/string.h>
 | 
					
						
							|  |  |  | #include <linux/mutex.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-27 23:28:54 -03:00
										 |  |  | static int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (cptr->info->check_value) { | 
					
						
							|  |  |  | 		if (!cptr->info->check_value(cptr,val)) return -ERANGE; | 
					
						
							| 
									
										
										
										
											2008-04-22 14:45:38 -03:00
										 |  |  | 	} else if (cptr->info->type == pvr2_ctl_enum) { | 
					
						
							|  |  |  | 		if (val < 0) return -ERANGE; | 
					
						
							|  |  |  | 		if (val >= cptr->info->def.type_enum.count) return -ERANGE; | 
					
						
							| 
									
										
										
										
											2006-12-27 23:28:54 -03:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		int lim; | 
					
						
							|  |  |  | 		lim = cptr->info->def.type_int.min_value; | 
					
						
							|  |  |  | 		if (cptr->info->get_min_value) { | 
					
						
							|  |  |  | 			cptr->info->get_min_value(cptr,&lim); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (val < lim) return -ERANGE; | 
					
						
							|  |  |  | 		lim = cptr->info->def.type_int.max_value; | 
					
						
							|  |  |  | 		if (cptr->info->get_max_value) { | 
					
						
							|  |  |  | 			cptr->info->get_max_value(cptr,&lim); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (val > lim) return -ERANGE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | /* Set the given control. */ | 
					
						
							|  |  |  | int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return pvr2_ctrl_set_mask_value(cptr,~0,val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Set/clear specific bits of the given control. */ | 
					
						
							|  |  |  | int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 	if (!cptr) return -EINVAL; | 
					
						
							|  |  |  | 	LOCK_TAKE(cptr->hdw->big_lock); do { | 
					
						
							| 
									
										
										
										
											2008-03-29 03:07:38 +00:00
										 |  |  | 		if (cptr->info->set_value) { | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 			if (cptr->info->type == pvr2_ctl_bitmask) { | 
					
						
							|  |  |  | 				mask &= cptr->info->def.type_bitmask.valid_bits; | 
					
						
							| 
									
										
										
										
											2008-04-22 14:45:38 -03:00
										 |  |  | 			} else if ((cptr->info->type == pvr2_ctl_int)|| | 
					
						
							|  |  |  | 				   (cptr->info->type == pvr2_ctl_enum)) { | 
					
						
							| 
									
										
										
										
											2006-12-27 23:28:54 -03:00
										 |  |  | 				ret = pvr2_ctrl_range_check(cptr,val); | 
					
						
							|  |  |  | 				if (ret < 0) break; | 
					
						
							| 
									
										
										
										
											2006-06-25 20:04:40 -03:00
										 |  |  | 			} else if (cptr->info->type != pvr2_ctl_bool) { | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			ret = cptr->info->set_value(cptr,mask,val); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ret = -EPERM; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while(0); LOCK_GIVE(cptr->hdw->big_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Get the current value of the given control. */ | 
					
						
							|  |  |  | int pvr2_ctrl_get_value(struct pvr2_ctrl *cptr,int *valptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 	if (!cptr) return -EINVAL; | 
					
						
							|  |  |  | 	LOCK_TAKE(cptr->hdw->big_lock); do { | 
					
						
							|  |  |  | 		ret = cptr->info->get_value(cptr,valptr); | 
					
						
							|  |  |  | 	} while(0); LOCK_GIVE(cptr->hdw->big_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Retrieve control's type */ | 
					
						
							|  |  |  | enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!cptr) return pvr2_ctl_int; | 
					
						
							|  |  |  | 	return cptr->info->type; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Retrieve control's maximum value (int type) */ | 
					
						
							|  |  |  | int pvr2_ctrl_get_max(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 	if (!cptr) return 0; | 
					
						
							|  |  |  | 	LOCK_TAKE(cptr->hdw->big_lock); do { | 
					
						
							| 
									
										
										
										
											2006-08-08 09:10:07 -03:00
										 |  |  | 		if (cptr->info->get_max_value) { | 
					
						
							|  |  |  | 			cptr->info->get_max_value(cptr,&ret); | 
					
						
							|  |  |  | 		} else if (cptr->info->type == pvr2_ctl_int) { | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 			ret = cptr->info->def.type_int.max_value; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while(0); LOCK_GIVE(cptr->hdw->big_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Retrieve control's minimum value (int type) */ | 
					
						
							|  |  |  | int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 	if (!cptr) return 0; | 
					
						
							|  |  |  | 	LOCK_TAKE(cptr->hdw->big_lock); do { | 
					
						
							| 
									
										
										
										
											2006-08-08 09:10:07 -03:00
										 |  |  | 		if (cptr->info->get_min_value) { | 
					
						
							|  |  |  | 			cptr->info->get_min_value(cptr,&ret); | 
					
						
							|  |  |  | 		} else if (cptr->info->type == pvr2_ctl_int) { | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 			ret = cptr->info->def.type_int.min_value; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while(0); LOCK_GIVE(cptr->hdw->big_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Retrieve control's default value (any type) */ | 
					
						
							| 
									
										
										
										
											2008-08-31 20:55:03 -03:00
										 |  |  | int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr, int *valptr) | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							| 
									
										
										
										
											2009-04-01 01:49:57 -03:00
										 |  |  | 	if (!cptr) return -EINVAL; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 	LOCK_TAKE(cptr->hdw->big_lock); do { | 
					
						
							| 
									
										
										
										
											2009-04-01 01:49:57 -03:00
										 |  |  | 		if (cptr->info->get_def_value) { | 
					
						
							|  |  |  | 			ret = cptr->info->get_def_value(cptr, valptr); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			*valptr = cptr->info->default_value; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} while(0); LOCK_GIVE(cptr->hdw->big_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Retrieve control's enumeration count (enum only) */ | 
					
						
							|  |  |  | int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 	if (!cptr) return 0; | 
					
						
							|  |  |  | 	LOCK_TAKE(cptr->hdw->big_lock); do { | 
					
						
							|  |  |  | 		if (cptr->info->type == pvr2_ctl_enum) { | 
					
						
							|  |  |  | 			ret = cptr->info->def.type_enum.count; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while(0); LOCK_GIVE(cptr->hdw->big_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Retrieve control's valid mask bits (bit mask only) */ | 
					
						
							|  |  |  | int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = 0; | 
					
						
							|  |  |  | 	if (!cptr) return 0; | 
					
						
							|  |  |  | 	LOCK_TAKE(cptr->hdw->big_lock); do { | 
					
						
							|  |  |  | 		if (cptr->info->type == pvr2_ctl_bitmask) { | 
					
						
							|  |  |  | 			ret = cptr->info->def.type_bitmask.valid_bits; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while(0); LOCK_GIVE(cptr->hdw->big_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Retrieve the control's name */ | 
					
						
							|  |  |  | const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-06-30 11:35:28 -03:00
										 |  |  | 	if (!cptr) return NULL; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 	return cptr->info->name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Retrieve the control's desc */ | 
					
						
							|  |  |  | const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2006-06-30 11:35:28 -03:00
										 |  |  | 	if (!cptr) return NULL; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 	return cptr->info->desc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Retrieve a control enumeration or bit mask value */ | 
					
						
							|  |  |  | int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val, | 
					
						
							|  |  |  | 			  char *bptr,unsigned int bmax, | 
					
						
							|  |  |  | 			  unsigned int *blen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -EINVAL; | 
					
						
							|  |  |  | 	if (!cptr) return 0; | 
					
						
							|  |  |  | 	*blen = 0; | 
					
						
							|  |  |  | 	LOCK_TAKE(cptr->hdw->big_lock); do { | 
					
						
							|  |  |  | 		if (cptr->info->type == pvr2_ctl_enum) { | 
					
						
							| 
									
										
										
										
											2010-12-29 14:25:52 -03:00
										 |  |  | 			const char * const *names; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 			names = cptr->info->def.type_enum.value_names; | 
					
						
							| 
									
										
										
										
											2008-04-22 14:45:38 -03:00
										 |  |  | 			if (pvr2_ctrl_range_check(cptr,val) == 0) { | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 				if (names[val]) { | 
					
						
							|  |  |  | 					*blen = scnprintf( | 
					
						
							|  |  |  | 						bptr,bmax,"%s", | 
					
						
							|  |  |  | 						names[val]); | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					*blen = 0; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				ret = 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else if (cptr->info->type == pvr2_ctl_bitmask) { | 
					
						
							|  |  |  | 			const char **names; | 
					
						
							|  |  |  | 			unsigned int idx; | 
					
						
							|  |  |  | 			int msk; | 
					
						
							|  |  |  | 			names = cptr->info->def.type_bitmask.bit_names; | 
					
						
							|  |  |  | 			val &= cptr->info->def.type_bitmask.valid_bits; | 
					
						
							|  |  |  | 			for (idx = 0, msk = 1; val; idx++, msk <<= 1) { | 
					
						
							|  |  |  | 				if (val & msk) { | 
					
						
							|  |  |  | 					*blen = scnprintf(bptr,bmax,"%s", | 
					
						
							|  |  |  | 							  names[idx]); | 
					
						
							|  |  |  | 					ret = 0; | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while(0); LOCK_GIVE(cptr->hdw->big_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 20:04:44 -03:00
										 |  |  | /* Return V4L ID for this control or zero if none */ | 
					
						
							|  |  |  | int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!cptr) return 0; | 
					
						
							|  |  |  | 	return cptr->info->v4l_id; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int flags = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cptr->info->get_v4lflags) { | 
					
						
							|  |  |  | 		flags = cptr->info->get_v4lflags(cptr); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 20:04:58 -03:00
										 |  |  | 	if (cptr->info->set_value) { | 
					
						
							|  |  |  | 		flags &= ~V4L2_CTRL_FLAG_READ_ONLY; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		flags |= V4L2_CTRL_FLAG_READ_ONLY; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-06-25 20:04:44 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return flags; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | /* Return true if control is writable */ | 
					
						
							|  |  |  | int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!cptr) return 0; | 
					
						
							| 
									
										
										
										
											2008-03-29 03:07:38 +00:00
										 |  |  | 	return cptr->info->set_value != NULL; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Return true if control has custom symbolic representation */ | 
					
						
							|  |  |  | int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!cptr) return 0; | 
					
						
							|  |  |  | 	if (!cptr->info->val_to_sym) return 0; | 
					
						
							|  |  |  | 	if (!cptr->info->sym_to_val) return 0; | 
					
						
							|  |  |  | 	return !0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Convert a given mask/val to a custom symbolic value */ | 
					
						
							|  |  |  | int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr, | 
					
						
							|  |  |  | 				  int mask,int val, | 
					
						
							|  |  |  | 				  char *buf,unsigned int maxlen, | 
					
						
							|  |  |  | 				  unsigned int *len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!cptr) return -EINVAL; | 
					
						
							|  |  |  | 	if (!cptr->info->val_to_sym) return -EINVAL; | 
					
						
							|  |  |  | 	return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Convert a symbolic value to a mask/value pair */ | 
					
						
							|  |  |  | int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr, | 
					
						
							|  |  |  | 				  const char *buf,unsigned int len, | 
					
						
							|  |  |  | 				  int *maskptr,int *valptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (!cptr) return -EINVAL; | 
					
						
							|  |  |  | 	if (!cptr->info->sym_to_val) return -EINVAL; | 
					
						
							|  |  |  | 	return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned int gen_bitmask_string(int msk,int val,int msk_only, | 
					
						
							|  |  |  | 				       const char **names, | 
					
						
							|  |  |  | 				       char *ptr,unsigned int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int idx; | 
					
						
							|  |  |  | 	long sm,um; | 
					
						
							|  |  |  | 	int spcFl; | 
					
						
							|  |  |  | 	unsigned int uc,cnt; | 
					
						
							|  |  |  | 	const char *idStr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spcFl = 0; | 
					
						
							|  |  |  | 	uc = 0; | 
					
						
							|  |  |  | 	um = 0; | 
					
						
							|  |  |  | 	for (idx = 0, sm = 1; msk; idx++, sm <<= 1) { | 
					
						
							|  |  |  | 		if (sm & msk) { | 
					
						
							|  |  |  | 			msk &= ~sm; | 
					
						
							|  |  |  | 			idStr = names[idx]; | 
					
						
							|  |  |  | 			if (idStr) { | 
					
						
							|  |  |  | 				cnt = scnprintf(ptr,len,"%s%s%s", | 
					
						
							|  |  |  | 						(spcFl ? " " : ""), | 
					
						
							|  |  |  | 						(msk_only ? "" : | 
					
						
							|  |  |  | 						 ((val & sm) ? "+" : "-")), | 
					
						
							|  |  |  | 						idStr); | 
					
						
							|  |  |  | 				ptr += cnt; len -= cnt; uc += cnt; | 
					
						
							|  |  |  | 				spcFl = !0; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				um |= sm; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (um) { | 
					
						
							|  |  |  | 		if (msk_only) { | 
					
						
							|  |  |  | 			cnt = scnprintf(ptr,len,"%s0x%lx", | 
					
						
							|  |  |  | 					(spcFl ? " " : ""), | 
					
						
							|  |  |  | 					um); | 
					
						
							|  |  |  | 			ptr += cnt; len -= cnt; uc += cnt; | 
					
						
							|  |  |  | 			spcFl = !0; | 
					
						
							|  |  |  | 		} else if (um & val) { | 
					
						
							|  |  |  | 			cnt = scnprintf(ptr,len,"%s+0x%lx", | 
					
						
							|  |  |  | 					(spcFl ? " " : ""), | 
					
						
							|  |  |  | 					um & val); | 
					
						
							|  |  |  | 			ptr += cnt; len -= cnt; uc += cnt; | 
					
						
							|  |  |  | 			spcFl = !0; | 
					
						
							|  |  |  | 		} else if (um & ~val) { | 
					
						
							|  |  |  | 			cnt = scnprintf(ptr,len,"%s+0x%lx", | 
					
						
							|  |  |  | 					(spcFl ? " " : ""), | 
					
						
							|  |  |  | 					um & ~val); | 
					
						
							|  |  |  | 			ptr += cnt; len -= cnt; uc += cnt; | 
					
						
							|  |  |  | 			spcFl = !0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return uc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-25 20:04:40 -03:00
										 |  |  | static const char *boolNames[] = { | 
					
						
							|  |  |  | 	"false", | 
					
						
							|  |  |  | 	"true", | 
					
						
							|  |  |  | 	"no", | 
					
						
							|  |  |  | 	"yes", | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | static int parse_token(const char *ptr,unsigned int len, | 
					
						
							|  |  |  | 		       int *valptr, | 
					
						
							| 
									
										
										
										
											2010-12-29 14:25:52 -03:00
										 |  |  | 		       const char * const *names, unsigned int namecnt) | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	char buf[33]; | 
					
						
							|  |  |  | 	unsigned int slen; | 
					
						
							|  |  |  | 	unsigned int idx; | 
					
						
							|  |  |  | 	int negfl; | 
					
						
							|  |  |  | 	char *p2; | 
					
						
							|  |  |  | 	*valptr = 0; | 
					
						
							|  |  |  | 	if (!names) namecnt = 0; | 
					
						
							|  |  |  | 	for (idx = 0; idx < namecnt; idx++) { | 
					
						
							|  |  |  | 		if (!names[idx]) continue; | 
					
						
							|  |  |  | 		slen = strlen(names[idx]); | 
					
						
							|  |  |  | 		if (slen != len) continue; | 
					
						
							|  |  |  | 		if (memcmp(names[idx],ptr,slen)) continue; | 
					
						
							|  |  |  | 		*valptr = idx; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	negfl = 0; | 
					
						
							|  |  |  | 	if ((*ptr == '-') || (*ptr == '+')) { | 
					
						
							|  |  |  | 		negfl = (*ptr == '-'); | 
					
						
							|  |  |  | 		ptr++; len--; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (len >= sizeof(buf)) return -EINVAL; | 
					
						
							|  |  |  | 	memcpy(buf,ptr,len); | 
					
						
							|  |  |  | 	buf[len] = 0; | 
					
						
							|  |  |  | 	*valptr = simple_strtol(buf,&p2,0); | 
					
						
							|  |  |  | 	if (negfl) *valptr = -(*valptr); | 
					
						
							|  |  |  | 	if (*p2) return -EINVAL; | 
					
						
							| 
									
										
										
										
											2006-06-25 20:04:40 -03:00
										 |  |  | 	return 1; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int parse_mtoken(const char *ptr,unsigned int len, | 
					
						
							|  |  |  | 			int *valptr, | 
					
						
							|  |  |  | 			const char **names,int valid_bits) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char buf[33]; | 
					
						
							|  |  |  | 	unsigned int slen; | 
					
						
							|  |  |  | 	unsigned int idx; | 
					
						
							|  |  |  | 	char *p2; | 
					
						
							|  |  |  | 	int msk; | 
					
						
							|  |  |  | 	*valptr = 0; | 
					
						
							|  |  |  | 	for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) { | 
					
						
							| 
									
										
										
										
											2007-10-28 22:15:33 -03:00
										 |  |  | 		if (!(msk & valid_bits)) continue; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 		valid_bits &= ~msk; | 
					
						
							|  |  |  | 		if (!names[idx]) continue; | 
					
						
							|  |  |  | 		slen = strlen(names[idx]); | 
					
						
							|  |  |  | 		if (slen != len) continue; | 
					
						
							|  |  |  | 		if (memcmp(names[idx],ptr,slen)) continue; | 
					
						
							|  |  |  | 		*valptr = msk; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (len >= sizeof(buf)) return -EINVAL; | 
					
						
							|  |  |  | 	memcpy(buf,ptr,len); | 
					
						
							|  |  |  | 	buf[len] = 0; | 
					
						
							|  |  |  | 	*valptr = simple_strtol(buf,&p2,0); | 
					
						
							|  |  |  | 	if (*p2) return -EINVAL; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int parse_tlist(const char *ptr,unsigned int len, | 
					
						
							|  |  |  | 		       int *maskptr,int *valptr, | 
					
						
							|  |  |  | 		       const char **names,int valid_bits) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int cnt; | 
					
						
							|  |  |  | 	int mask,val,kv,mode,ret; | 
					
						
							|  |  |  | 	mask = 0; | 
					
						
							|  |  |  | 	val = 0; | 
					
						
							|  |  |  | 	ret = 0; | 
					
						
							|  |  |  | 	while (len) { | 
					
						
							|  |  |  | 		cnt = 0; | 
					
						
							|  |  |  | 		while ((cnt < len) && | 
					
						
							|  |  |  | 		       ((ptr[cnt] <= 32) || | 
					
						
							|  |  |  | 			(ptr[cnt] >= 127))) cnt++; | 
					
						
							|  |  |  | 		ptr += cnt; | 
					
						
							|  |  |  | 		len -= cnt; | 
					
						
							|  |  |  | 		mode = 0; | 
					
						
							|  |  |  | 		if ((*ptr == '-') || (*ptr == '+')) { | 
					
						
							|  |  |  | 			mode = (*ptr == '-') ? -1 : 1; | 
					
						
							|  |  |  | 			ptr++; | 
					
						
							|  |  |  | 			len--; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		cnt = 0; | 
					
						
							|  |  |  | 		while (cnt < len) { | 
					
						
							|  |  |  | 			if (ptr[cnt] <= 32) break; | 
					
						
							|  |  |  | 			if (ptr[cnt] >= 127) break; | 
					
						
							|  |  |  | 			cnt++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (!cnt) break; | 
					
						
							|  |  |  | 		if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) { | 
					
						
							|  |  |  | 			ret = -EINVAL; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ptr += cnt; | 
					
						
							|  |  |  | 		len -= cnt; | 
					
						
							|  |  |  | 		switch (mode) { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							|  |  |  | 			mask = valid_bits; | 
					
						
							|  |  |  | 			val |= kv; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case -1: | 
					
						
							|  |  |  | 			mask |= kv; | 
					
						
							|  |  |  | 			val &= ~kv; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 1: | 
					
						
							|  |  |  | 			mask |= kv; | 
					
						
							|  |  |  | 			val |= kv; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	*maskptr = mask; | 
					
						
							|  |  |  | 	*valptr = val; | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Convert a symbolic value to a mask/value pair */ | 
					
						
							|  |  |  | int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr, | 
					
						
							|  |  |  | 			   const char *ptr,unsigned int len, | 
					
						
							|  |  |  | 			   int *maskptr,int *valptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -EINVAL; | 
					
						
							|  |  |  | 	unsigned int cnt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*maskptr = 0; | 
					
						
							|  |  |  | 	*valptr = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cnt = 0; | 
					
						
							|  |  |  | 	while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++; | 
					
						
							|  |  |  | 	len -= cnt; ptr += cnt; | 
					
						
							|  |  |  | 	cnt = 0; | 
					
						
							|  |  |  | 	while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) || | 
					
						
							|  |  |  | 			       (ptr[len-(cnt+1)] >= 127))) cnt++; | 
					
						
							|  |  |  | 	len -= cnt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!len) return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	LOCK_TAKE(cptr->hdw->big_lock); do { | 
					
						
							|  |  |  | 		if (cptr->info->type == pvr2_ctl_int) { | 
					
						
							| 
									
										
										
										
											2006-06-30 11:35:28 -03:00
										 |  |  | 			ret = parse_token(ptr,len,valptr,NULL,0); | 
					
						
							| 
									
										
										
										
											2006-12-27 23:06:54 -03:00
										 |  |  | 			if (ret >= 0) { | 
					
						
							| 
									
										
										
										
											2006-12-27 23:28:54 -03:00
										 |  |  | 				ret = pvr2_ctrl_range_check(cptr,*valptr); | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-08-19 06:50:04 -03:00
										 |  |  | 			*maskptr = ~0; | 
					
						
							| 
									
										
										
										
											2006-06-25 20:04:40 -03:00
										 |  |  | 		} else if (cptr->info->type == pvr2_ctl_bool) { | 
					
						
							| 
									
										
										
										
											2007-01-20 00:39:17 -03:00
										 |  |  | 			ret = parse_token(ptr,len,valptr,boolNames, | 
					
						
							|  |  |  | 					  ARRAY_SIZE(boolNames)); | 
					
						
							| 
									
										
										
										
											2006-06-25 20:04:40 -03:00
										 |  |  | 			if (ret == 1) { | 
					
						
							|  |  |  | 				*valptr = *valptr ? !0 : 0; | 
					
						
							|  |  |  | 			} else if (ret == 0) { | 
					
						
							|  |  |  | 				*valptr = (*valptr & 1) ? !0 : 0; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-08-19 06:50:04 -03:00
										 |  |  | 			*maskptr = 1; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 		} else if (cptr->info->type == pvr2_ctl_enum) { | 
					
						
							|  |  |  | 			ret = parse_token( | 
					
						
							|  |  |  | 				ptr,len,valptr, | 
					
						
							|  |  |  | 				cptr->info->def.type_enum.value_names, | 
					
						
							|  |  |  | 				cptr->info->def.type_enum.count); | 
					
						
							| 
									
										
										
										
											2008-04-22 14:45:38 -03:00
										 |  |  | 			if (ret >= 0) { | 
					
						
							|  |  |  | 				ret = pvr2_ctrl_range_check(cptr,*valptr); | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-08-19 06:50:04 -03:00
										 |  |  | 			*maskptr = ~0; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 		} else if (cptr->info->type == pvr2_ctl_bitmask) { | 
					
						
							|  |  |  | 			ret = parse_tlist( | 
					
						
							|  |  |  | 				ptr,len,maskptr,valptr, | 
					
						
							|  |  |  | 				cptr->info->def.type_bitmask.bit_names, | 
					
						
							|  |  |  | 				cptr->info->def.type_bitmask.valid_bits); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while(0); LOCK_GIVE(cptr->hdw->big_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Convert a given mask/val to a symbolic value */ | 
					
						
							|  |  |  | int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr, | 
					
						
							|  |  |  | 				    int mask,int val, | 
					
						
							|  |  |  | 				    char *buf,unsigned int maxlen, | 
					
						
							|  |  |  | 				    unsigned int *len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret = -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*len = 0; | 
					
						
							|  |  |  | 	if (cptr->info->type == pvr2_ctl_int) { | 
					
						
							|  |  |  | 		*len = scnprintf(buf,maxlen,"%d",val); | 
					
						
							|  |  |  | 		ret = 0; | 
					
						
							| 
									
										
										
										
											2006-06-25 20:04:40 -03:00
										 |  |  | 	} else if (cptr->info->type == pvr2_ctl_bool) { | 
					
						
							|  |  |  | 		*len = scnprintf(buf,maxlen,"%s",val ? "true" : "false"); | 
					
						
							|  |  |  | 		ret = 0; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 	} else if (cptr->info->type == pvr2_ctl_enum) { | 
					
						
							| 
									
										
										
										
											2010-12-29 14:25:52 -03:00
										 |  |  | 		const char * const *names; | 
					
						
							| 
									
										
										
										
											2006-06-26 20:58:46 -03:00
										 |  |  | 		names = cptr->info->def.type_enum.value_names; | 
					
						
							|  |  |  | 		if ((val >= 0) && | 
					
						
							|  |  |  | 		    (val < cptr->info->def.type_enum.count)) { | 
					
						
							|  |  |  | 			if (names[val]) { | 
					
						
							|  |  |  | 				*len = scnprintf( | 
					
						
							|  |  |  | 					buf,maxlen,"%s", | 
					
						
							|  |  |  | 					names[val]); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				*len = 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			ret = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if (cptr->info->type == pvr2_ctl_bitmask) { | 
					
						
							|  |  |  | 		*len = gen_bitmask_string( | 
					
						
							|  |  |  | 			val & mask & cptr->info->def.type_bitmask.valid_bits, | 
					
						
							|  |  |  | 			~0,!0, | 
					
						
							|  |  |  | 			cptr->info->def.type_bitmask.bit_names, | 
					
						
							|  |  |  | 			buf,maxlen); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Convert a given mask/val to a symbolic value */ | 
					
						
							|  |  |  | int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr, | 
					
						
							|  |  |  | 			   int mask,int val, | 
					
						
							|  |  |  | 			   char *buf,unsigned int maxlen, | 
					
						
							|  |  |  | 			   unsigned int *len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 	LOCK_TAKE(cptr->hdw->big_lock); do { | 
					
						
							|  |  |  | 		ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val, | 
					
						
							|  |  |  | 						      buf,maxlen,len); | 
					
						
							|  |  |  | 	} while(0); LOCK_GIVE(cptr->hdw->big_lock); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |   Stuff for Emacs to see, in order to encourage consistent editing style: | 
					
						
							|  |  |  |   *** Local Variables: *** | 
					
						
							|  |  |  |   *** mode: c *** | 
					
						
							|  |  |  |   *** fill-column: 75 *** | 
					
						
							|  |  |  |   *** tab-width: 8 *** | 
					
						
							|  |  |  |   *** c-basic-offset: 8 *** | 
					
						
							|  |  |  |   *** End: *** | 
					
						
							|  |  |  |   */ |