| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * V4L2 controls framework core implementation.
- *
- * Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl>
- */
- #include <linux/export.h>
- #include <linux/mm.h>
- #include <linux/slab.h>
- #include <media/v4l2-ctrls.h>
- #include <media/v4l2-event.h>
- #include <media/v4l2-fwnode.h>
- #include "v4l2-ctrls-priv.h"
- static const union v4l2_ctrl_ptr ptr_null;
- static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl,
- u32 changes)
- {
- memset(ev, 0, sizeof(*ev));
- ev->type = V4L2_EVENT_CTRL;
- ev->id = ctrl->id;
- ev->u.ctrl.changes = changes;
- ev->u.ctrl.type = ctrl->type;
- ev->u.ctrl.flags = user_flags(ctrl);
- if (ctrl->is_ptr)
- ev->u.ctrl.value64 = 0;
- else
- ev->u.ctrl.value64 = *ctrl->p_cur.p_s64;
- ev->u.ctrl.minimum = ctrl->minimum;
- ev->u.ctrl.maximum = ctrl->maximum;
- if (ctrl->type == V4L2_CTRL_TYPE_MENU
- || ctrl->type == V4L2_CTRL_TYPE_INTEGER_MENU)
- ev->u.ctrl.step = 1;
- else
- ev->u.ctrl.step = ctrl->step;
- ev->u.ctrl.default_value = ctrl->default_value;
- }
- void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl)
- {
- struct v4l2_event ev;
- u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
- if (!(ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY))
- changes |= V4L2_EVENT_CTRL_CH_VALUE;
- fill_event(&ev, ctrl, changes);
- v4l2_event_queue_fh(fh, &ev);
- }
- void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
- {
- struct v4l2_event ev;
- struct v4l2_subscribed_event *sev;
- if (list_empty(&ctrl->ev_subs))
- return;
- fill_event(&ev, ctrl, changes);
- list_for_each_entry(sev, &ctrl->ev_subs, node)
- if (sev->fh != fh ||
- (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK))
- v4l2_event_queue_fh(sev->fh, &ev);
- }
- bool v4l2_ctrl_type_op_equal(const struct v4l2_ctrl *ctrl,
- union v4l2_ctrl_ptr ptr1, union v4l2_ctrl_ptr ptr2)
- {
- unsigned int i;
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_BUTTON:
- return false;
- case V4L2_CTRL_TYPE_STRING:
- for (i = 0; i < ctrl->elems; i++) {
- unsigned int idx = i * ctrl->elem_size;
- /* strings are always 0-terminated */
- if (strcmp(ptr1.p_char + idx, ptr2.p_char + idx))
- return false;
- }
- return true;
- default:
- return !memcmp(ptr1.p_const, ptr2.p_const,
- ctrl->elems * ctrl->elem_size);
- }
- }
- EXPORT_SYMBOL(v4l2_ctrl_type_op_equal);
- /* Default intra MPEG-2 quantisation coefficients, from the specification. */
- static const u8 mpeg2_intra_quant_matrix[64] = {
- 8, 16, 16, 19, 16, 19, 22, 22,
- 22, 22, 22, 22, 26, 24, 26, 27,
- 27, 27, 26, 26, 26, 26, 27, 27,
- 27, 29, 29, 29, 34, 34, 34, 29,
- 29, 29, 27, 27, 29, 29, 32, 32,
- 34, 34, 37, 38, 37, 35, 35, 34,
- 35, 38, 38, 40, 40, 40, 48, 48,
- 46, 46, 56, 56, 58, 69, 69, 83
- };
- static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx,
- union v4l2_ctrl_ptr ptr)
- {
- struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence;
- struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture;
- struct v4l2_ctrl_mpeg2_quantisation *p_mpeg2_quant;
- struct v4l2_ctrl_vp8_frame *p_vp8_frame;
- struct v4l2_ctrl_vp9_frame *p_vp9_frame;
- struct v4l2_ctrl_fwht_params *p_fwht_params;
- struct v4l2_ctrl_h264_scaling_matrix *p_h264_scaling_matrix;
- struct v4l2_ctrl_av1_sequence *p_av1_sequence;
- void *p = ptr.p + idx * ctrl->elem_size;
- if (ctrl->p_def.p_const)
- memcpy(p, ctrl->p_def.p_const, ctrl->elem_size);
- else
- memset(p, 0, ctrl->elem_size);
- switch ((u32)ctrl->type) {
- case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
- p_mpeg2_sequence = p;
- /* 4:2:0 */
- p_mpeg2_sequence->chroma_format = 1;
- break;
- case V4L2_CTRL_TYPE_MPEG2_PICTURE:
- p_mpeg2_picture = p;
- /* interlaced top field */
- p_mpeg2_picture->picture_structure = V4L2_MPEG2_PIC_TOP_FIELD;
- p_mpeg2_picture->picture_coding_type =
- V4L2_MPEG2_PIC_CODING_TYPE_I;
- break;
- case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
- p_mpeg2_quant = p;
- memcpy(p_mpeg2_quant->intra_quantiser_matrix,
- mpeg2_intra_quant_matrix,
- ARRAY_SIZE(mpeg2_intra_quant_matrix));
- /*
- * The default non-intra MPEG-2 quantisation
- * coefficients are all 16, as per the specification.
- */
- memset(p_mpeg2_quant->non_intra_quantiser_matrix, 16,
- sizeof(p_mpeg2_quant->non_intra_quantiser_matrix));
- break;
- case V4L2_CTRL_TYPE_VP8_FRAME:
- p_vp8_frame = p;
- p_vp8_frame->num_dct_parts = 1;
- break;
- case V4L2_CTRL_TYPE_VP9_FRAME:
- p_vp9_frame = p;
- p_vp9_frame->profile = 0;
- p_vp9_frame->bit_depth = 8;
- p_vp9_frame->flags |= V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING |
- V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING;
- break;
- case V4L2_CTRL_TYPE_AV1_SEQUENCE:
- p_av1_sequence = p;
- p_av1_sequence->bit_depth = 8;
- break;
- case V4L2_CTRL_TYPE_FWHT_PARAMS:
- p_fwht_params = p;
- p_fwht_params->version = V4L2_FWHT_VERSION;
- p_fwht_params->width = 1280;
- p_fwht_params->height = 720;
- p_fwht_params->flags = V4L2_FWHT_FL_PIXENC_YUV |
- (2 << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET);
- break;
- case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
- p_h264_scaling_matrix = p;
- /*
- * The default (flat) H.264 scaling matrix when none are
- * specified in the bitstream, this is according to formulas
- * (7-8) and (7-9) of the specification.
- */
- memset(p_h264_scaling_matrix, 16, sizeof(*p_h264_scaling_matrix));
- break;
- }
- }
- void v4l2_ctrl_type_op_init(const struct v4l2_ctrl *ctrl, u32 from_idx,
- union v4l2_ctrl_ptr ptr)
- {
- unsigned int i;
- u32 tot_elems = ctrl->elems;
- u32 elems = tot_elems - from_idx;
- if (from_idx >= tot_elems)
- return;
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_STRING:
- for (i = from_idx; i < tot_elems; i++) {
- unsigned int offset = i * ctrl->elem_size;
- memset(ptr.p_char + offset, ' ', ctrl->minimum);
- ptr.p_char[offset + ctrl->minimum] = '\0';
- }
- break;
- case V4L2_CTRL_TYPE_INTEGER64:
- if (ctrl->default_value) {
- for (i = from_idx; i < tot_elems; i++)
- ptr.p_s64[i] = ctrl->default_value;
- } else {
- memset(ptr.p_s64 + from_idx, 0, elems * sizeof(s64));
- }
- break;
- case V4L2_CTRL_TYPE_INTEGER:
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_BITMASK:
- case V4L2_CTRL_TYPE_BOOLEAN:
- if (ctrl->default_value) {
- for (i = from_idx; i < tot_elems; i++)
- ptr.p_s32[i] = ctrl->default_value;
- } else {
- memset(ptr.p_s32 + from_idx, 0, elems * sizeof(s32));
- }
- break;
- case V4L2_CTRL_TYPE_BUTTON:
- case V4L2_CTRL_TYPE_CTRL_CLASS:
- memset(ptr.p_s32 + from_idx, 0, elems * sizeof(s32));
- break;
- case V4L2_CTRL_TYPE_U8:
- memset(ptr.p_u8 + from_idx, ctrl->default_value, elems);
- break;
- case V4L2_CTRL_TYPE_U16:
- if (ctrl->default_value) {
- for (i = from_idx; i < tot_elems; i++)
- ptr.p_u16[i] = ctrl->default_value;
- } else {
- memset(ptr.p_u16 + from_idx, 0, elems * sizeof(u16));
- }
- break;
- case V4L2_CTRL_TYPE_U32:
- if (ctrl->default_value) {
- for (i = from_idx; i < tot_elems; i++)
- ptr.p_u32[i] = ctrl->default_value;
- } else {
- memset(ptr.p_u32 + from_idx, 0, elems * sizeof(u32));
- }
- break;
- default:
- for (i = from_idx; i < tot_elems; i++)
- std_init_compound(ctrl, i, ptr);
- break;
- }
- }
- EXPORT_SYMBOL(v4l2_ctrl_type_op_init);
- void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)
- {
- union v4l2_ctrl_ptr ptr = ctrl->p_cur;
- if (ctrl->is_array) {
- unsigned i;
- for (i = 0; i < ctrl->nr_of_dims; i++)
- pr_cont("[%u]", ctrl->dims[i]);
- pr_cont(" ");
- }
- switch (ctrl->type) {
- case V4L2_CTRL_TYPE_INTEGER:
- pr_cont("%d", *ptr.p_s32);
- break;
- case V4L2_CTRL_TYPE_BOOLEAN:
- pr_cont("%s", *ptr.p_s32 ? "true" : "false");
- break;
- case V4L2_CTRL_TYPE_MENU:
- pr_cont("%s", ctrl->qmenu[*ptr.p_s32]);
- break;
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- pr_cont("%lld", ctrl->qmenu_int[*ptr.p_s32]);
- break;
- case V4L2_CTRL_TYPE_BITMASK:
- pr_cont("0x%08x", *ptr.p_s32);
- break;
- case V4L2_CTRL_TYPE_INTEGER64:
- pr_cont("%lld", *ptr.p_s64);
- break;
- case V4L2_CTRL_TYPE_STRING:
- pr_cont("%s", ptr.p_char);
- break;
- case V4L2_CTRL_TYPE_U8:
- pr_cont("%u", (unsigned)*ptr.p_u8);
- break;
- case V4L2_CTRL_TYPE_U16:
- pr_cont("%u", (unsigned)*ptr.p_u16);
- break;
- case V4L2_CTRL_TYPE_U32:
- pr_cont("%u", (unsigned)*ptr.p_u32);
- break;
- case V4L2_CTRL_TYPE_AREA:
- pr_cont("%ux%u", ptr.p_area->width, ptr.p_area->height);
- break;
- case V4L2_CTRL_TYPE_H264_SPS:
- pr_cont("H264_SPS");
- break;
- case V4L2_CTRL_TYPE_H264_PPS:
- pr_cont("H264_PPS");
- break;
- case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
- pr_cont("H264_SCALING_MATRIX");
- break;
- case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
- pr_cont("H264_SLICE_PARAMS");
- break;
- case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
- pr_cont("H264_DECODE_PARAMS");
- break;
- case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
- pr_cont("H264_PRED_WEIGHTS");
- break;
- case V4L2_CTRL_TYPE_FWHT_PARAMS:
- pr_cont("FWHT_PARAMS");
- break;
- case V4L2_CTRL_TYPE_VP8_FRAME:
- pr_cont("VP8_FRAME");
- break;
- case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
- pr_cont("HDR10_CLL_INFO");
- break;
- case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
- pr_cont("HDR10_MASTERING_DISPLAY");
- break;
- case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
- pr_cont("MPEG2_QUANTISATION");
- break;
- case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
- pr_cont("MPEG2_SEQUENCE");
- break;
- case V4L2_CTRL_TYPE_MPEG2_PICTURE:
- pr_cont("MPEG2_PICTURE");
- break;
- case V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR:
- pr_cont("VP9_COMPRESSED_HDR");
- break;
- case V4L2_CTRL_TYPE_VP9_FRAME:
- pr_cont("VP9_FRAME");
- break;
- case V4L2_CTRL_TYPE_HEVC_SPS:
- pr_cont("HEVC_SPS");
- break;
- case V4L2_CTRL_TYPE_HEVC_PPS:
- pr_cont("HEVC_PPS");
- break;
- case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
- pr_cont("HEVC_SLICE_PARAMS");
- break;
- case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
- pr_cont("HEVC_SCALING_MATRIX");
- break;
- case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS:
- pr_cont("HEVC_DECODE_PARAMS");
- break;
- case V4L2_CTRL_TYPE_AV1_SEQUENCE:
- pr_cont("AV1_SEQUENCE");
- break;
- case V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY:
- pr_cont("AV1_TILE_GROUP_ENTRY");
- break;
- case V4L2_CTRL_TYPE_AV1_FRAME:
- pr_cont("AV1_FRAME");
- break;
- case V4L2_CTRL_TYPE_AV1_FILM_GRAIN:
- pr_cont("AV1_FILM_GRAIN");
- break;
- default:
- pr_cont("unknown type %d", ctrl->type);
- break;
- }
- }
- EXPORT_SYMBOL(v4l2_ctrl_type_op_log);
- /*
- * Round towards the closest legal value. Be careful when we are
- * close to the maximum range of the control type to prevent
- * wrap-arounds.
- */
- #define ROUND_TO_RANGE(val, offset_type, ctrl) \
- ({ \
- offset_type offset; \
- if ((ctrl)->maximum >= 0 && \
- val >= (ctrl)->maximum - (s32)((ctrl)->step / 2)) \
- val = (ctrl)->maximum; \
- else \
- val += (s32)((ctrl)->step / 2); \
- val = clamp_t(typeof(val), val, \
- (ctrl)->minimum, (ctrl)->maximum); \
- offset = (val) - (ctrl)->minimum; \
- offset = (ctrl)->step * (offset / (u32)(ctrl)->step); \
- val = (ctrl)->minimum + offset; \
- 0; \
- })
- /* Validate a new control */
- #define zero_padding(s) \
- memset(&(s).padding, 0, sizeof((s).padding))
- #define zero_reserved(s) \
- memset(&(s).reserved, 0, sizeof((s).reserved))
- static int
- validate_vp9_lf_params(struct v4l2_vp9_loop_filter *lf)
- {
- unsigned int i;
- if (lf->flags & ~(V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED |
- V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE))
- return -EINVAL;
- /* That all values are in the accepted range. */
- if (lf->level > GENMASK(5, 0))
- return -EINVAL;
- if (lf->sharpness > GENMASK(2, 0))
- return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++)
- if (lf->ref_deltas[i] < -63 || lf->ref_deltas[i] > 63)
- return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++)
- if (lf->mode_deltas[i] < -63 || lf->mode_deltas[i] > 63)
- return -EINVAL;
- zero_reserved(*lf);
- return 0;
- }
- static int
- validate_vp9_quant_params(struct v4l2_vp9_quantization *quant)
- {
- if (quant->delta_q_y_dc < -15 || quant->delta_q_y_dc > 15 ||
- quant->delta_q_uv_dc < -15 || quant->delta_q_uv_dc > 15 ||
- quant->delta_q_uv_ac < -15 || quant->delta_q_uv_ac > 15)
- return -EINVAL;
- zero_reserved(*quant);
- return 0;
- }
- static int
- validate_vp9_seg_params(struct v4l2_vp9_segmentation *seg)
- {
- unsigned int i, j;
- if (seg->flags & ~(V4L2_VP9_SEGMENTATION_FLAG_ENABLED |
- V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP |
- V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE |
- V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA |
- V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE))
- return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(seg->feature_enabled); i++) {
- if (seg->feature_enabled[i] &
- ~V4L2_VP9_SEGMENT_FEATURE_ENABLED_MASK)
- return -EINVAL;
- }
- for (i = 0; i < ARRAY_SIZE(seg->feature_data); i++) {
- static const int range[] = { 255, 63, 3, 0 };
- for (j = 0; j < ARRAY_SIZE(seg->feature_data[j]); j++) {
- if (seg->feature_data[i][j] < -range[j] ||
- seg->feature_data[i][j] > range[j])
- return -EINVAL;
- }
- }
- zero_reserved(*seg);
- return 0;
- }
- static int
- validate_vp9_compressed_hdr(struct v4l2_ctrl_vp9_compressed_hdr *hdr)
- {
- if (hdr->tx_mode > V4L2_VP9_TX_MODE_SELECT)
- return -EINVAL;
- return 0;
- }
- static int
- validate_vp9_frame(struct v4l2_ctrl_vp9_frame *frame)
- {
- int ret;
- /* Make sure we're not passed invalid flags. */
- if (frame->flags & ~(V4L2_VP9_FRAME_FLAG_KEY_FRAME |
- V4L2_VP9_FRAME_FLAG_SHOW_FRAME |
- V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT |
- V4L2_VP9_FRAME_FLAG_INTRA_ONLY |
- V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV |
- V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX |
- V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE |
- V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING |
- V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING |
- V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING))
- return -EINVAL;
- if (frame->flags & V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT &&
- frame->flags & V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX)
- return -EINVAL;
- if (frame->profile > V4L2_VP9_PROFILE_MAX)
- return -EINVAL;
- if (frame->reset_frame_context > V4L2_VP9_RESET_FRAME_CTX_ALL)
- return -EINVAL;
- if (frame->frame_context_idx >= V4L2_VP9_NUM_FRAME_CTX)
- return -EINVAL;
- /*
- * Profiles 0 and 1 only support 8-bit depth, profiles 2 and 3 only 10
- * and 12 bit depths.
- */
- if ((frame->profile < 2 && frame->bit_depth != 8) ||
- (frame->profile >= 2 &&
- (frame->bit_depth != 10 && frame->bit_depth != 12)))
- return -EINVAL;
- /* Profile 0 and 2 only accept YUV 4:2:0. */
- if ((frame->profile == 0 || frame->profile == 2) &&
- (!(frame->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) ||
- !(frame->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING)))
- return -EINVAL;
- /* Profile 1 and 3 only accept YUV 4:2:2, 4:4:0 and 4:4:4. */
- if ((frame->profile == 1 || frame->profile == 3) &&
- ((frame->flags & V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING) &&
- (frame->flags & V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING)))
- return -EINVAL;
- if (frame->interpolation_filter > V4L2_VP9_INTERP_FILTER_SWITCHABLE)
- return -EINVAL;
- /*
- * According to the spec, tile_cols_log2 shall be less than or equal
- * to 6.
- */
- if (frame->tile_cols_log2 > 6)
- return -EINVAL;
- if (frame->reference_mode > V4L2_VP9_REFERENCE_MODE_SELECT)
- return -EINVAL;
- ret = validate_vp9_lf_params(&frame->lf);
- if (ret)
- return ret;
- ret = validate_vp9_quant_params(&frame->quant);
- if (ret)
- return ret;
- ret = validate_vp9_seg_params(&frame->seg);
- if (ret)
- return ret;
- zero_reserved(*frame);
- return 0;
- }
- static int validate_av1_quantization(struct v4l2_av1_quantization *q)
- {
- if (q->flags > GENMASK(2, 0))
- return -EINVAL;
- if (q->delta_q_y_dc < -64 || q->delta_q_y_dc > 63 ||
- q->delta_q_u_dc < -64 || q->delta_q_u_dc > 63 ||
- q->delta_q_v_dc < -64 || q->delta_q_v_dc > 63 ||
- q->delta_q_u_ac < -64 || q->delta_q_u_ac > 63 ||
- q->delta_q_v_ac < -64 || q->delta_q_v_ac > 63 ||
- q->delta_q_res > GENMASK(1, 0))
- return -EINVAL;
- if (q->qm_y > GENMASK(3, 0) ||
- q->qm_u > GENMASK(3, 0) ||
- q->qm_v > GENMASK(3, 0))
- return -EINVAL;
- return 0;
- }
- static int validate_av1_segmentation(struct v4l2_av1_segmentation *s)
- {
- u32 i;
- u32 j;
- if (s->flags > GENMASK(4, 0))
- return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(s->feature_data); i++) {
- static const int segmentation_feature_signed[] = { 1, 1, 1, 1, 1, 0, 0, 0 };
- static const int segmentation_feature_max[] = { 255, 63, 63, 63, 63, 7, 0, 0};
- for (j = 0; j < ARRAY_SIZE(s->feature_data[j]); j++) {
- s32 limit = segmentation_feature_max[j];
- if (segmentation_feature_signed[j]) {
- if (s->feature_data[i][j] < -limit ||
- s->feature_data[i][j] > limit)
- return -EINVAL;
- } else {
- if (s->feature_data[i][j] < 0 || s->feature_data[i][j] > limit)
- return -EINVAL;
- }
- }
- }
- return 0;
- }
- static int validate_av1_loop_filter(struct v4l2_av1_loop_filter *lf)
- {
- u32 i;
- if (lf->flags > GENMASK(3, 0))
- return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(lf->level); i++) {
- if (lf->level[i] > GENMASK(5, 0))
- return -EINVAL;
- }
- if (lf->sharpness > GENMASK(2, 0))
- return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(lf->ref_deltas); i++) {
- if (lf->ref_deltas[i] < -64 || lf->ref_deltas[i] > 63)
- return -EINVAL;
- }
- for (i = 0; i < ARRAY_SIZE(lf->mode_deltas); i++) {
- if (lf->mode_deltas[i] < -64 || lf->mode_deltas[i] > 63)
- return -EINVAL;
- }
- return 0;
- }
- static int validate_av1_cdef(struct v4l2_av1_cdef *cdef)
- {
- u32 i;
- if (cdef->damping_minus_3 > GENMASK(1, 0) ||
- cdef->bits > GENMASK(1, 0))
- return -EINVAL;
- for (i = 0; i < 1 << cdef->bits; i++) {
- if (cdef->y_pri_strength[i] > GENMASK(3, 0) ||
- cdef->y_sec_strength[i] > 4 ||
- cdef->uv_pri_strength[i] > GENMASK(3, 0) ||
- cdef->uv_sec_strength[i] > 4)
- return -EINVAL;
- }
- return 0;
- }
- static int validate_av1_loop_restauration(struct v4l2_av1_loop_restoration *lr)
- {
- if (lr->lr_unit_shift > 3 || lr->lr_uv_shift > 1)
- return -EINVAL;
- return 0;
- }
- static int validate_av1_film_grain(struct v4l2_ctrl_av1_film_grain *fg)
- {
- u32 i;
- if (fg->flags > GENMASK(4, 0))
- return -EINVAL;
- if (fg->film_grain_params_ref_idx > GENMASK(2, 0) ||
- fg->num_y_points > 14 ||
- fg->num_cb_points > 10 ||
- fg->num_cr_points > GENMASK(3, 0) ||
- fg->grain_scaling_minus_8 > GENMASK(1, 0) ||
- fg->ar_coeff_lag > GENMASK(1, 0) ||
- fg->ar_coeff_shift_minus_6 > GENMASK(1, 0) ||
- fg->grain_scale_shift > GENMASK(1, 0))
- return -EINVAL;
- if (!(fg->flags & V4L2_AV1_FILM_GRAIN_FLAG_APPLY_GRAIN))
- return 0;
- for (i = 1; i < fg->num_y_points; i++)
- if (fg->point_y_value[i] <= fg->point_y_value[i - 1])
- return -EINVAL;
- for (i = 1; i < fg->num_cb_points; i++)
- if (fg->point_cb_value[i] <= fg->point_cb_value[i - 1])
- return -EINVAL;
- for (i = 1; i < fg->num_cr_points; i++)
- if (fg->point_cr_value[i] <= fg->point_cr_value[i - 1])
- return -EINVAL;
- return 0;
- }
- static int validate_av1_frame(struct v4l2_ctrl_av1_frame *f)
- {
- int ret = 0;
- ret = validate_av1_quantization(&f->quantization);
- if (ret)
- return ret;
- ret = validate_av1_segmentation(&f->segmentation);
- if (ret)
- return ret;
- ret = validate_av1_loop_filter(&f->loop_filter);
- if (ret)
- return ret;
- ret = validate_av1_cdef(&f->cdef);
- if (ret)
- return ret;
- ret = validate_av1_loop_restauration(&f->loop_restoration);
- if (ret)
- return ret;
- if (f->flags &
- ~(V4L2_AV1_FRAME_FLAG_SHOW_FRAME |
- V4L2_AV1_FRAME_FLAG_SHOWABLE_FRAME |
- V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE |
- V4L2_AV1_FRAME_FLAG_DISABLE_CDF_UPDATE |
- V4L2_AV1_FRAME_FLAG_ALLOW_SCREEN_CONTENT_TOOLS |
- V4L2_AV1_FRAME_FLAG_FORCE_INTEGER_MV |
- V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC |
- V4L2_AV1_FRAME_FLAG_USE_SUPERRES |
- V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV |
- V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE |
- V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS |
- V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF |
- V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION |
- V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT |
- V4L2_AV1_FRAME_FLAG_REDUCED_TX_SET |
- V4L2_AV1_FRAME_FLAG_SKIP_MODE_ALLOWED |
- V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT |
- V4L2_AV1_FRAME_FLAG_FRAME_SIZE_OVERRIDE |
- V4L2_AV1_FRAME_FLAG_BUFFER_REMOVAL_TIME_PRESENT |
- V4L2_AV1_FRAME_FLAG_FRAME_REFS_SHORT_SIGNALING))
- return -EINVAL;
- if (f->superres_denom > GENMASK(2, 0) + 9)
- return -EINVAL;
- return 0;
- }
- static int validate_av1_sequence(struct v4l2_ctrl_av1_sequence *s)
- {
- if (s->flags &
- ~(V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE |
- V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_WARPED_MOTION |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_SUPERRES |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF |
- V4L2_AV1_SEQUENCE_FLAG_ENABLE_RESTORATION |
- V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME |
- V4L2_AV1_SEQUENCE_FLAG_COLOR_RANGE |
- V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X |
- V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y |
- V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT |
- V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q))
- return -EINVAL;
- if (s->seq_profile == 1 && s->flags & V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME)
- return -EINVAL;
- /* reserved */
- if (s->seq_profile > 2)
- return -EINVAL;
- /* TODO: PROFILES */
- return 0;
- }
- /*
- * Compound controls validation requires setting unused fields/flags to zero
- * in order to properly detect unchanged controls with v4l2_ctrl_type_op_equal's
- * memcmp.
- */
- static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
- union v4l2_ctrl_ptr ptr)
- {
- struct v4l2_ctrl_mpeg2_sequence *p_mpeg2_sequence;
- struct v4l2_ctrl_mpeg2_picture *p_mpeg2_picture;
- struct v4l2_ctrl_vp8_frame *p_vp8_frame;
- struct v4l2_ctrl_fwht_params *p_fwht_params;
- struct v4l2_ctrl_h264_sps *p_h264_sps;
- struct v4l2_ctrl_h264_pps *p_h264_pps;
- struct v4l2_ctrl_h264_pred_weights *p_h264_pred_weights;
- struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
- struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
- struct v4l2_ctrl_hevc_sps *p_hevc_sps;
- struct v4l2_ctrl_hevc_pps *p_hevc_pps;
- struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
- struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params;
- struct v4l2_area *area;
- void *p = ptr.p + idx * ctrl->elem_size;
- unsigned int i;
- switch ((u32)ctrl->type) {
- case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
- p_mpeg2_sequence = p;
- switch (p_mpeg2_sequence->chroma_format) {
- case 1: /* 4:2:0 */
- case 2: /* 4:2:2 */
- case 3: /* 4:4:4 */
- break;
- default:
- return -EINVAL;
- }
- break;
- case V4L2_CTRL_TYPE_MPEG2_PICTURE:
- p_mpeg2_picture = p;
- switch (p_mpeg2_picture->intra_dc_precision) {
- case 0: /* 8 bits */
- case 1: /* 9 bits */
- case 2: /* 10 bits */
- case 3: /* 11 bits */
- break;
- default:
- return -EINVAL;
- }
- switch (p_mpeg2_picture->picture_structure) {
- case V4L2_MPEG2_PIC_TOP_FIELD:
- case V4L2_MPEG2_PIC_BOTTOM_FIELD:
- case V4L2_MPEG2_PIC_FRAME:
- break;
- default:
- return -EINVAL;
- }
- switch (p_mpeg2_picture->picture_coding_type) {
- case V4L2_MPEG2_PIC_CODING_TYPE_I:
- case V4L2_MPEG2_PIC_CODING_TYPE_P:
- case V4L2_MPEG2_PIC_CODING_TYPE_B:
- break;
- default:
- return -EINVAL;
- }
- zero_reserved(*p_mpeg2_picture);
- break;
- case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
- break;
- case V4L2_CTRL_TYPE_FWHT_PARAMS:
- p_fwht_params = p;
- if (p_fwht_params->version < V4L2_FWHT_VERSION)
- return -EINVAL;
- if (!p_fwht_params->width || !p_fwht_params->height)
- return -EINVAL;
- break;
- case V4L2_CTRL_TYPE_H264_SPS:
- p_h264_sps = p;
- /* Some syntax elements are only conditionally valid */
- if (p_h264_sps->pic_order_cnt_type != 0) {
- p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 = 0;
- } else if (p_h264_sps->pic_order_cnt_type != 1) {
- p_h264_sps->num_ref_frames_in_pic_order_cnt_cycle = 0;
- p_h264_sps->offset_for_non_ref_pic = 0;
- p_h264_sps->offset_for_top_to_bottom_field = 0;
- memset(&p_h264_sps->offset_for_ref_frame, 0,
- sizeof(p_h264_sps->offset_for_ref_frame));
- }
- if (!V4L2_H264_SPS_HAS_CHROMA_FORMAT(p_h264_sps)) {
- p_h264_sps->chroma_format_idc = 1;
- p_h264_sps->bit_depth_luma_minus8 = 0;
- p_h264_sps->bit_depth_chroma_minus8 = 0;
- p_h264_sps->flags &=
- ~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS;
- }
- if (p_h264_sps->chroma_format_idc < 3)
- p_h264_sps->flags &=
- ~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE;
- if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)
- p_h264_sps->flags &=
- ~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD;
- /*
- * Chroma 4:2:2 format require at least High 4:2:2 profile.
- *
- * The H264 specification and well-known parser implementations
- * use profile-idc values directly, as that is clearer and
- * less ambiguous. We do the same here.
- */
- if (p_h264_sps->profile_idc < 122 &&
- p_h264_sps->chroma_format_idc > 1)
- return -EINVAL;
- /* Chroma 4:4:4 format require at least High 4:2:2 profile */
- if (p_h264_sps->profile_idc < 244 &&
- p_h264_sps->chroma_format_idc > 2)
- return -EINVAL;
- if (p_h264_sps->chroma_format_idc > 3)
- return -EINVAL;
- if (p_h264_sps->bit_depth_luma_minus8 > 6)
- return -EINVAL;
- if (p_h264_sps->bit_depth_chroma_minus8 > 6)
- return -EINVAL;
- if (p_h264_sps->log2_max_frame_num_minus4 > 12)
- return -EINVAL;
- if (p_h264_sps->pic_order_cnt_type > 2)
- return -EINVAL;
- if (p_h264_sps->log2_max_pic_order_cnt_lsb_minus4 > 12)
- return -EINVAL;
- if (p_h264_sps->max_num_ref_frames > V4L2_H264_REF_LIST_LEN)
- return -EINVAL;
- break;
- case V4L2_CTRL_TYPE_H264_PPS:
- p_h264_pps = p;
- if (p_h264_pps->num_slice_groups_minus1 > 7)
- return -EINVAL;
- if (p_h264_pps->num_ref_idx_l0_default_active_minus1 >
- (V4L2_H264_REF_LIST_LEN - 1))
- return -EINVAL;
- if (p_h264_pps->num_ref_idx_l1_default_active_minus1 >
- (V4L2_H264_REF_LIST_LEN - 1))
- return -EINVAL;
- if (p_h264_pps->weighted_bipred_idc > 2)
- return -EINVAL;
- /*
- * pic_init_qp_minus26 shall be in the range of
- * -(26 + QpBdOffset_y) to +25, inclusive,
- * where QpBdOffset_y is 6 * bit_depth_luma_minus8
- */
- if (p_h264_pps->pic_init_qp_minus26 < -62 ||
- p_h264_pps->pic_init_qp_minus26 > 25)
- return -EINVAL;
- if (p_h264_pps->pic_init_qs_minus26 < -26 ||
- p_h264_pps->pic_init_qs_minus26 > 25)
- return -EINVAL;
- if (p_h264_pps->chroma_qp_index_offset < -12 ||
- p_h264_pps->chroma_qp_index_offset > 12)
- return -EINVAL;
- if (p_h264_pps->second_chroma_qp_index_offset < -12 ||
- p_h264_pps->second_chroma_qp_index_offset > 12)
- return -EINVAL;
- break;
- case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
- break;
- case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
- p_h264_pred_weights = p;
- if (p_h264_pred_weights->luma_log2_weight_denom > 7)
- return -EINVAL;
- if (p_h264_pred_weights->chroma_log2_weight_denom > 7)
- return -EINVAL;
- break;
- case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
- p_h264_slice_params = p;
- if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B)
- p_h264_slice_params->flags &=
- ~V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED;
- if (p_h264_slice_params->colour_plane_id > 2)
- return -EINVAL;
- if (p_h264_slice_params->cabac_init_idc > 2)
- return -EINVAL;
- if (p_h264_slice_params->disable_deblocking_filter_idc > 2)
- return -EINVAL;
- if (p_h264_slice_params->slice_alpha_c0_offset_div2 < -6 ||
- p_h264_slice_params->slice_alpha_c0_offset_div2 > 6)
- return -EINVAL;
- if (p_h264_slice_params->slice_beta_offset_div2 < -6 ||
- p_h264_slice_params->slice_beta_offset_div2 > 6)
- return -EINVAL;
- if (p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_I ||
- p_h264_slice_params->slice_type == V4L2_H264_SLICE_TYPE_SI)
- p_h264_slice_params->num_ref_idx_l0_active_minus1 = 0;
- if (p_h264_slice_params->slice_type != V4L2_H264_SLICE_TYPE_B)
- p_h264_slice_params->num_ref_idx_l1_active_minus1 = 0;
- if (p_h264_slice_params->num_ref_idx_l0_active_minus1 >
- (V4L2_H264_REF_LIST_LEN - 1))
- return -EINVAL;
- if (p_h264_slice_params->num_ref_idx_l1_active_minus1 >
- (V4L2_H264_REF_LIST_LEN - 1))
- return -EINVAL;
- zero_reserved(*p_h264_slice_params);
- break;
- case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
- p_h264_dec_params = p;
- if (p_h264_dec_params->nal_ref_idc > 3)
- return -EINVAL;
- for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
- struct v4l2_h264_dpb_entry *dpb_entry =
- &p_h264_dec_params->dpb[i];
- zero_reserved(*dpb_entry);
- }
- zero_reserved(*p_h264_dec_params);
- break;
- case V4L2_CTRL_TYPE_VP8_FRAME:
- p_vp8_frame = p;
- switch (p_vp8_frame->num_dct_parts) {
- case 1:
- case 2:
- case 4:
- case 8:
- break;
- default:
- return -EINVAL;
- }
- zero_padding(p_vp8_frame->segment);
- zero_padding(p_vp8_frame->lf);
- zero_padding(p_vp8_frame->quant);
- zero_padding(p_vp8_frame->entropy);
- zero_padding(p_vp8_frame->coder_state);
- break;
- case V4L2_CTRL_TYPE_HEVC_SPS:
- p_hevc_sps = p;
- if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) {
- p_hevc_sps->pcm_sample_bit_depth_luma_minus1 = 0;
- p_hevc_sps->pcm_sample_bit_depth_chroma_minus1 = 0;
- p_hevc_sps->log2_min_pcm_luma_coding_block_size_minus3 = 0;
- p_hevc_sps->log2_diff_max_min_pcm_luma_coding_block_size = 0;
- }
- if (!(p_hevc_sps->flags &
- V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT))
- p_hevc_sps->num_long_term_ref_pics_sps = 0;
- break;
- case V4L2_CTRL_TYPE_HEVC_PPS:
- p_hevc_pps = p;
- if (!(p_hevc_pps->flags &
- V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED))
- p_hevc_pps->diff_cu_qp_delta_depth = 0;
- if (!(p_hevc_pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED)) {
- p_hevc_pps->num_tile_columns_minus1 = 0;
- p_hevc_pps->num_tile_rows_minus1 = 0;
- memset(&p_hevc_pps->column_width_minus1, 0,
- sizeof(p_hevc_pps->column_width_minus1));
- memset(&p_hevc_pps->row_height_minus1, 0,
- sizeof(p_hevc_pps->row_height_minus1));
- p_hevc_pps->flags &=
- ~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED;
- }
- if (p_hevc_pps->flags &
- V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER) {
- p_hevc_pps->pps_beta_offset_div2 = 0;
- p_hevc_pps->pps_tc_offset_div2 = 0;
- }
- break;
- case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS:
- p_hevc_decode_params = p;
- if (p_hevc_decode_params->num_active_dpb_entries >
- V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
- return -EINVAL;
- break;
- case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
- break;
- case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
- break;
- case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
- p_hdr10_mastering = p;
- for (i = 0; i < 3; ++i) {
- if (p_hdr10_mastering->display_primaries_x[i] <
- V4L2_HDR10_MASTERING_PRIMARIES_X_LOW ||
- p_hdr10_mastering->display_primaries_x[i] >
- V4L2_HDR10_MASTERING_PRIMARIES_X_HIGH ||
- p_hdr10_mastering->display_primaries_y[i] <
- V4L2_HDR10_MASTERING_PRIMARIES_Y_LOW ||
- p_hdr10_mastering->display_primaries_y[i] >
- V4L2_HDR10_MASTERING_PRIMARIES_Y_HIGH)
- return -EINVAL;
- }
- if (p_hdr10_mastering->white_point_x <
- V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW ||
- p_hdr10_mastering->white_point_x >
- V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH ||
- p_hdr10_mastering->white_point_y <
- V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW ||
- p_hdr10_mastering->white_point_y >
- V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH)
- return -EINVAL;
- if (p_hdr10_mastering->max_display_mastering_luminance <
- V4L2_HDR10_MASTERING_MAX_LUMA_LOW ||
- p_hdr10_mastering->max_display_mastering_luminance >
- V4L2_HDR10_MASTERING_MAX_LUMA_HIGH ||
- p_hdr10_mastering->min_display_mastering_luminance <
- V4L2_HDR10_MASTERING_MIN_LUMA_LOW ||
- p_hdr10_mastering->min_display_mastering_luminance >
- V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)
- return -EINVAL;
- /* The following restriction comes from ITU-T Rec. H.265 spec */
- if (p_hdr10_mastering->max_display_mastering_luminance ==
- V4L2_HDR10_MASTERING_MAX_LUMA_LOW &&
- p_hdr10_mastering->min_display_mastering_luminance ==
- V4L2_HDR10_MASTERING_MIN_LUMA_HIGH)
- return -EINVAL;
- break;
- case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
- break;
- case V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR:
- return validate_vp9_compressed_hdr(p);
- case V4L2_CTRL_TYPE_VP9_FRAME:
- return validate_vp9_frame(p);
- case V4L2_CTRL_TYPE_AV1_FRAME:
- return validate_av1_frame(p);
- case V4L2_CTRL_TYPE_AV1_SEQUENCE:
- return validate_av1_sequence(p);
- case V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY:
- break;
- case V4L2_CTRL_TYPE_AV1_FILM_GRAIN:
- return validate_av1_film_grain(p);
- case V4L2_CTRL_TYPE_AREA:
- area = p;
- if (!area->width || !area->height)
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static int std_validate_elem(const struct v4l2_ctrl *ctrl, u32 idx,
- union v4l2_ctrl_ptr ptr)
- {
- size_t len;
- u64 offset;
- s64 val;
- switch ((u32)ctrl->type) {
- case V4L2_CTRL_TYPE_INTEGER:
- return ROUND_TO_RANGE(ptr.p_s32[idx], u32, ctrl);
- case V4L2_CTRL_TYPE_INTEGER64:
- /*
- * We can't use the ROUND_TO_RANGE define here due to
- * the u64 divide that needs special care.
- */
- val = ptr.p_s64[idx];
- if (ctrl->maximum >= 0 && val >= ctrl->maximum - (s64)(ctrl->step / 2))
- val = ctrl->maximum;
- else
- val += (s64)(ctrl->step / 2);
- val = clamp_t(s64, val, ctrl->minimum, ctrl->maximum);
- offset = val - ctrl->minimum;
- do_div(offset, ctrl->step);
- ptr.p_s64[idx] = ctrl->minimum + offset * ctrl->step;
- return 0;
- case V4L2_CTRL_TYPE_U8:
- return ROUND_TO_RANGE(ptr.p_u8[idx], u8, ctrl);
- case V4L2_CTRL_TYPE_U16:
- return ROUND_TO_RANGE(ptr.p_u16[idx], u16, ctrl);
- case V4L2_CTRL_TYPE_U32:
- return ROUND_TO_RANGE(ptr.p_u32[idx], u32, ctrl);
- case V4L2_CTRL_TYPE_BOOLEAN:
- ptr.p_s32[idx] = !!ptr.p_s32[idx];
- return 0;
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum)
- return -ERANGE;
- if (ptr.p_s32[idx] < BITS_PER_LONG_LONG &&
- (ctrl->menu_skip_mask & BIT_ULL(ptr.p_s32[idx])))
- return -EINVAL;
- if (ctrl->type == V4L2_CTRL_TYPE_MENU &&
- ctrl->qmenu[ptr.p_s32[idx]][0] == '\0')
- return -EINVAL;
- return 0;
- case V4L2_CTRL_TYPE_BITMASK:
- ptr.p_s32[idx] &= ctrl->maximum;
- return 0;
- case V4L2_CTRL_TYPE_BUTTON:
- case V4L2_CTRL_TYPE_CTRL_CLASS:
- ptr.p_s32[idx] = 0;
- return 0;
- case V4L2_CTRL_TYPE_STRING:
- idx *= ctrl->elem_size;
- len = strlen(ptr.p_char + idx);
- if (len < ctrl->minimum)
- return -ERANGE;
- if ((len - (u32)ctrl->minimum) % (u32)ctrl->step)
- return -ERANGE;
- return 0;
- default:
- return std_validate_compound(ctrl, idx, ptr);
- }
- }
- int v4l2_ctrl_type_op_validate(const struct v4l2_ctrl *ctrl,
- union v4l2_ctrl_ptr ptr)
- {
- unsigned int i;
- int ret = 0;
- switch ((u32)ctrl->type) {
- case V4L2_CTRL_TYPE_U8:
- if (ctrl->maximum == 0xff && ctrl->minimum == 0 && ctrl->step == 1)
- return 0;
- break;
- case V4L2_CTRL_TYPE_U16:
- if (ctrl->maximum == 0xffff && ctrl->minimum == 0 && ctrl->step == 1)
- return 0;
- break;
- case V4L2_CTRL_TYPE_U32:
- if (ctrl->maximum == 0xffffffff && ctrl->minimum == 0 && ctrl->step == 1)
- return 0;
- break;
- case V4L2_CTRL_TYPE_BUTTON:
- case V4L2_CTRL_TYPE_CTRL_CLASS:
- memset(ptr.p_s32, 0, ctrl->new_elems * sizeof(s32));
- return 0;
- }
- for (i = 0; !ret && i < ctrl->new_elems; i++)
- ret = std_validate_elem(ctrl, i, ptr);
- return ret;
- }
- EXPORT_SYMBOL(v4l2_ctrl_type_op_validate);
- static const struct v4l2_ctrl_type_ops std_type_ops = {
- .equal = v4l2_ctrl_type_op_equal,
- .init = v4l2_ctrl_type_op_init,
- .log = v4l2_ctrl_type_op_log,
- .validate = v4l2_ctrl_type_op_validate,
- };
- void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
- {
- if (!ctrl)
- return;
- if (!notify) {
- ctrl->call_notify = 0;
- return;
- }
- if (WARN_ON(ctrl->handler->notify && ctrl->handler->notify != notify))
- return;
- ctrl->handler->notify = notify;
- ctrl->handler->notify_priv = priv;
- ctrl->call_notify = 1;
- }
- EXPORT_SYMBOL(v4l2_ctrl_notify);
- /* Copy the one value to another. */
- static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
- union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to,
- unsigned int elems)
- {
- if (ctrl == NULL)
- return;
- memcpy(to.p, from.p_const, elems * ctrl->elem_size);
- }
- /* Copy the new value to the current value. */
- void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
- {
- bool changed;
- if (ctrl == NULL)
- return;
- /* has_changed is set by cluster_changed */
- changed = ctrl->has_changed;
- if (changed) {
- if (ctrl->is_dyn_array)
- ctrl->elems = ctrl->new_elems;
- ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur, ctrl->elems);
- }
- if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
- /* Note: CH_FLAGS is only set for auto clusters. */
- ctrl->flags &=
- ~(V4L2_CTRL_FLAG_INACTIVE | V4L2_CTRL_FLAG_VOLATILE);
- if (!is_cur_manual(ctrl->cluster[0])) {
- ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- if (ctrl->cluster[0]->has_volatiles)
- ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
- }
- fh = NULL;
- }
- if (changed || ch_flags) {
- /* If a control was changed that was not one of the controls
- modified by the application, then send the event to all. */
- if (!ctrl->is_new)
- fh = NULL;
- send_event(fh, ctrl,
- (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) | ch_flags);
- if (ctrl->call_notify && changed && ctrl->handler->notify)
- ctrl->handler->notify(ctrl, ctrl->handler->notify_priv);
- }
- }
- /* Copy the current value to the new value */
- void cur_to_new(struct v4l2_ctrl *ctrl)
- {
- if (ctrl == NULL)
- return;
- if (ctrl->is_dyn_array)
- ctrl->new_elems = ctrl->elems;
- ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new, ctrl->new_elems);
- }
- static bool req_alloc_array(struct v4l2_ctrl_ref *ref, u32 elems)
- {
- void *tmp;
- if (elems == ref->p_req_array_alloc_elems)
- return true;
- if (ref->ctrl->is_dyn_array &&
- elems < ref->p_req_array_alloc_elems)
- return true;
- tmp = kvmalloc(elems * ref->ctrl->elem_size, GFP_KERNEL);
- if (!tmp) {
- ref->p_req_array_enomem = true;
- return false;
- }
- ref->p_req_array_enomem = false;
- kvfree(ref->p_req.p);
- ref->p_req.p = tmp;
- ref->p_req_array_alloc_elems = elems;
- return true;
- }
- /* Copy the new value to the request value */
- void new_to_req(struct v4l2_ctrl_ref *ref)
- {
- struct v4l2_ctrl *ctrl;
- if (!ref)
- return;
- ctrl = ref->ctrl;
- if (ctrl->is_array && !req_alloc_array(ref, ctrl->new_elems))
- return;
- ref->p_req_elems = ctrl->new_elems;
- ptr_to_ptr(ctrl, ctrl->p_new, ref->p_req, ref->p_req_elems);
- ref->p_req_valid = true;
- }
- /* Copy the current value to the request value */
- void cur_to_req(struct v4l2_ctrl_ref *ref)
- {
- struct v4l2_ctrl *ctrl;
- if (!ref)
- return;
- ctrl = ref->ctrl;
- if (ctrl->is_array && !req_alloc_array(ref, ctrl->elems))
- return;
- ref->p_req_elems = ctrl->elems;
- ptr_to_ptr(ctrl, ctrl->p_cur, ref->p_req, ctrl->elems);
- ref->p_req_valid = true;
- }
- /* Copy the request value to the new value */
- int req_to_new(struct v4l2_ctrl_ref *ref)
- {
- struct v4l2_ctrl *ctrl;
- if (!ref)
- return 0;
- ctrl = ref->ctrl;
- /*
- * This control was never set in the request, so just use the current
- * value.
- */
- if (!ref->p_req_valid) {
- if (ctrl->is_dyn_array)
- ctrl->new_elems = ctrl->elems;
- ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new, ctrl->new_elems);
- return 0;
- }
- /* Not an array, so just copy the request value */
- if (!ctrl->is_array) {
- ptr_to_ptr(ctrl, ref->p_req, ctrl->p_new, ctrl->new_elems);
- return 0;
- }
- /* Sanity check, should never happen */
- if (WARN_ON(!ref->p_req_array_alloc_elems))
- return -ENOMEM;
- if (!ctrl->is_dyn_array &&
- ref->p_req_elems != ctrl->p_array_alloc_elems)
- return -ENOMEM;
- /*
- * Check if the number of elements in the request is more than the
- * elements in ctrl->p_array. If so, attempt to realloc ctrl->p_array.
- * Note that p_array is allocated with twice the number of elements
- * in the dynamic array since it has to store both the current and
- * new value of such a control.
- */
- if (ref->p_req_elems > ctrl->p_array_alloc_elems) {
- unsigned int sz = ref->p_req_elems * ctrl->elem_size;
- void *old = ctrl->p_array;
- void *tmp = kvzalloc(2 * sz, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
- memcpy(tmp, ctrl->p_new.p, ctrl->elems * ctrl->elem_size);
- memcpy(tmp + sz, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size);
- ctrl->p_new.p = tmp;
- ctrl->p_cur.p = tmp + sz;
- ctrl->p_array = tmp;
- ctrl->p_array_alloc_elems = ref->p_req_elems;
- kvfree(old);
- }
- ctrl->new_elems = ref->p_req_elems;
- ptr_to_ptr(ctrl, ref->p_req, ctrl->p_new, ctrl->new_elems);
- return 0;
- }
- /* Control range checking */
- int check_range(enum v4l2_ctrl_type type,
- s64 min, s64 max, u64 step, s64 def)
- {
- switch (type) {
- case V4L2_CTRL_TYPE_BOOLEAN:
- if (step != 1 || max > 1 || min < 0)
- return -ERANGE;
- fallthrough;
- case V4L2_CTRL_TYPE_U8:
- case V4L2_CTRL_TYPE_U16:
- case V4L2_CTRL_TYPE_U32:
- case V4L2_CTRL_TYPE_INTEGER:
- case V4L2_CTRL_TYPE_INTEGER64:
- if (step == 0 || min > max || def < min || def > max)
- return -ERANGE;
- return 0;
- case V4L2_CTRL_TYPE_BITMASK:
- if (step || min || !max || (def & ~max))
- return -ERANGE;
- return 0;
- case V4L2_CTRL_TYPE_MENU:
- case V4L2_CTRL_TYPE_INTEGER_MENU:
- if (min > max || def < min || def > max ||
- min < 0 || (step && max >= BITS_PER_LONG_LONG))
- return -ERANGE;
- /* Note: step == menu_skip_mask for menu controls.
- So here we check if the default value is masked out. */
- if (def < BITS_PER_LONG_LONG && (step & BIT_ULL(def)))
- return -EINVAL;
- return 0;
- case V4L2_CTRL_TYPE_STRING:
- if (min > max || min < 0 || step < 1 || def)
- return -ERANGE;
- return 0;
- default:
- return 0;
- }
- }
- /* Set the handler's error code if it wasn't set earlier already */
- static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
- {
- if (hdl->error == 0)
- hdl->error = err;
- return err;
- }
- /* Initialize the handler */
- int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
- unsigned nr_of_controls_hint,
- struct lock_class_key *key, const char *name)
- {
- mutex_init(&hdl->_lock);
- hdl->lock = &hdl->_lock;
- lockdep_set_class_and_name(hdl->lock, key, name);
- INIT_LIST_HEAD(&hdl->ctrls);
- INIT_LIST_HEAD(&hdl->ctrl_refs);
- hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
- hdl->buckets = kvcalloc(hdl->nr_of_buckets, sizeof(hdl->buckets[0]),
- GFP_KERNEL);
- hdl->error = hdl->buckets ? 0 : -ENOMEM;
- v4l2_ctrl_handler_init_request(hdl);
- return hdl->error;
- }
- EXPORT_SYMBOL(v4l2_ctrl_handler_init_class);
- /* Free all controls and control refs */
- void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
- {
- struct v4l2_ctrl_ref *ref, *next_ref;
- struct v4l2_ctrl *ctrl, *next_ctrl;
- struct v4l2_subscribed_event *sev, *next_sev;
- if (hdl == NULL || hdl->buckets == NULL)
- return;
- v4l2_ctrl_handler_free_request(hdl);
- mutex_lock(hdl->lock);
- /* Free all nodes */
- list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
- list_del(&ref->node);
- if (ref->p_req_array_alloc_elems)
- kvfree(ref->p_req.p);
- kfree(ref);
- }
- /* Free all controls owned by the handler */
- list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
- list_del(&ctrl->node);
- list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
- list_del(&sev->node);
- kvfree(ctrl->p_array);
- kvfree(ctrl);
- }
- kvfree(hdl->buckets);
- hdl->buckets = NULL;
- hdl->cached = NULL;
- mutex_unlock(hdl->lock);
- mutex_destroy(&hdl->_lock);
- }
- EXPORT_SYMBOL(v4l2_ctrl_handler_free);
- /* For backwards compatibility: V4L2_CID_PRIVATE_BASE should no longer
- be used except in G_CTRL, S_CTRL, QUERYCTRL and QUERYMENU when dealing
- with applications that do not use the NEXT_CTRL flag.
- We just find the n-th private user control. It's O(N), but that should not
- be an issue in this particular case. */
- static struct v4l2_ctrl_ref *find_private_ref(
- struct v4l2_ctrl_handler *hdl, u32 id)
- {
- struct v4l2_ctrl_ref *ref;
- id -= V4L2_CID_PRIVATE_BASE;
- list_for_each_entry(ref, &hdl->ctrl_refs, node) {
- /* Search for private user controls that are compatible with
- VIDIOC_G/S_CTRL. */
- if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
- V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) {
- if (!ref->ctrl->is_int)
- continue;
- if (id == 0)
- return ref;
- id--;
- }
- }
- return NULL;
- }
- /* Find a control with the given ID. */
- struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id)
- {
- struct v4l2_ctrl_ref *ref;
- int bucket;
- id &= V4L2_CTRL_ID_MASK;
- /* Old-style private controls need special handling */
- if (id >= V4L2_CID_PRIVATE_BASE)
- return find_private_ref(hdl, id);
- bucket = id % hdl->nr_of_buckets;
- /* Simple optimization: cache the last control found */
- if (hdl->cached && hdl->cached->ctrl->id == id)
- return hdl->cached;
- /* Not in cache, search the hash */
- ref = hdl->buckets ? hdl->buckets[bucket] : NULL;
- while (ref && ref->ctrl->id != id)
- ref = ref->next;
- if (ref)
- hdl->cached = ref; /* cache it! */
- return ref;
- }
- /* Find a control with the given ID. Take the handler's lock first. */
- struct v4l2_ctrl_ref *find_ref_lock(struct v4l2_ctrl_handler *hdl, u32 id)
- {
- struct v4l2_ctrl_ref *ref = NULL;
- if (hdl) {
- mutex_lock(hdl->lock);
- ref = find_ref(hdl, id);
- mutex_unlock(hdl->lock);
- }
- return ref;
- }
- /* Find a control with the given ID. */
- struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
- {
- struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
- return ref ? ref->ctrl : NULL;
- }
- EXPORT_SYMBOL(v4l2_ctrl_find);
- /* Allocate a new v4l2_ctrl_ref and hook it into the handler. */
- int handler_new_ref(struct v4l2_ctrl_handler *hdl,
- struct v4l2_ctrl *ctrl,
- struct v4l2_ctrl_ref **ctrl_ref,
- bool from_other_dev, bool allocate_req)
- {
- struct v4l2_ctrl_ref *ref;
- struct v4l2_ctrl_ref *new_ref;
- u32 id = ctrl->id;
- u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1;
- int bucket = id % hdl->nr_of_buckets; /* which bucket to use */
- unsigned int size_extra_req = 0;
- if (ctrl_ref)
- *ctrl_ref = NULL;
- /*
- * Automatically add the control class if it is not yet present and
- * the new control is not a compound control.
- */
- if (ctrl->type < V4L2_CTRL_COMPOUND_TYPES &&
- id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL)
- if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0))
- return hdl->error;
- if (hdl->error)
- return hdl->error;
- if (allocate_req && !ctrl->is_array)
- size_extra_req = ctrl->elems * ctrl->elem_size;
- new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL);
- if (!new_ref)
- return handler_set_err(hdl, -ENOMEM);
- new_ref->ctrl = ctrl;
- new_ref->from_other_dev = from_other_dev;
- if (size_extra_req)
- new_ref->p_req.p = &new_ref[1];
- INIT_LIST_HEAD(&new_ref->node);
- mutex_lock(hdl->lock);
- /* Add immediately at the end of the list if the list is empty, or if
- the last element in the list has a lower ID.
- This ensures that when elements are added in ascending order the
- insertion is an O(1) operation. */
- if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) {
- list_add_tail(&new_ref->node, &hdl->ctrl_refs);
- goto insert_in_hash;
- }
- /* Find insert position in sorted list */
- list_for_each_entry(ref, &hdl->ctrl_refs, node) {
- if (ref->ctrl->id < id)
- continue;
- /* Don't add duplicates */
- if (ref->ctrl->id == id) {
- kfree(new_ref);
- goto unlock;
- }
- list_add(&new_ref->node, ref->node.prev);
- break;
- }
- insert_in_hash:
- /* Insert the control node in the hash */
- new_ref->next = hdl->buckets[bucket];
- hdl->buckets[bucket] = new_ref;
- if (ctrl_ref)
- *ctrl_ref = new_ref;
- if (ctrl->handler == hdl) {
- /* By default each control starts in a cluster of its own.
- * new_ref->ctrl is basically a cluster array with one
- * element, so that's perfect to use as the cluster pointer.
- * But only do this for the handler that owns the control.
- */
- ctrl->cluster = &new_ref->ctrl;
- ctrl->ncontrols = 1;
- }
- unlock:
- mutex_unlock(hdl->lock);
- return 0;
- }
- /* Add a new control */
- static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops,
- const struct v4l2_ctrl_type_ops *type_ops,
- u32 id, const char *name, enum v4l2_ctrl_type type,
- s64 min, s64 max, u64 step, s64 def,
- const u32 dims[V4L2_CTRL_MAX_DIMS], u32 elem_size,
- u32 flags, const char * const *qmenu,
- const s64 *qmenu_int, const union v4l2_ctrl_ptr p_def,
- void *priv)
- {
- struct v4l2_ctrl *ctrl;
- unsigned sz_extra;
- unsigned nr_of_dims = 0;
- unsigned elems = 1;
- bool is_array;
- unsigned tot_ctrl_size;
- void *data;
- int err;
- if (hdl->error)
- return NULL;
- while (dims && dims[nr_of_dims]) {
- elems *= dims[nr_of_dims];
- nr_of_dims++;
- if (nr_of_dims == V4L2_CTRL_MAX_DIMS)
- break;
- }
- is_array = nr_of_dims > 0;
- /* Prefill elem_size for all types handled by std_type_ops */
- switch ((u32)type) {
- case V4L2_CTRL_TYPE_INTEGER64:
- elem_size = sizeof(s64);
- break;
- case V4L2_CTRL_TYPE_STRING:
- elem_size = max + 1;
- break;
- case V4L2_CTRL_TYPE_U8:
- elem_size = sizeof(u8);
- break;
- case V4L2_CTRL_TYPE_U16:
- elem_size = sizeof(u16);
- break;
- case V4L2_CTRL_TYPE_U32:
- elem_size = sizeof(u32);
- break;
- case V4L2_CTRL_TYPE_MPEG2_SEQUENCE:
- elem_size = sizeof(struct v4l2_ctrl_mpeg2_sequence);
- break;
- case V4L2_CTRL_TYPE_MPEG2_PICTURE:
- elem_size = sizeof(struct v4l2_ctrl_mpeg2_picture);
- break;
- case V4L2_CTRL_TYPE_MPEG2_QUANTISATION:
- elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantisation);
- break;
- case V4L2_CTRL_TYPE_FWHT_PARAMS:
- elem_size = sizeof(struct v4l2_ctrl_fwht_params);
- break;
- case V4L2_CTRL_TYPE_H264_SPS:
- elem_size = sizeof(struct v4l2_ctrl_h264_sps);
- break;
- case V4L2_CTRL_TYPE_H264_PPS:
- elem_size = sizeof(struct v4l2_ctrl_h264_pps);
- break;
- case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
- elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix);
- break;
- case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
- elem_size = sizeof(struct v4l2_ctrl_h264_slice_params);
- break;
- case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
- elem_size = sizeof(struct v4l2_ctrl_h264_decode_params);
- break;
- case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
- elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights);
- break;
- case V4L2_CTRL_TYPE_VP8_FRAME:
- elem_size = sizeof(struct v4l2_ctrl_vp8_frame);
- break;
- case V4L2_CTRL_TYPE_HEVC_SPS:
- elem_size = sizeof(struct v4l2_ctrl_hevc_sps);
- break;
- case V4L2_CTRL_TYPE_HEVC_PPS:
- elem_size = sizeof(struct v4l2_ctrl_hevc_pps);
- break;
- case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
- elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params);
- break;
- case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
- elem_size = sizeof(struct v4l2_ctrl_hevc_scaling_matrix);
- break;
- case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS:
- elem_size = sizeof(struct v4l2_ctrl_hevc_decode_params);
- break;
- case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
- elem_size = sizeof(struct v4l2_ctrl_hdr10_cll_info);
- break;
- case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY:
- elem_size = sizeof(struct v4l2_ctrl_hdr10_mastering_display);
- break;
- case V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR:
- elem_size = sizeof(struct v4l2_ctrl_vp9_compressed_hdr);
- break;
- case V4L2_CTRL_TYPE_VP9_FRAME:
- elem_size = sizeof(struct v4l2_ctrl_vp9_frame);
- break;
- case V4L2_CTRL_TYPE_AV1_SEQUENCE:
- elem_size = sizeof(struct v4l2_ctrl_av1_sequence);
- break;
- case V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY:
- elem_size = sizeof(struct v4l2_ctrl_av1_tile_group_entry);
- break;
- case V4L2_CTRL_TYPE_AV1_FRAME:
- elem_size = sizeof(struct v4l2_ctrl_av1_frame);
- break;
- case V4L2_CTRL_TYPE_AV1_FILM_GRAIN:
- elem_size = sizeof(struct v4l2_ctrl_av1_film_grain);
- break;
- case V4L2_CTRL_TYPE_AREA:
- elem_size = sizeof(struct v4l2_area);
- break;
- default:
- if (type < V4L2_CTRL_COMPOUND_TYPES)
- elem_size = sizeof(s32);
- break;
- }
- /* Sanity checks */
- if (id == 0 || name == NULL || !elem_size ||
- id >= V4L2_CID_PRIVATE_BASE ||
- (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
- (type == V4L2_CTRL_TYPE_INTEGER_MENU && qmenu_int == NULL)) {
- handler_set_err(hdl, -ERANGE);
- return NULL;
- }
- err = check_range(type, min, max, step, def);
- if (err) {
- handler_set_err(hdl, err);
- return NULL;
- }
- if (is_array &&
- (type == V4L2_CTRL_TYPE_BUTTON ||
- type == V4L2_CTRL_TYPE_CTRL_CLASS)) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- if (flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) {
- /*
- * For now only support this for one-dimensional arrays only.
- *
- * This can be relaxed in the future, but this will
- * require more effort.
- */
- if (nr_of_dims != 1) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- /* Start with just 1 element */
- elems = 1;
- }
- tot_ctrl_size = elem_size * elems;
- sz_extra = 0;
- if (type == V4L2_CTRL_TYPE_BUTTON)
- flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
- V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
- else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
- flags |= V4L2_CTRL_FLAG_READ_ONLY;
- else if (!is_array &&
- (type == V4L2_CTRL_TYPE_INTEGER64 ||
- type == V4L2_CTRL_TYPE_STRING ||
- type >= V4L2_CTRL_COMPOUND_TYPES))
- sz_extra += 2 * tot_ctrl_size;
- if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const)
- sz_extra += elem_size;
- ctrl = kvzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
- if (ctrl == NULL) {
- handler_set_err(hdl, -ENOMEM);
- return NULL;
- }
- INIT_LIST_HEAD(&ctrl->node);
- INIT_LIST_HEAD(&ctrl->ev_subs);
- ctrl->handler = hdl;
- ctrl->ops = ops;
- ctrl->type_ops = type_ops ? type_ops : &std_type_ops;
- ctrl->id = id;
- ctrl->name = name;
- ctrl->type = type;
- ctrl->flags = flags;
- ctrl->minimum = min;
- ctrl->maximum = max;
- ctrl->step = step;
- ctrl->default_value = def;
- ctrl->is_string = !is_array && type == V4L2_CTRL_TYPE_STRING;
- ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
- ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
- ctrl->is_array = is_array;
- ctrl->is_dyn_array = !!(flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY);
- ctrl->elems = elems;
- ctrl->new_elems = elems;
- ctrl->nr_of_dims = nr_of_dims;
- if (nr_of_dims)
- memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0]));
- ctrl->elem_size = elem_size;
- if (type == V4L2_CTRL_TYPE_MENU)
- ctrl->qmenu = qmenu;
- else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
- ctrl->qmenu_int = qmenu_int;
- ctrl->priv = priv;
- ctrl->cur.val = ctrl->val = def;
- data = &ctrl[1];
- if (ctrl->is_array) {
- ctrl->p_array_alloc_elems = elems;
- ctrl->p_array = kvzalloc(2 * elems * elem_size, GFP_KERNEL);
- if (!ctrl->p_array) {
- kvfree(ctrl);
- return NULL;
- }
- data = ctrl->p_array;
- }
- if (!ctrl->is_int) {
- ctrl->p_new.p = data;
- ctrl->p_cur.p = data + tot_ctrl_size;
- } else {
- ctrl->p_new.p = &ctrl->val;
- ctrl->p_cur.p = &ctrl->cur.val;
- }
- if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) {
- if (ctrl->is_array)
- ctrl->p_def.p = &ctrl[1];
- else
- ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size;
- memcpy(ctrl->p_def.p, p_def.p_const, elem_size);
- }
- ctrl->type_ops->init(ctrl, 0, ctrl->p_cur);
- cur_to_new(ctrl);
- if (handler_new_ref(hdl, ctrl, NULL, false, false)) {
- kvfree(ctrl->p_array);
- kvfree(ctrl);
- return NULL;
- }
- mutex_lock(hdl->lock);
- list_add_tail(&ctrl->node, &hdl->ctrls);
- mutex_unlock(hdl->lock);
- return ctrl;
- }
- struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_config *cfg, void *priv)
- {
- bool is_menu;
- struct v4l2_ctrl *ctrl;
- const char *name = cfg->name;
- const char * const *qmenu = cfg->qmenu;
- const s64 *qmenu_int = cfg->qmenu_int;
- enum v4l2_ctrl_type type = cfg->type;
- u32 flags = cfg->flags;
- s64 min = cfg->min;
- s64 max = cfg->max;
- u64 step = cfg->step;
- s64 def = cfg->def;
- if (name == NULL)
- v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
- &def, &flags);
- is_menu = (type == V4L2_CTRL_TYPE_MENU ||
- type == V4L2_CTRL_TYPE_INTEGER_MENU);
- if (is_menu)
- WARN_ON(step);
- else
- WARN_ON(cfg->menu_skip_mask);
- if (type == V4L2_CTRL_TYPE_MENU && !qmenu) {
- qmenu = v4l2_ctrl_get_menu(cfg->id);
- } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->type_ops, cfg->id, name,
- type, min, max,
- is_menu ? cfg->menu_skip_mask : step, def,
- cfg->dims, cfg->elem_size,
- flags, qmenu, qmenu_int, cfg->p_def, priv);
- if (ctrl)
- ctrl->is_private = cfg->is_private;
- return ctrl;
- }
- EXPORT_SYMBOL(v4l2_ctrl_new_custom);
- /* Helper function for standard non-menu controls */
- struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops,
- u32 id, s64 min, s64 max, u64 step, s64 def)
- {
- const char *name;
- enum v4l2_ctrl_type type;
- u32 flags;
- v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
- if (type == V4L2_CTRL_TYPE_MENU ||
- type == V4L2_CTRL_TYPE_INTEGER_MENU ||
- type >= V4L2_CTRL_COMPOUND_TYPES) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
- min, max, step, def, NULL, 0,
- flags, NULL, NULL, ptr_null, NULL);
- }
- EXPORT_SYMBOL(v4l2_ctrl_new_std);
- /* Helper function for standard menu controls */
- struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops,
- u32 id, u8 _max, u64 mask, u8 _def)
- {
- const char * const *qmenu = NULL;
- const s64 *qmenu_int = NULL;
- unsigned int qmenu_int_len = 0;
- const char *name;
- enum v4l2_ctrl_type type;
- s64 min;
- s64 max = _max;
- s64 def = _def;
- u64 step;
- u32 flags;
- v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
- if (type == V4L2_CTRL_TYPE_MENU)
- qmenu = v4l2_ctrl_get_menu(id);
- else if (type == V4L2_CTRL_TYPE_INTEGER_MENU)
- qmenu_int = v4l2_ctrl_get_int_menu(id, &qmenu_int_len);
- if ((!qmenu && !qmenu_int) || (qmenu_int && max >= qmenu_int_len)) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
- 0, max, mask, def, NULL, 0,
- flags, qmenu, qmenu_int, ptr_null, NULL);
- }
- EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
- /* Helper function for standard menu controls with driver defined menu */
- struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops, u32 id, u8 _max,
- u64 mask, u8 _def, const char * const *qmenu)
- {
- enum v4l2_ctrl_type type;
- const char *name;
- u32 flags;
- u64 step;
- s64 min;
- s64 max = _max;
- s64 def = _def;
- /* v4l2_ctrl_new_std_menu_items() should only be called for
- * standard controls without a standard menu.
- */
- if (v4l2_ctrl_get_menu(id)) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
- if (type != V4L2_CTRL_TYPE_MENU || qmenu == NULL) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
- 0, max, mask, def, NULL, 0,
- flags, qmenu, NULL, ptr_null, NULL);
- }
- EXPORT_SYMBOL(v4l2_ctrl_new_std_menu_items);
- /* Helper function for standard compound controls */
- struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops, u32 id,
- const union v4l2_ctrl_ptr p_def)
- {
- const char *name;
- enum v4l2_ctrl_type type;
- u32 flags;
- s64 min, max, step, def;
- v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
- if (type < V4L2_CTRL_COMPOUND_TYPES) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
- min, max, step, def, NULL, 0,
- flags, NULL, NULL, p_def, NULL);
- }
- EXPORT_SYMBOL(v4l2_ctrl_new_std_compound);
- /* Helper function for standard integer menu controls */
- struct v4l2_ctrl *v4l2_ctrl_new_int_menu(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ops,
- u32 id, u8 _max, u8 _def, const s64 *qmenu_int)
- {
- const char *name;
- enum v4l2_ctrl_type type;
- s64 min;
- u64 step;
- s64 max = _max;
- s64 def = _def;
- u32 flags;
- v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
- if (type != V4L2_CTRL_TYPE_INTEGER_MENU) {
- handler_set_err(hdl, -EINVAL);
- return NULL;
- }
- return v4l2_ctrl_new(hdl, ops, NULL, id, name, type,
- 0, max, 0, def, NULL, 0,
- flags, NULL, qmenu_int, ptr_null, NULL);
- }
- EXPORT_SYMBOL(v4l2_ctrl_new_int_menu);
- /* Add the controls from another handler to our own. */
- int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
- struct v4l2_ctrl_handler *add,
- bool (*filter)(const struct v4l2_ctrl *ctrl),
- bool from_other_dev)
- {
- struct v4l2_ctrl_ref *ref;
- int ret = 0;
- /* Do nothing if either handler is NULL or if they are the same */
- if (!hdl || !add || hdl == add)
- return 0;
- if (hdl->error)
- return hdl->error;
- mutex_lock(add->lock);
- list_for_each_entry(ref, &add->ctrl_refs, node) {
- struct v4l2_ctrl *ctrl = ref->ctrl;
- /* Skip handler-private controls. */
- if (ctrl->is_private)
- continue;
- /* And control classes */
- if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
- continue;
- /* Filter any unwanted controls */
- if (filter && !filter(ctrl))
- continue;
- ret = handler_new_ref(hdl, ctrl, NULL, from_other_dev, false);
- if (ret)
- break;
- }
- mutex_unlock(add->lock);
- return ret;
- }
- EXPORT_SYMBOL(v4l2_ctrl_add_handler);
- bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl)
- {
- if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX)
- return true;
- if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX)
- return true;
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_LOUDNESS:
- return true;
- default:
- break;
- }
- return false;
- }
- EXPORT_SYMBOL(v4l2_ctrl_radio_filter);
- /* Cluster controls */
- void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
- {
- bool has_volatiles = false;
- int i;
- /* The first control is the master control and it must not be NULL */
- if (WARN_ON(ncontrols == 0 || controls[0] == NULL))
- return;
- for (i = 0; i < ncontrols; i++) {
- if (controls[i]) {
- controls[i]->cluster = controls;
- controls[i]->ncontrols = ncontrols;
- if (controls[i]->flags & V4L2_CTRL_FLAG_VOLATILE)
- has_volatiles = true;
- }
- }
- controls[0]->has_volatiles = has_volatiles;
- }
- EXPORT_SYMBOL(v4l2_ctrl_cluster);
- void v4l2_ctrl_auto_cluster(unsigned ncontrols, struct v4l2_ctrl **controls,
- u8 manual_val, bool set_volatile)
- {
- struct v4l2_ctrl *master = controls[0];
- u32 flag = 0;
- int i;
- v4l2_ctrl_cluster(ncontrols, controls);
- WARN_ON(ncontrols <= 1);
- WARN_ON(manual_val < master->minimum || manual_val > master->maximum);
- WARN_ON(set_volatile && !has_op(master, g_volatile_ctrl));
- master->is_auto = true;
- master->has_volatiles = set_volatile;
- master->manual_mode_value = manual_val;
- master->flags |= V4L2_CTRL_FLAG_UPDATE;
- if (!is_cur_manual(master))
- flag = V4L2_CTRL_FLAG_INACTIVE |
- (set_volatile ? V4L2_CTRL_FLAG_VOLATILE : 0);
- for (i = 1; i < ncontrols; i++)
- if (controls[i])
- controls[i]->flags |= flag;
- }
- EXPORT_SYMBOL(v4l2_ctrl_auto_cluster);
- /*
- * Obtain the current volatile values of an autocluster and mark them
- * as new.
- */
- void update_from_auto_cluster(struct v4l2_ctrl *master)
- {
- int i;
- for (i = 1; i < master->ncontrols; i++)
- cur_to_new(master->cluster[i]);
- if (!call_op(master, g_volatile_ctrl))
- for (i = 1; i < master->ncontrols; i++)
- if (master->cluster[i])
- master->cluster[i]->is_new = 1;
- }
- /*
- * Return non-zero if one or more of the controls in the cluster has a new
- * value that differs from the current value.
- */
- static int cluster_changed(struct v4l2_ctrl *master)
- {
- bool changed = false;
- int i;
- for (i = 0; i < master->ncontrols; i++) {
- struct v4l2_ctrl *ctrl = master->cluster[i];
- bool ctrl_changed = false;
- if (!ctrl)
- continue;
- if (ctrl->flags & V4L2_CTRL_FLAG_EXECUTE_ON_WRITE) {
- changed = true;
- ctrl_changed = true;
- }
- /*
- * Set has_changed to false to avoid generating
- * the event V4L2_EVENT_CTRL_CH_VALUE
- */
- if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) {
- ctrl->has_changed = false;
- continue;
- }
- if (ctrl->elems != ctrl->new_elems)
- ctrl_changed = true;
- if (!ctrl_changed)
- ctrl_changed = !ctrl->type_ops->equal(ctrl,
- ctrl->p_cur, ctrl->p_new);
- ctrl->has_changed = ctrl_changed;
- changed |= ctrl->has_changed;
- }
- return changed;
- }
- /*
- * Core function that calls try/s_ctrl and ensures that the new value is
- * copied to the current value on a set.
- * Must be called with ctrl->handler->lock held.
- */
- int try_or_set_cluster(struct v4l2_fh *fh, struct v4l2_ctrl *master,
- bool set, u32 ch_flags)
- {
- bool update_flag;
- int ret;
- int i;
- /*
- * Go through the cluster and either validate the new value or
- * (if no new value was set), copy the current value to the new
- * value, ensuring a consistent view for the control ops when
- * called.
- */
- for (i = 0; i < master->ncontrols; i++) {
- struct v4l2_ctrl *ctrl = master->cluster[i];
- if (!ctrl)
- continue;
- if (!ctrl->is_new) {
- cur_to_new(ctrl);
- continue;
- }
- /*
- * Check again: it may have changed since the
- * previous check in try_or_set_ext_ctrls().
- */
- if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
- return -EBUSY;
- }
- ret = call_op(master, try_ctrl);
- /* Don't set if there is no change */
- if (ret || !set || !cluster_changed(master))
- return ret;
- ret = call_op(master, s_ctrl);
- if (ret)
- return ret;
- /* If OK, then make the new values permanent. */
- update_flag = is_cur_manual(master) != is_new_manual(master);
- for (i = 0; i < master->ncontrols; i++) {
- /*
- * If we switch from auto to manual mode, and this cluster
- * contains volatile controls, then all non-master controls
- * have to be marked as changed. The 'new' value contains
- * the volatile value (obtained by update_from_auto_cluster),
- * which now has to become the current value.
- */
- if (i && update_flag && is_new_manual(master) &&
- master->has_volatiles && master->cluster[i])
- master->cluster[i]->has_changed = true;
- new_to_cur(fh, master->cluster[i], ch_flags |
- ((update_flag && i > 0) ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
- }
- return 0;
- }
- /* Activate/deactivate a control. */
- void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
- {
- /* invert since the actual flag is called 'inactive' */
- bool inactive = !active;
- bool old;
- if (ctrl == NULL)
- return;
- if (inactive)
- /* set V4L2_CTRL_FLAG_INACTIVE */
- old = test_and_set_bit(4, &ctrl->flags);
- else
- /* clear V4L2_CTRL_FLAG_INACTIVE */
- old = test_and_clear_bit(4, &ctrl->flags);
- if (old != inactive)
- send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
- }
- EXPORT_SYMBOL(v4l2_ctrl_activate);
- void __v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
- {
- bool old;
- if (ctrl == NULL)
- return;
- lockdep_assert_held(ctrl->handler->lock);
- if (grabbed)
- /* set V4L2_CTRL_FLAG_GRABBED */
- old = test_and_set_bit(1, &ctrl->flags);
- else
- /* clear V4L2_CTRL_FLAG_GRABBED */
- old = test_and_clear_bit(1, &ctrl->flags);
- if (old != grabbed)
- send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
- }
- EXPORT_SYMBOL(__v4l2_ctrl_grab);
- /* Call s_ctrl for all controls owned by the handler */
- int __v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
- {
- struct v4l2_ctrl *ctrl;
- int ret = 0;
- if (hdl == NULL)
- return 0;
- lockdep_assert_held(hdl->lock);
- list_for_each_entry(ctrl, &hdl->ctrls, node)
- ctrl->done = false;
- list_for_each_entry(ctrl, &hdl->ctrls, node) {
- struct v4l2_ctrl *master = ctrl->cluster[0];
- int i;
- /* Skip if this control was already handled by a cluster. */
- /* Skip button controls and read-only controls. */
- if (ctrl->done || ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
- (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
- continue;
- for (i = 0; i < master->ncontrols; i++) {
- if (master->cluster[i]) {
- cur_to_new(master->cluster[i]);
- master->cluster[i]->is_new = 1;
- master->cluster[i]->done = true;
- }
- }
- ret = call_op(master, s_ctrl);
- if (ret)
- break;
- }
- return ret;
- }
- EXPORT_SYMBOL_GPL(__v4l2_ctrl_handler_setup);
- int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
- {
- int ret;
- if (hdl == NULL)
- return 0;
- mutex_lock(hdl->lock);
- ret = __v4l2_ctrl_handler_setup(hdl);
- mutex_unlock(hdl->lock);
- return ret;
- }
- EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
- /* Log the control name and value */
- static void log_ctrl(const struct v4l2_ctrl *ctrl,
- const char *prefix, const char *colon)
- {
- if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY))
- return;
- if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
- return;
- pr_info("%s%s%s: ", prefix, colon, ctrl->name);
- ctrl->type_ops->log(ctrl);
- if (ctrl->flags & (V4L2_CTRL_FLAG_INACTIVE |
- V4L2_CTRL_FLAG_GRABBED |
- V4L2_CTRL_FLAG_VOLATILE)) {
- if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
- pr_cont(" inactive");
- if (ctrl->flags & V4L2_CTRL_FLAG_GRABBED)
- pr_cont(" grabbed");
- if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE)
- pr_cont(" volatile");
- }
- pr_cont("\n");
- }
- /* Log all controls owned by the handler */
- void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
- const char *prefix)
- {
- struct v4l2_ctrl *ctrl;
- const char *colon = "";
- int len;
- if (!hdl)
- return;
- if (!prefix)
- prefix = "";
- len = strlen(prefix);
- if (len && prefix[len - 1] != ' ')
- colon = ": ";
- mutex_lock(hdl->lock);
- list_for_each_entry(ctrl, &hdl->ctrls, node)
- if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
- log_ctrl(ctrl, prefix, colon);
- mutex_unlock(hdl->lock);
- }
- EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
- int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl,
- const struct v4l2_ctrl_ops *ctrl_ops,
- const struct v4l2_fwnode_device_properties *p)
- {
- if (hdl->error)
- return hdl->error;
- if (p->orientation != V4L2_FWNODE_PROPERTY_UNSET) {
- u32 orientation_ctrl;
- switch (p->orientation) {
- case V4L2_FWNODE_ORIENTATION_FRONT:
- orientation_ctrl = V4L2_CAMERA_ORIENTATION_FRONT;
- break;
- case V4L2_FWNODE_ORIENTATION_BACK:
- orientation_ctrl = V4L2_CAMERA_ORIENTATION_BACK;
- break;
- case V4L2_FWNODE_ORIENTATION_EXTERNAL:
- orientation_ctrl = V4L2_CAMERA_ORIENTATION_EXTERNAL;
- break;
- default:
- return -EINVAL;
- }
- if (!v4l2_ctrl_new_std_menu(hdl, ctrl_ops,
- V4L2_CID_CAMERA_ORIENTATION,
- V4L2_CAMERA_ORIENTATION_EXTERNAL, 0,
- orientation_ctrl))
- return hdl->error;
- }
- if (p->rotation != V4L2_FWNODE_PROPERTY_UNSET) {
- if (!v4l2_ctrl_new_std(hdl, ctrl_ops,
- V4L2_CID_CAMERA_SENSOR_ROTATION,
- p->rotation, p->rotation, 1,
- p->rotation))
- return hdl->error;
- }
- return hdl->error;
- }
- EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties);
|