| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298 |
- /**
- * \file xf86drm.c
- * User-level interface to DRM device
- *
- */
- /*
- * SPDX-FileContributor: Rickard E. (Rik) Faith <faith@valinux.com>
- * SPDX-FileContributor: Kevin E. Martin <martin@valinux.com>
- * SPDX-FileCopyrightText: 1999 Precision Insight, Inc., Cedar Park, Texas.
- * SPDX-FileCopyrightText: 2000 VA Linux Systems, Inc., Sunnyvale, California.
- * SPDX-License-Identifier: MIT
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <unistd.h>
- #include <string.h>
- #include <strings.h>
- #include <ctype.h>
- #include <dirent.h>
- #include <stddef.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <libgen.h>
- #include <limits.h>
- #include <signal.h>
- #include <time.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #define stat_t struct stat
- #include <sys/ioctl.h>
- #include <sys/time.h>
- #include <stdarg.h>
- #ifdef MAJOR_IN_MKDEV
- #include <sys/mkdev.h>
- #endif
- #ifdef MAJOR_IN_SYSMACROS
- #include <sys/sysmacros.h>
- #endif
- #if HAVE_SYS_SYSCTL_H
- #include <sys/sysctl.h>
- #endif
- #include <inttypes.h>
- #if defined(__FreeBSD__)
- #include <sys/param.h>
- #include <sys/pciio.h>
- #endif
- #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
- /* Not all systems have MAP_FAILED defined */
- #ifndef MAP_FAILED
- #define MAP_FAILED ((void *)-1)
- #endif
- #include "xf86drm.h"
- #include "libdrm_macros.h"
- #include "drm_fourcc.h"
- #include "util_math.h"
- #ifdef __DragonFly__
- #define DRM_MAJOR 145
- #endif
- #ifdef __NetBSD__
- #define DRM_MAJOR 34
- #endif
- #ifdef __OpenBSD__
- #ifdef __i386__
- #define DRM_MAJOR 88
- #else
- #define DRM_MAJOR 87
- #endif
- #endif /* __OpenBSD__ */
- #ifndef DRM_MAJOR
- #define DRM_MAJOR 226 /* Linux */
- #endif
- #if defined(__OpenBSD__) || defined(__DragonFly__)
- struct drm_pciinfo {
- uint16_t domain;
- uint8_t bus;
- uint8_t dev;
- uint8_t func;
- uint16_t vendor_id;
- uint16_t device_id;
- uint16_t subvendor_id;
- uint16_t subdevice_id;
- uint8_t revision_id;
- };
- #define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo)
- #endif
- #define DRM_MSG_VERBOSITY 3
- #define memclear(s) memset(&s, 0, sizeof(s))
- static drmServerInfoPtr drm_server_info;
- static bool drmNodeIsDRM(int maj, int min);
- static char *drmGetMinorNameForFD(int fd, int type);
- #define DRM_MODIFIER(v, f, f_name) \
- .modifier = DRM_FORMAT_MOD_##v ## _ ##f, \
- .modifier_name = #f_name
- #define DRM_MODIFIER_INVALID(v, f_name) \
- .modifier = DRM_FORMAT_MOD_INVALID, .modifier_name = #f_name
- #define DRM_MODIFIER_LINEAR(v, f_name) \
- .modifier = DRM_FORMAT_MOD_LINEAR, .modifier_name = #f_name
- /* Intel is abit special as the format doesn't follow other vendors naming
- * scheme */
- #define DRM_MODIFIER_INTEL(f, f_name) \
- .modifier = I915_FORMAT_MOD_##f, .modifier_name = #f_name
- struct drmFormatModifierInfo {
- uint64_t modifier;
- const char *modifier_name;
- };
- struct drmFormatModifierVendorInfo {
- uint8_t vendor;
- const char *vendor_name;
- };
- #include "generated_static_table_fourcc.h"
- struct drmVendorInfo {
- uint8_t vendor;
- char *(*vendor_cb)(uint64_t modifier);
- };
- struct drmFormatVendorModifierInfo {
- uint64_t modifier;
- const char *modifier_name;
- };
- static char *
- drmGetFormatModifierNameFromArm(uint64_t modifier);
- static char *
- drmGetFormatModifierNameFromNvidia(uint64_t modifier);
- static char *
- drmGetFormatModifierNameFromAmd(uint64_t modifier);
- static char *
- drmGetFormatModifierNameFromAmlogic(uint64_t modifier);
- static char *
- drmGetFormatModifierNameFromVivante(uint64_t modifier);
- static const struct drmVendorInfo modifier_format_vendor_table[] = {
- { DRM_FORMAT_MOD_VENDOR_ARM, drmGetFormatModifierNameFromArm },
- { DRM_FORMAT_MOD_VENDOR_NVIDIA, drmGetFormatModifierNameFromNvidia },
- { DRM_FORMAT_MOD_VENDOR_AMD, drmGetFormatModifierNameFromAmd },
- { DRM_FORMAT_MOD_VENDOR_AMLOGIC, drmGetFormatModifierNameFromAmlogic },
- { DRM_FORMAT_MOD_VENDOR_VIVANTE, drmGetFormatModifierNameFromVivante },
- };
- #ifndef AFBC_FORMAT_MOD_MODE_VALUE_MASK
- #define AFBC_FORMAT_MOD_MODE_VALUE_MASK 0x000fffffffffffffULL
- #endif
- static const struct drmFormatVendorModifierInfo arm_mode_value_table[] = {
- { AFBC_FORMAT_MOD_YTR, "YTR" },
- { AFBC_FORMAT_MOD_SPLIT, "SPLIT" },
- { AFBC_FORMAT_MOD_SPARSE, "SPARSE" },
- { AFBC_FORMAT_MOD_CBR, "CBR" },
- { AFBC_FORMAT_MOD_TILED, "TILED" },
- { AFBC_FORMAT_MOD_SC, "SC" },
- { AFBC_FORMAT_MOD_DB, "DB" },
- { AFBC_FORMAT_MOD_BCH, "BCH" },
- { AFBC_FORMAT_MOD_USM, "USM" },
- };
- static bool
- drmGetAfbcFormatModifierNameFromArm(uint64_t modifier, FILE *fp)
- {
- uint64_t mode_value = modifier & AFBC_FORMAT_MOD_MODE_VALUE_MASK;
- uint64_t block_size = mode_value & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
- const char *block = NULL;
- const char *mode = NULL;
- bool did_print_mode = false;
- /* add block, can only have a (single) block */
- switch (block_size) {
- case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
- block = "16x16";
- break;
- case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
- block = "32x8";
- break;
- case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
- block = "64x4";
- break;
- case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
- block = "32x8_64x4";
- break;
- }
- if (!block) {
- return false;
- }
- fprintf(fp, "BLOCK_SIZE=%s,", block);
- /* add mode */
- for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_value_table); i++) {
- if (arm_mode_value_table[i].modifier & mode_value) {
- mode = arm_mode_value_table[i].modifier_name;
- if (!did_print_mode) {
- fprintf(fp, "MODE=%s", mode);
- did_print_mode = true;
- } else {
- fprintf(fp, "|%s", mode);
- }
- }
- }
- return true;
- }
- static bool
- drmGetAfrcFormatModifierNameFromArm(uint64_t modifier, FILE *fp)
- {
- bool scan_layout;
- for (unsigned int i = 0; i < 2; ++i) {
- uint64_t coding_unit_block =
- (modifier >> (i * 4)) & AFRC_FORMAT_MOD_CU_SIZE_MASK;
- const char *coding_unit_size = NULL;
- switch (coding_unit_block) {
- case AFRC_FORMAT_MOD_CU_SIZE_16:
- coding_unit_size = "CU_16";
- break;
- case AFRC_FORMAT_MOD_CU_SIZE_24:
- coding_unit_size = "CU_24";
- break;
- case AFRC_FORMAT_MOD_CU_SIZE_32:
- coding_unit_size = "CU_32";
- break;
- }
- if (!coding_unit_size) {
- if (i == 0) {
- return false;
- }
- break;
- }
- if (i == 0) {
- fprintf(fp, "P0=%s,", coding_unit_size);
- } else {
- fprintf(fp, "P12=%s,", coding_unit_size);
- }
- }
- scan_layout =
- (modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN) == AFRC_FORMAT_MOD_LAYOUT_SCAN;
- if (scan_layout) {
- fprintf(fp, "SCAN");
- } else {
- fprintf(fp, "ROT");
- }
- return true;
- }
- static char *
- drmGetFormatModifierNameFromArm(uint64_t modifier)
- {
- uint64_t type = (modifier >> 52) & 0xf;
- FILE *fp;
- size_t size = 0;
- char *modifier_name = NULL;
- bool result = false;
- fp = open_memstream(&modifier_name, &size);
- if (!fp)
- return NULL;
- switch (type) {
- case DRM_FORMAT_MOD_ARM_TYPE_AFBC:
- result = drmGetAfbcFormatModifierNameFromArm(modifier, fp);
- break;
- case DRM_FORMAT_MOD_ARM_TYPE_AFRC:
- result = drmGetAfrcFormatModifierNameFromArm(modifier, fp);
- break;
- /* misc type is already handled by the static table */
- case DRM_FORMAT_MOD_ARM_TYPE_MISC:
- default:
- result = false;
- break;
- }
- fclose(fp);
- if (!result) {
- free(modifier_name);
- return NULL;
- }
- return modifier_name;
- }
- static char *
- drmGetFormatModifierNameFromNvidia(uint64_t modifier)
- {
- uint64_t height, kind, gen, sector, compression;
- height = modifier & 0xf;
- kind = (modifier >> 12) & 0xff;
- gen = (modifier >> 20) & 0x3;
- sector = (modifier >> 22) & 0x1;
- compression = (modifier >> 23) & 0x7;
- /* just in case there could other simpler modifiers, not yet added, avoid
- * testing against TEGRA_TILE */
- if ((modifier & 0x10) == 0x10) {
- char *mod_nvidia;
- if (asprintf(&mod_nvidia, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64",KIND=%"PRIu64","
- "GEN=%"PRIu64",SECTOR=%"PRIu64",COMPRESSION=%"PRIu64"", height,
- kind, gen, sector, compression) < 0)
- mod_nvidia = NULL;
- return mod_nvidia;
- }
- return NULL;
- }
- static char *
- drmGetFormatModifierNameFromAmd(uint64_t modifier)
- {
- static const char *gfx9_gfx11_tile_strings[32] = {
- "LINEAR",
- "256B_S",
- "256B_D",
- "256B_R",
- "4KB_Z",
- "4KB_S",
- "4KB_D",
- "4KB_R",
- "64KB_Z",
- "64KB_S",
- "64KB_D",
- "64KB_R",
- "INVALID12",
- "INVALID13",
- "INVALID14",
- "INVALID15",
- "64KB_Z_T",
- "64KB_S_T",
- "64KB_D_T",
- "64KB_R_T",
- "4KB_Z_X",
- "4KB_S_X",
- "4KB_D_X",
- "4KB_R_X",
- "64KB_Z_X",
- "64KB_S_X",
- "64KB_D_X",
- "64KB_R_X",
- "256KB_Z_X",
- "256KB_S_X",
- "256KB_D_X",
- "256KB_R_X",
- };
- static const char *gfx12_tile_strings[32] = {
- "LINEAR",
- "256B_2D",
- "4KB_2D",
- "64KB_2D",
- "256KB_2D",
- "4KB_3D",
- "64KB_3D",
- "256KB_3D",
- /* other values are unused */
- };
- uint64_t tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier);
- FILE *fp;
- char *mod_amd = NULL;
- size_t size = 0;
- fp = open_memstream(&mod_amd, &size);
- if (!fp)
- return NULL;
- switch (tile_version) {
- case AMD_FMT_MOD_TILE_VER_GFX9:
- fprintf(fp, "GFX9");
- break;
- case AMD_FMT_MOD_TILE_VER_GFX10:
- fprintf(fp, "GFX10");
- break;
- case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS:
- fprintf(fp, "GFX10_RBPLUS");
- break;
- case AMD_FMT_MOD_TILE_VER_GFX11:
- fprintf(fp, "GFX11");
- break;
- case AMD_FMT_MOD_TILE_VER_GFX12:
- fprintf(fp, "GFX12");
- break;
- default:
- fclose(fp);
- free(mod_amd);
- return NULL;
- }
- if (tile_version >= AMD_FMT_MOD_TILE_VER_GFX12) {
- unsigned tile = AMD_FMT_MOD_GET(TILE, modifier);
- fprintf(fp, ",%s", gfx12_tile_strings[tile]);
- if (AMD_FMT_MOD_GET(DCC, modifier)) {
- fprintf(fp, ",DCC,DCC_MAX_COMPRESSED_BLOCK=%uB",
- 64 << AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier));
- /* Other DCC fields are unused by GFX12. */
- }
- } else {
- unsigned tile = AMD_FMT_MOD_GET(TILE, modifier);
- fprintf(fp, ",%s", gfx9_gfx11_tile_strings[tile]);
- /* All *_T and *_X modes are affected by chip-specific fields. */
- if (tile >= 16) {
- fprintf(fp, ",PIPE_XOR_BITS=%u",
- (unsigned)AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier));
- switch (tile_version) {
- case AMD_FMT_MOD_TILE_VER_GFX9:
- fprintf(fp, ",BANK_XOR_BITS=%u",
- (unsigned)AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier));
- break;
- case AMD_FMT_MOD_TILE_VER_GFX10:
- /* Nothing else for GFX10. */
- break;
- case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS:
- case AMD_FMT_MOD_TILE_VER_GFX11:
- /* This also determines the DCC layout, but DCC is only legal
- * with tile=27 and tile=31 (*_R_X modes).
- */
- fprintf(fp, ",PACKERS=%u",
- (unsigned)AMD_FMT_MOD_GET(PACKERS, modifier));
- break;
- }
- }
- if (AMD_FMT_MOD_GET(DCC, modifier)) {
- if (tile_version == AMD_FMT_MOD_TILE_VER_GFX9 &&
- (AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier) ||
- AMD_FMT_MOD_GET(DCC_RETILE, modifier))) {
- /* These two only determine the layout of
- * the non-displayable DCC plane.
- */
- fprintf(fp, ",RB=%u",
- (unsigned)AMD_FMT_MOD_GET(RB, modifier));
- fprintf(fp, ",PIPE=%u",
- (unsigned)AMD_FMT_MOD_GET(PIPE, modifier));
- }
- fprintf(fp, ",DCC,DCC_MAX_COMPRESSED_BLOCK=%uB",
- 64 << AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier));
- if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier))
- fprintf(fp, ",DCC_INDEPENDENT_64B");
- if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier))
- fprintf(fp, ",DCC_INDEPENDENT_128B");
- if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE, modifier))
- fprintf(fp, ",DCC_CONSTANT_ENCODE");
- if (AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier))
- fprintf(fp, ",DCC_PIPE_ALIGN");
- if (AMD_FMT_MOD_GET(DCC_RETILE, modifier))
- fprintf(fp, ",DCC_RETILE");
- }
- }
- fclose(fp);
- return mod_amd;
- }
- static char *
- drmGetFormatModifierNameFromAmlogic(uint64_t modifier)
- {
- uint64_t layout = modifier & 0xff;
- uint64_t options = (modifier >> 8) & 0xff;
- char *mod_amlogic = NULL;
- const char *layout_str;
- const char *opts_str;
- switch (layout) {
- case AMLOGIC_FBC_LAYOUT_BASIC:
- layout_str = "BASIC";
- break;
- case AMLOGIC_FBC_LAYOUT_SCATTER:
- layout_str = "SCATTER";
- break;
- default:
- layout_str = "INVALID_LAYOUT";
- break;
- }
- if (options & AMLOGIC_FBC_OPTION_MEM_SAVING)
- opts_str = "MEM_SAVING";
- else
- opts_str = "0";
- if (asprintf(&mod_amlogic, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str, opts_str) < 0)
- mod_amlogic = NULL;
- return mod_amlogic;
- }
- static char *
- drmGetFormatModifierNameFromVivante(uint64_t modifier)
- {
- const char *color_tiling, *tile_status, *compression;
- char *mod_vivante = NULL;
- switch (modifier & VIVANTE_MOD_TS_MASK) {
- case 0:
- tile_status = "";
- break;
- case VIVANTE_MOD_TS_64_4:
- tile_status = ",TS=64B_4";
- break;
- case VIVANTE_MOD_TS_64_2:
- tile_status = ",TS=64B_2";
- break;
- case VIVANTE_MOD_TS_128_4:
- tile_status = ",TS=128B_4";
- break;
- case VIVANTE_MOD_TS_256_4:
- tile_status = ",TS=256B_4";
- break;
- default:
- tile_status = ",TS=UNKNOWN";
- break;
- }
- switch (modifier & VIVANTE_MOD_COMP_MASK) {
- case 0:
- compression = "";
- break;
- case VIVANTE_MOD_COMP_DEC400:
- compression = ",COMP=DEC400";
- break;
- default:
- compression = ",COMP=UNKNOWN";
- break;
- }
- switch (modifier & ~VIVANTE_MOD_EXT_MASK) {
- case 0:
- color_tiling = "LINEAR";
- break;
- case DRM_FORMAT_MOD_VIVANTE_TILED:
- color_tiling = "TILED";
- break;
- case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
- color_tiling = "SUPER_TILED";
- break;
- case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
- color_tiling = "SPLIT_TILED";
- break;
- case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
- color_tiling = "SPLIT_SUPER_TILED";
- break;
- default:
- color_tiling = "UNKNOWN";
- break;
- }
- if (asprintf(&mod_vivante, "%s%s%s", color_tiling, tile_status, compression) < 0)
- mod_vivante = NULL;
- return mod_vivante;
- }
- static unsigned log2_int(unsigned x)
- {
- unsigned l;
- if (x < 2) {
- return 0;
- }
- for (l = 2; ; l++) {
- if ((unsigned)(1 << l) > x) {
- return l - 1;
- }
- }
- return 0;
- }
- drm_public void drmSetServerInfo(drmServerInfoPtr info)
- {
- drm_server_info = info;
- }
- /**
- * Output a message to stderr.
- *
- * \param format printf() like format string.
- *
- * \internal
- * This function is a wrapper around vfprintf().
- */
- static int DRM_PRINTFLIKE(1, 0)
- drmDebugPrint(const char *format, va_list ap)
- {
- return vfprintf(stderr, format, ap);
- }
- drm_public void
- drmMsg(const char *format, ...)
- {
- va_list ap;
- const char *env;
- if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
- (drm_server_info && drm_server_info->debug_print))
- {
- va_start(ap, format);
- if (drm_server_info) {
- drm_server_info->debug_print(format,ap);
- } else {
- drmDebugPrint(format, ap);
- }
- va_end(ap);
- }
- }
- static void *drmHashTable = NULL; /* Context switch callbacks */
- drm_public void *drmGetHashTable(void)
- {
- return drmHashTable;
- }
- drm_public void *drmMalloc(int size)
- {
- return calloc(1, size);
- }
- drm_public void drmFree(void *pt)
- {
- free(pt);
- }
- /**
- * Call ioctl, restarting if it is interrupted
- */
- drm_public int
- drmIoctl(int fd, unsigned long request, void *arg)
- {
- int ret;
- do {
- ret = ioctl(fd, request, arg);
- } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
- return ret;
- }
- static unsigned long drmGetKeyFromFd(int fd)
- {
- stat_t st;
- st.st_rdev = 0;
- fstat(fd, &st);
- return st.st_rdev;
- }
- drm_public drmHashEntry *drmGetEntry(int fd)
- {
- unsigned long key = drmGetKeyFromFd(fd);
- void *value;
- drmHashEntry *entry;
- if (!drmHashTable)
- drmHashTable = drmHashCreate();
- if (drmHashLookup(drmHashTable, key, &value)) {
- entry = drmMalloc(sizeof(*entry));
- entry->fd = fd;
- entry->f = NULL;
- entry->tagTable = drmHashCreate();
- drmHashInsert(drmHashTable, key, entry);
- } else {
- entry = value;
- }
- return entry;
- }
- /**
- * Compare two busid strings
- *
- * \param first
- * \param second
- *
- * \return 1 if matched.
- *
- * \internal
- * This function compares two bus ID strings. It understands the older
- * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is
- * domain, b is bus, d is device, f is function.
- */
- static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
- {
- /* First, check if the IDs are exactly the same */
- if (strcasecmp(id1, id2) == 0)
- return 1;
- /* Try to match old/new-style PCI bus IDs. */
- if (strncasecmp(id1, "pci", 3) == 0) {
- unsigned int o1, b1, d1, f1;
- unsigned int o2, b2, d2, f2;
- int ret;
- ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
- if (ret != 4) {
- o1 = 0;
- ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
- if (ret != 3)
- return 0;
- }
- ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
- if (ret != 4) {
- o2 = 0;
- ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
- if (ret != 3)
- return 0;
- }
- /* If domains aren't properly supported by the kernel interface,
- * just ignore them, which sucks less than picking a totally random
- * card with "open by name"
- */
- if (!pci_domain_ok)
- o1 = o2 = 0;
- if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
- return 0;
- else
- return 1;
- }
- return 0;
- }
- /**
- * Handles error checking for chown call.
- *
- * \param path to file.
- * \param id of the new owner.
- * \param id of the new group.
- *
- * \return zero if success or -1 if failure.
- *
- * \internal
- * Checks for failure. If failure was caused by signal call chown again.
- * If any other failure happened then it will output error message using
- * drmMsg() call.
- */
- #if !UDEV
- static int chown_check_return(const char *path, uid_t owner, gid_t group)
- {
- int rv;
- do {
- rv = chown(path, owner, group);
- } while (rv != 0 && errno == EINTR);
- if (rv == 0)
- return 0;
- drmMsg("Failed to change owner or group for file %s! %d: %s\n",
- path, errno, strerror(errno));
- return -1;
- }
- #endif
- static const char *drmGetDeviceName(int type)
- {
- switch (type) {
- case DRM_NODE_PRIMARY:
- return DRM_DEV_NAME;
- case DRM_NODE_RENDER:
- return DRM_RENDER_DEV_NAME;
- }
- return NULL;
- }
- /**
- * Open the DRM device, creating it if necessary.
- *
- * \param dev major and minor numbers of the device.
- * \param minor minor number of the device.
- *
- * \return a file descriptor on success, or a negative value on error.
- *
- * \internal
- * Assembles the device name from \p minor and opens it, creating the device
- * special file node with the major and minor numbers specified by \p dev and
- * parent directory if necessary and was called by root.
- */
- static int drmOpenDevice(dev_t dev, int minor, int type)
- {
- stat_t st;
- const char *dev_name = drmGetDeviceName(type);
- char buf[DRM_NODE_NAME_MAX];
- int fd;
- mode_t devmode = DRM_DEV_MODE, serv_mode;
- gid_t serv_group;
- #if !UDEV
- int isroot = !geteuid();
- uid_t user = DRM_DEV_UID;
- gid_t group = DRM_DEV_GID;
- #endif
- if (!dev_name)
- return -EINVAL;
- sprintf(buf, dev_name, DRM_DIR_NAME, minor);
- drmMsg("drmOpenDevice: node name is %s\n", buf);
- if (drm_server_info && drm_server_info->get_perms) {
- drm_server_info->get_perms(&serv_group, &serv_mode);
- devmode = serv_mode ? serv_mode : DRM_DEV_MODE;
- devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
- }
- #if !UDEV
- if (stat(DRM_DIR_NAME, &st)) {
- if (!isroot)
- return DRM_ERR_NOT_ROOT;
- mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
- chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
- chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
- }
- /* Check if the device node exists and create it if necessary. */
- if (stat(buf, &st)) {
- if (!isroot)
- return DRM_ERR_NOT_ROOT;
- remove(buf);
- mknod(buf, S_IFCHR | devmode, dev);
- }
- if (drm_server_info && drm_server_info->get_perms) {
- group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
- chown_check_return(buf, user, group);
- chmod(buf, devmode);
- }
- #else
- /* if we modprobed then wait for udev */
- {
- int udev_count = 0;
- wait_for_udev:
- if (stat(DRM_DIR_NAME, &st)) {
- usleep(20);
- udev_count++;
- if (udev_count == 50)
- return -1;
- goto wait_for_udev;
- }
- if (stat(buf, &st)) {
- usleep(20);
- udev_count++;
- if (udev_count == 50)
- return -1;
- goto wait_for_udev;
- }
- }
- #endif
- fd = open(buf, O_RDWR | O_CLOEXEC);
- drmMsg("drmOpenDevice: open result is %d, (%s)\n",
- fd, fd < 0 ? strerror(errno) : "OK");
- if (fd >= 0)
- return fd;
- #if !UDEV
- /* Check if the device node is not what we expect it to be, and recreate it
- * and try again if so.
- */
- if (st.st_rdev != dev) {
- if (!isroot)
- return DRM_ERR_NOT_ROOT;
- remove(buf);
- mknod(buf, S_IFCHR | devmode, dev);
- if (drm_server_info && drm_server_info->get_perms) {
- chown_check_return(buf, user, group);
- chmod(buf, devmode);
- }
- }
- fd = open(buf, O_RDWR | O_CLOEXEC);
- drmMsg("drmOpenDevice: open result is %d, (%s)\n",
- fd, fd < 0 ? strerror(errno) : "OK");
- if (fd >= 0)
- return fd;
- drmMsg("drmOpenDevice: Open failed\n");
- remove(buf);
- #endif
- return -errno;
- }
- /**
- * Open the DRM device
- *
- * \param minor device minor number.
- * \param create allow to create the device if set.
- *
- * \return a file descriptor on success, or a negative value on error.
- *
- * \internal
- * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
- * name from \p minor and opens it.
- */
- static int drmOpenMinor(int minor, int create, int type)
- {
- int fd;
- char buf[DRM_NODE_NAME_MAX];
- const char *dev_name = drmGetDeviceName(type);
- if (create)
- return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
- if (!dev_name)
- return -EINVAL;
- sprintf(buf, dev_name, DRM_DIR_NAME, minor);
- if ((fd = open(buf, O_RDWR | O_CLOEXEC)) >= 0)
- return fd;
- return -errno;
- }
- /**
- * Determine whether the DRM kernel driver has been loaded.
- *
- * \return 1 if the DRM driver is loaded, 0 otherwise.
- *
- * \deprecated
- * This function doesn't work when a device goes away (as is often the case
- * with simpledrm). drmGetDevices2 should be used instead to enumerate DRM
- * devices.
- *
- * \internal
- * Determine the presence of the kernel driver by attempting to open the 0
- * minor and get version information. For backward compatibility with older
- * Linux implementations, /proc/dri is also checked.
- */
- drm_public int drmAvailable(void)
- {
- drmVersionPtr version;
- int retval = 0;
- int fd;
- if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
- #ifdef __linux__
- /* Try proc for backward Linux compatibility */
- if (!access("/proc/dri/0", R_OK))
- return 1;
- #endif
- return 0;
- }
- if ((version = drmGetVersion(fd))) {
- retval = 1;
- drmFreeVersion(version);
- }
- close(fd);
- return retval;
- }
- static int drmGetMinorBase(int type)
- {
- switch (type) {
- case DRM_NODE_PRIMARY:
- return 0;
- case DRM_NODE_RENDER:
- return 128;
- default:
- return -1;
- };
- }
- static int drmGetMinorType(int major, int minor)
- {
- #ifdef __FreeBSD__
- char name[SPECNAMELEN];
- int id;
- if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name)))
- return -1;
- if (sscanf(name, "drm/%d", &id) != 1) {
- // If not in /dev/drm/ we have the type in the name
- if (sscanf(name, "dri/card%d\n", &id) >= 1)
- return DRM_NODE_PRIMARY;
- else if (sscanf(name, "dri/renderD%d\n", &id) >= 1)
- return DRM_NODE_RENDER;
- return -1;
- }
- minor = id;
- #endif
- char path[DRM_NODE_NAME_MAX];
- const char *dev_name;
- int i;
- for (i = DRM_NODE_PRIMARY; i < DRM_NODE_MAX; i++) {
- dev_name = drmGetDeviceName(i);
- if (!dev_name)
- continue;
- snprintf(path, sizeof(path), dev_name, DRM_DIR_NAME, minor);
- if (!access(path, F_OK))
- return i;
- }
- return -1;
- }
- static const char *drmGetMinorName(int type)
- {
- switch (type) {
- case DRM_NODE_PRIMARY:
- return DRM_PRIMARY_MINOR_NAME;
- case DRM_NODE_RENDER:
- return DRM_RENDER_MINOR_NAME;
- default:
- return NULL;
- }
- }
- /**
- * Open the device by bus ID.
- *
- * \param busid bus ID.
- * \param type device node type.
- *
- * \return a file descriptor on success, or a negative value on error.
- *
- * \internal
- * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
- * comparing the device bus ID with the one supplied.
- *
- * \sa drmOpenMinor() and drmGetBusid().
- */
- static int drmOpenByBusid(const char *busid, int type)
- {
- int i, pci_domain_ok = 1;
- int fd;
- const char *buf;
- drmSetVersion sv;
- int base = drmGetMinorBase(type);
- if (base < 0)
- return -1;
- drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
- for (i = base; i < base + DRM_MAX_MINOR; i++) {
- fd = drmOpenMinor(i, 1, type);
- drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
- if (fd >= 0) {
- /* We need to try for 1.4 first for proper PCI domain support
- * and if that fails, we know the kernel is busted
- */
- sv.drm_di_major = 1;
- sv.drm_di_minor = 4;
- sv.drm_dd_major = -1; /* Don't care */
- sv.drm_dd_minor = -1; /* Don't care */
- if (drmSetInterfaceVersion(fd, &sv)) {
- #ifndef __alpha__
- pci_domain_ok = 0;
- #endif
- sv.drm_di_major = 1;
- sv.drm_di_minor = 1;
- sv.drm_dd_major = -1; /* Don't care */
- sv.drm_dd_minor = -1; /* Don't care */
- drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
- drmSetInterfaceVersion(fd, &sv);
- }
- buf = drmGetBusid(fd);
- drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
- if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
- drmFreeBusid(buf);
- return fd;
- }
- if (buf)
- drmFreeBusid(buf);
- close(fd);
- }
- }
- return -1;
- }
- /**
- * Open the device by name.
- *
- * \param name driver name.
- * \param type the device node type.
- *
- * \return a file descriptor on success, or a negative value on error.
- *
- * \internal
- * This function opens the first minor number that matches the driver name and
- * isn't already in use. If it's in use it then it will already have a bus ID
- * assigned.
- *
- * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
- */
- static int drmOpenByName(const char *name, int type)
- {
- int i;
- int fd;
- drmVersionPtr version;
- char * id;
- int base = drmGetMinorBase(type);
- if (base < 0)
- return -1;
- /*
- * Open the first minor number that matches the driver name and isn't
- * already in use. If it's in use it will have a busid assigned already.
- */
- for (i = base; i < base + DRM_MAX_MINOR; i++) {
- if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
- if ((version = drmGetVersion(fd))) {
- if (!strcmp(version->name, name)) {
- drmFreeVersion(version);
- id = drmGetBusid(fd);
- drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
- if (!id || !*id) {
- if (id)
- drmFreeBusid(id);
- return fd;
- } else {
- drmFreeBusid(id);
- }
- } else {
- drmFreeVersion(version);
- }
- }
- close(fd);
- }
- }
- #ifdef __linux__
- /* Backward-compatibility /proc support */
- for (i = 0; i < 8; i++) {
- char proc_name[64], buf[512];
- char *driver, *pt, *devstring;
- int retcode;
- sprintf(proc_name, "/proc/dri/%d/name", i);
- if ((fd = open(proc_name, O_RDONLY)) >= 0) {
- retcode = read(fd, buf, sizeof(buf)-1);
- close(fd);
- if (retcode > 0) {
- buf[retcode-1] = '\0';
- for (driver = pt = buf; *pt && *pt != ' '; ++pt)
- ;
- if (*pt) { /* Device is next */
- *pt = '\0';
- if (!strcmp(driver, name)) { /* Match */
- for (devstring = ++pt; *pt && *pt != ' '; ++pt)
- ;
- if (*pt) { /* Found busid */
- return drmOpenByBusid(++pt, type);
- } else { /* No busid */
- return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
- }
- }
- }
- }
- }
- }
- #endif
- return -1;
- }
- /**
- * Open the DRM device.
- *
- * Looks up the specified name and bus ID, and opens the device found. The
- * entry in /dev/dri is created if necessary and if called by root.
- *
- * \param name driver name. Not referenced if bus ID is supplied.
- * \param busid bus ID. Zero if not known.
- *
- * \return a file descriptor on success, or a negative value on error.
- *
- * \internal
- * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
- * otherwise.
- */
- drm_public int drmOpen(const char *name, const char *busid)
- {
- return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
- }
- /**
- * Open the DRM device with specified type.
- *
- * Looks up the specified name and bus ID, and opens the device found. The
- * entry in /dev/dri is created if necessary and if called by root.
- *
- * \param name driver name. Not referenced if bus ID is supplied.
- * \param busid bus ID. Zero if not known.
- * \param type the device node type to open, PRIMARY or RENDER
- *
- * \return a file descriptor on success, or a negative value on error.
- *
- * \internal
- * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
- * otherwise.
- */
- drm_public int drmOpenWithType(const char *name, const char *busid, int type)
- {
- if (name != NULL && drm_server_info &&
- drm_server_info->load_module && !drmAvailable()) {
- /* try to load the kernel module */
- if (!drm_server_info->load_module(name)) {
- drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
- return -1;
- }
- }
- if (busid) {
- int fd = drmOpenByBusid(busid, type);
- if (fd >= 0)
- return fd;
- }
- if (name)
- return drmOpenByName(name, type);
- return -1;
- }
- drm_public int drmOpenControl(int minor)
- {
- return -EINVAL;
- }
- drm_public int drmOpenRender(int minor)
- {
- return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
- }
- /**
- * Free the version information returned by drmGetVersion().
- *
- * \param v pointer to the version information.
- *
- * \internal
- * It frees the memory pointed by \p %v as well as all the non-null strings
- * pointers in it.
- */
- drm_public void drmFreeVersion(drmVersionPtr v)
- {
- if (!v)
- return;
- drmFree(v->name);
- drmFree(v->date);
- drmFree(v->desc);
- drmFree(v);
- }
- /**
- * Free the non-public version information returned by the kernel.
- *
- * \param v pointer to the version information.
- *
- * \internal
- * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
- * the non-null strings pointers in it.
- */
- static void drmFreeKernelVersion(drm_version_t *v)
- {
- if (!v)
- return;
- drmFree(v->name);
- drmFree(v->date);
- drmFree(v->desc);
- drmFree(v);
- }
- /**
- * Copy version information.
- *
- * \param d destination pointer.
- * \param s source pointer.
- *
- * \internal
- * Used by drmGetVersion() to translate the information returned by the ioctl
- * interface in a private structure into the public structure counterpart.
- */
- static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
- {
- d->version_major = s->version_major;
- d->version_minor = s->version_minor;
- d->version_patchlevel = s->version_patchlevel;
- d->name_len = s->name_len;
- d->name = s->name ? strdup(s->name) : NULL;
- d->date_len = s->date_len;
- d->date = s->date ? strdup(s->date) : NULL;
- d->desc_len = s->desc_len;
- d->desc = s->desc ? strdup(s->desc) : NULL;
- }
- /**
- * Query the driver version information.
- *
- * \param fd file descriptor.
- *
- * \return pointer to a drmVersion structure which should be freed with
- * drmFreeVersion().
- *
- * \note Similar information is available via /proc/dri.
- *
- * \internal
- * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
- * first with zeros to get the string lengths, and then the actually strings.
- * It also null-terminates them since they might not be already.
- */
- drm_public drmVersionPtr drmGetVersion(int fd)
- {
- drmVersionPtr retval;
- drm_version_t *version = drmMalloc(sizeof(*version));
- if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
- drmFreeKernelVersion(version);
- return NULL;
- }
- if (version->name_len)
- version->name = drmMalloc(version->name_len + 1);
- if (version->date_len)
- version->date = drmMalloc(version->date_len + 1);
- if (version->desc_len)
- version->desc = drmMalloc(version->desc_len + 1);
- if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
- drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
- drmFreeKernelVersion(version);
- return NULL;
- }
- /* The results might not be null-terminated strings, so terminate them. */
- if (version->name_len) version->name[version->name_len] = '\0';
- if (version->date_len) version->date[version->date_len] = '\0';
- if (version->desc_len) version->desc[version->desc_len] = '\0';
- retval = drmMalloc(sizeof(*retval));
- drmCopyVersion(retval, version);
- drmFreeKernelVersion(version);
- return retval;
- }
- /**
- * Get version information for the DRM user space library.
- *
- * This version number is driver independent.
- *
- * \param fd file descriptor.
- *
- * \return version information.
- *
- * \internal
- * This function allocates and fills a drm_version structure with a hard coded
- * version number.
- */
- drm_public drmVersionPtr drmGetLibVersion(int fd)
- {
- drm_version_t *version = drmMalloc(sizeof(*version));
- /* Version history:
- * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
- * revision 1.0.x = original DRM interface with no drmGetLibVersion
- * entry point and many drm<Device> extensions
- * revision 1.1.x = added drmCommand entry points for device extensions
- * added drmGetLibVersion to identify libdrm.a version
- * revision 1.2.x = added drmSetInterfaceVersion
- * modified drmOpen to handle both busid and name
- * revision 1.3.x = added server + memory manager
- */
- version->version_major = 1;
- version->version_minor = 3;
- version->version_patchlevel = 0;
- return (drmVersionPtr)version;
- }
- drm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value)
- {
- struct drm_get_cap cap;
- int ret;
- memclear(cap);
- cap.capability = capability;
- ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
- if (ret)
- return ret;
- *value = cap.value;
- return 0;
- }
- drm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
- {
- struct drm_set_client_cap cap;
- memclear(cap);
- cap.capability = capability;
- cap.value = value;
- return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
- }
- /**
- * Free the bus ID information.
- *
- * \param busid bus ID information string as given by drmGetBusid().
- *
- * \internal
- * This function is just frees the memory pointed by \p busid.
- */
- drm_public void drmFreeBusid(const char *busid)
- {
- drmFree((void *)busid);
- }
- /**
- * Get the bus ID of the device.
- *
- * \param fd file descriptor.
- *
- * \return bus ID string.
- *
- * \internal
- * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
- * get the string length and data, passing the arguments in a drm_unique
- * structure.
- */
- drm_public char *drmGetBusid(int fd)
- {
- drm_unique_t u;
- memclear(u);
- if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
- return NULL;
- u.unique = drmMalloc(u.unique_len + 1);
- if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) {
- drmFree(u.unique);
- return NULL;
- }
- u.unique[u.unique_len] = '\0';
- return u.unique;
- }
- /**
- * Set the bus ID of the device.
- *
- * \param fd file descriptor.
- * \param busid bus ID string.
- *
- * \return zero on success, negative on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
- * the arguments in a drm_unique structure.
- */
- drm_public int drmSetBusid(int fd, const char *busid)
- {
- drm_unique_t u;
- memclear(u);
- u.unique = (char *)busid;
- u.unique_len = strlen(busid);
- if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
- return -errno;
- }
- return 0;
- }
- drm_public int drmGetMagic(int fd, drm_magic_t * magic)
- {
- drm_auth_t auth;
- memclear(auth);
- *magic = 0;
- if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
- return -errno;
- *magic = auth.magic;
- return 0;
- }
- drm_public int drmAuthMagic(int fd, drm_magic_t magic)
- {
- drm_auth_t auth;
- memclear(auth);
- auth.magic = magic;
- if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
- return -errno;
- return 0;
- }
- /**
- * Specifies a range of memory that is available for mapping by a
- * non-root process.
- *
- * \param fd file descriptor.
- * \param offset usually the physical address. The actual meaning depends of
- * the \p type parameter. See below.
- * \param size of the memory in bytes.
- * \param type type of the memory to be mapped.
- * \param flags combination of several flags to modify the function actions.
- * \param handle will be set to a value that may be used as the offset
- * parameter for mmap().
- *
- * \return zero on success or a negative value on error.
- *
- * \par Mapping the frame buffer
- * For the frame buffer
- * - \p offset will be the physical address of the start of the frame buffer,
- * - \p size will be the size of the frame buffer in bytes, and
- * - \p type will be DRM_FRAME_BUFFER.
- *
- * \par
- * The area mapped will be uncached. If MTRR support is available in the
- * kernel, the frame buffer area will be set to write combining.
- *
- * \par Mapping the MMIO register area
- * For the MMIO register area,
- * - \p offset will be the physical address of the start of the register area,
- * - \p size will be the size of the register area bytes, and
- * - \p type will be DRM_REGISTERS.
- * \par
- * The area mapped will be uncached.
- *
- * \par Mapping the SAREA
- * For the SAREA,
- * - \p offset will be ignored and should be set to zero,
- * - \p size will be the desired size of the SAREA in bytes,
- * - \p type will be DRM_SHM.
- *
- * \par
- * A shared memory area of the requested size will be created and locked in
- * kernel memory. This area may be mapped into client-space by using the handle
- * returned.
- *
- * \note May only be called by root.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
- * the arguments in a drm_map structure.
- */
- drm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
- drmMapFlags flags, drm_handle_t *handle)
- {
- drm_map_t map;
- memclear(map);
- map.offset = offset;
- map.size = size;
- map.type = (enum drm_map_type)type;
- map.flags = (enum drm_map_flags)flags;
- if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
- return -errno;
- if (handle)
- *handle = (drm_handle_t)(uintptr_t)map.handle;
- return 0;
- }
- drm_public int drmRmMap(int fd, drm_handle_t handle)
- {
- drm_map_t map;
- memclear(map);
- map.handle = (void *)(uintptr_t)handle;
- if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
- return -errno;
- return 0;
- }
- /**
- * Make buffers available for DMA transfers.
- *
- * \param fd file descriptor.
- * \param count number of buffers.
- * \param size size of each buffer.
- * \param flags buffer allocation flags.
- * \param agp_offset offset in the AGP aperture
- *
- * \return number of buffers allocated, negative on error.
- *
- * \internal
- * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
- *
- * \sa drm_buf_desc.
- */
- drm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
- int agp_offset)
- {
- drm_buf_desc_t request;
- memclear(request);
- request.count = count;
- request.size = size;
- request.flags = (int)flags;
- request.agp_start = agp_offset;
- if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
- return -errno;
- return request.count;
- }
- drm_public int drmMarkBufs(int fd, double low, double high)
- {
- drm_buf_info_t info;
- int i;
- memclear(info);
- if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
- return -EINVAL;
- if (!info.count)
- return -EINVAL;
- if (!(info.list = calloc(info.count, sizeof(*info.list))))
- return -ENOMEM;
- if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
- int retval = -errno;
- drmFree(info.list);
- return retval;
- }
- for (i = 0; i < info.count; i++) {
- info.list[i].low_mark = low * info.list[i].count;
- info.list[i].high_mark = high * info.list[i].count;
- if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
- int retval = -errno;
- drmFree(info.list);
- return retval;
- }
- }
- drmFree(info.list);
- return 0;
- }
- /**
- * Free buffers.
- *
- * \param fd file descriptor.
- * \param count number of buffers to free.
- * \param list list of buffers to be freed.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \note This function is primarily used for debugging.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
- * the arguments in a drm_buf_free structure.
- */
- drm_public int drmFreeBufs(int fd, int count, int *list)
- {
- drm_buf_free_t request;
- memclear(request);
- request.count = count;
- request.list = list;
- if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
- return -errno;
- return 0;
- }
- /**
- * Close the device.
- *
- * \param fd file descriptor.
- *
- * \internal
- * This function closes the file descriptor.
- */
- drm_public int drmClose(int fd)
- {
- unsigned long key = drmGetKeyFromFd(fd);
- drmHashEntry *entry = drmGetEntry(fd);
- drmHashDestroy(entry->tagTable);
- entry->fd = 0;
- entry->f = NULL;
- entry->tagTable = NULL;
- drmHashDelete(drmHashTable, key);
- drmFree(entry);
- return close(fd);
- }
- /**
- * Map a region of memory.
- *
- * \param fd file descriptor.
- * \param handle handle returned by drmAddMap().
- * \param size size in bytes. Must match the size used by drmAddMap().
- * \param address will contain the user-space virtual address where the mapping
- * begins.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper for mmap().
- */
- drm_public int drmMap(int fd, drm_handle_t handle, drmSize size,
- drmAddressPtr address)
- {
- static unsigned long pagesize_mask = 0;
- if (fd < 0)
- return -EINVAL;
- if (!pagesize_mask)
- pagesize_mask = getpagesize() - 1;
- size = (size + pagesize_mask) & ~pagesize_mask;
- *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
- if (*address == MAP_FAILED)
- return -errno;
- return 0;
- }
- /**
- * Unmap mappings obtained with drmMap().
- *
- * \param address address as given by drmMap().
- * \param size size in bytes. Must match the size used by drmMap().
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper for munmap().
- */
- drm_public int drmUnmap(drmAddress address, drmSize size)
- {
- return drm_munmap(address, size);
- }
- drm_public drmBufInfoPtr drmGetBufInfo(int fd)
- {
- drm_buf_info_t info;
- drmBufInfoPtr retval;
- int i;
- memclear(info);
- if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
- return NULL;
- if (info.count) {
- if (!(info.list = calloc(info.count, sizeof(*info.list))))
- return NULL;
- if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
- drmFree(info.list);
- return NULL;
- }
- retval = drmMalloc(sizeof(*retval));
- retval->count = info.count;
- if (!(retval->list = calloc(info.count, sizeof(*retval->list)))) {
- drmFree(retval);
- drmFree(info.list);
- return NULL;
- }
- for (i = 0; i < info.count; i++) {
- retval->list[i].count = info.list[i].count;
- retval->list[i].size = info.list[i].size;
- retval->list[i].low_mark = info.list[i].low_mark;
- retval->list[i].high_mark = info.list[i].high_mark;
- }
- drmFree(info.list);
- return retval;
- }
- return NULL;
- }
- /**
- * Map all DMA buffers into client-virtual space.
- *
- * \param fd file descriptor.
- *
- * \return a pointer to a ::drmBufMap structure.
- *
- * \note The client may not use these buffers until obtaining buffer indices
- * with drmDMA().
- *
- * \internal
- * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
- * information about the buffers in a drm_buf_map structure into the
- * client-visible data structures.
- */
- drm_public drmBufMapPtr drmMapBufs(int fd)
- {
- drm_buf_map_t bufs;
- drmBufMapPtr retval;
- int i;
- memclear(bufs);
- if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
- return NULL;
- if (!bufs.count)
- return NULL;
- if (!(bufs.list = calloc(bufs.count, sizeof(*bufs.list))))
- return NULL;
- if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
- drmFree(bufs.list);
- return NULL;
- }
- retval = drmMalloc(sizeof(*retval));
- retval->count = bufs.count;
- retval->list = calloc(bufs.count, sizeof(*retval->list));
- for (i = 0; i < bufs.count; i++) {
- retval->list[i].idx = bufs.list[i].idx;
- retval->list[i].total = bufs.list[i].total;
- retval->list[i].used = 0;
- retval->list[i].address = bufs.list[i].address;
- }
- drmFree(bufs.list);
- return retval;
- }
- /**
- * Unmap buffers allocated with drmMapBufs().
- *
- * \return zero on success, or negative value on failure.
- *
- * \internal
- * Calls munmap() for every buffer stored in \p bufs and frees the
- * memory allocated by drmMapBufs().
- */
- drm_public int drmUnmapBufs(drmBufMapPtr bufs)
- {
- int i;
- for (i = 0; i < bufs->count; i++) {
- drm_munmap(bufs->list[i].address, bufs->list[i].total);
- }
- drmFree(bufs->list);
- drmFree(bufs);
- return 0;
- }
- #define DRM_DMA_RETRY 16
- /**
- * Reserve DMA buffers.
- *
- * \param fd file descriptor.
- * \param request
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * Assemble the arguments into a drm_dma structure and keeps issuing the
- * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
- */
- drm_public int drmDMA(int fd, drmDMAReqPtr request)
- {
- drm_dma_t dma;
- int ret, i = 0;
- dma.context = request->context;
- dma.send_count = request->send_count;
- dma.send_indices = request->send_list;
- dma.send_sizes = request->send_sizes;
- dma.flags = (enum drm_dma_flags)request->flags;
- dma.request_count = request->request_count;
- dma.request_size = request->request_size;
- dma.request_indices = request->request_list;
- dma.request_sizes = request->request_sizes;
- dma.granted_count = 0;
- do {
- ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
- } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
- if ( ret == 0 ) {
- request->granted_count = dma.granted_count;
- return 0;
- } else {
- return -errno;
- }
- }
- /**
- * Obtain heavyweight hardware lock.
- *
- * \param fd file descriptor.
- * \param context context.
- * \param flags flags that determine the state of the hardware when the function
- * returns.
- *
- * \return always zero.
- *
- * \internal
- * This function translates the arguments into a drm_lock structure and issue
- * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
- */
- drm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
- {
- drm_lock_t lock;
- memclear(lock);
- lock.context = context;
- lock.flags = 0;
- if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
- if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
- if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
- if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
- if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
- if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
- while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
- ;
- return 0;
- }
- /**
- * Release the hardware lock.
- *
- * \param fd file descriptor.
- * \param context context.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
- * argument in a drm_lock structure.
- */
- drm_public int drmUnlock(int fd, drm_context_t context)
- {
- drm_lock_t lock;
- memclear(lock);
- lock.context = context;
- return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
- }
- drm_public drm_context_t *drmGetReservedContextList(int fd, int *count)
- {
- drm_ctx_res_t res;
- drm_ctx_t *list;
- drm_context_t * retval;
- int i;
- memclear(res);
- if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
- return NULL;
- if (!res.count)
- return NULL;
- if (!(list = calloc(res.count, sizeof(*list))))
- return NULL;
- if (!(retval = calloc(res.count, sizeof(*retval))))
- goto err_free_list;
- res.contexts = list;
- if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
- goto err_free_context;
- for (i = 0; i < res.count; i++)
- retval[i] = list[i].handle;
- drmFree(list);
- *count = res.count;
- return retval;
- err_free_list:
- drmFree(list);
- err_free_context:
- drmFree(retval);
- return NULL;
- }
- drm_public void drmFreeReservedContextList(drm_context_t *pt)
- {
- drmFree(pt);
- }
- /**
- * Create context.
- *
- * Used by the X server during GLXContext initialization. This causes
- * per-context kernel-level resources to be allocated.
- *
- * \param fd file descriptor.
- * \param handle is set on success. To be used by the client when requesting DMA
- * dispatch with drmDMA().
- *
- * \return zero on success, or a negative value on failure.
- *
- * \note May only be called by root.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
- * argument in a drm_ctx structure.
- */
- drm_public int drmCreateContext(int fd, drm_context_t *handle)
- {
- drm_ctx_t ctx;
- memclear(ctx);
- if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
- return -errno;
- *handle = ctx.handle;
- return 0;
- }
- drm_public int drmSwitchToContext(int fd, drm_context_t context)
- {
- drm_ctx_t ctx;
- memclear(ctx);
- ctx.handle = context;
- if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
- return -errno;
- return 0;
- }
- drm_public int drmSetContextFlags(int fd, drm_context_t context,
- drm_context_tFlags flags)
- {
- drm_ctx_t ctx;
- /*
- * Context preserving means that no context switches are done between DMA
- * buffers from one context and the next. This is suitable for use in the
- * X server (which promises to maintain hardware context), or in the
- * client-side library when buffers are swapped on behalf of two threads.
- */
- memclear(ctx);
- ctx.handle = context;
- if (flags & DRM_CONTEXT_PRESERVED)
- ctx.flags |= _DRM_CONTEXT_PRESERVED;
- if (flags & DRM_CONTEXT_2DONLY)
- ctx.flags |= _DRM_CONTEXT_2DONLY;
- if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
- return -errno;
- return 0;
- }
- drm_public int drmGetContextFlags(int fd, drm_context_t context,
- drm_context_tFlagsPtr flags)
- {
- drm_ctx_t ctx;
- memclear(ctx);
- ctx.handle = context;
- if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
- return -errno;
- *flags = 0;
- if (ctx.flags & _DRM_CONTEXT_PRESERVED)
- *flags |= DRM_CONTEXT_PRESERVED;
- if (ctx.flags & _DRM_CONTEXT_2DONLY)
- *flags |= DRM_CONTEXT_2DONLY;
- return 0;
- }
- /**
- * Destroy context.
- *
- * Free any kernel-level resources allocated with drmCreateContext() associated
- * with the context.
- *
- * \param fd file descriptor.
- * \param handle handle given by drmCreateContext().
- *
- * \return zero on success, or a negative value on failure.
- *
- * \note May only be called by root.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
- * argument in a drm_ctx structure.
- */
- drm_public int drmDestroyContext(int fd, drm_context_t handle)
- {
- drm_ctx_t ctx;
- memclear(ctx);
- ctx.handle = handle;
- if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
- return -errno;
- return 0;
- }
- drm_public int drmCreateDrawable(int fd, drm_drawable_t *handle)
- {
- drm_draw_t draw;
- memclear(draw);
- if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
- return -errno;
- *handle = draw.handle;
- return 0;
- }
- drm_public int drmDestroyDrawable(int fd, drm_drawable_t handle)
- {
- drm_draw_t draw;
- memclear(draw);
- draw.handle = handle;
- if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
- return -errno;
- return 0;
- }
- drm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
- drm_drawable_info_type_t type,
- unsigned int num, void *data)
- {
- drm_update_draw_t update;
- memclear(update);
- update.handle = handle;
- update.type = type;
- update.num = num;
- update.data = (unsigned long long)(unsigned long)data;
- if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
- return -errno;
- return 0;
- }
- drm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence,
- uint64_t *ns)
- {
- struct drm_crtc_get_sequence get_seq;
- int ret;
- memclear(get_seq);
- get_seq.crtc_id = crtcId;
- ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq);
- if (ret)
- return ret;
- if (sequence)
- *sequence = get_seq.sequence;
- if (ns)
- *ns = get_seq.sequence_ns;
- return 0;
- }
- drm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags,
- uint64_t sequence,
- uint64_t *sequence_queued,
- uint64_t user_data)
- {
- struct drm_crtc_queue_sequence queue_seq;
- int ret;
- memclear(queue_seq);
- queue_seq.crtc_id = crtcId;
- queue_seq.flags = flags;
- queue_seq.sequence = sequence;
- queue_seq.user_data = user_data;
- ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq);
- if (ret == 0 && sequence_queued)
- *sequence_queued = queue_seq.sequence;
- return ret;
- }
- /**
- * Acquire the AGP device.
- *
- * Must be called before any of the other AGP related calls.
- *
- * \param fd file descriptor.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
- */
- drm_public int drmAgpAcquire(int fd)
- {
- if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
- return -errno;
- return 0;
- }
- /**
- * Release the AGP device.
- *
- * \param fd file descriptor.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
- */
- drm_public int drmAgpRelease(int fd)
- {
- if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
- return -errno;
- return 0;
- }
- /**
- * Set the AGP mode.
- *
- * \param fd file descriptor.
- * \param mode AGP mode.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
- * argument in a drm_agp_mode structure.
- */
- drm_public int drmAgpEnable(int fd, unsigned long mode)
- {
- drm_agp_mode_t m;
- memclear(m);
- m.mode = mode;
- if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
- return -errno;
- return 0;
- }
- /**
- * Allocate a chunk of AGP memory.
- *
- * \param fd file descriptor.
- * \param size requested memory size in bytes. Will be rounded to page boundary.
- * \param type type of memory to allocate.
- * \param address if not zero, will be set to the physical address of the
- * allocated memory.
- * \param handle on success will be set to a handle of the allocated memory.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
- * arguments in a drm_agp_buffer structure.
- */
- drm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
- unsigned long *address, drm_handle_t *handle)
- {
- drm_agp_buffer_t b;
- memclear(b);
- *handle = DRM_AGP_NO_HANDLE;
- b.size = size;
- b.type = type;
- if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
- return -errno;
- if (address != 0UL)
- *address = b.physical;
- *handle = b.handle;
- return 0;
- }
- /**
- * Free a chunk of AGP memory.
- *
- * \param fd file descriptor.
- * \param handle handle to the allocated memory, as given by drmAgpAllocate().
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
- * argument in a drm_agp_buffer structure.
- */
- drm_public int drmAgpFree(int fd, drm_handle_t handle)
- {
- drm_agp_buffer_t b;
- memclear(b);
- b.handle = handle;
- if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
- return -errno;
- return 0;
- }
- /**
- * Bind a chunk of AGP memory.
- *
- * \param fd file descriptor.
- * \param handle handle to the allocated memory, as given by drmAgpAllocate().
- * \param offset offset in bytes. It will round to page boundary.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
- * argument in a drm_agp_binding structure.
- */
- drm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
- {
- drm_agp_binding_t b;
- memclear(b);
- b.handle = handle;
- b.offset = offset;
- if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
- return -errno;
- return 0;
- }
- /**
- * Unbind a chunk of AGP memory.
- *
- * \param fd file descriptor.
- * \param handle handle to the allocated memory, as given by drmAgpAllocate().
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
- * the argument in a drm_agp_binding structure.
- */
- drm_public int drmAgpUnbind(int fd, drm_handle_t handle)
- {
- drm_agp_binding_t b;
- memclear(b);
- b.handle = handle;
- if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
- return -errno;
- return 0;
- }
- /**
- * Get AGP driver major version number.
- *
- * \param fd file descriptor.
- *
- * \return major version number on success, or a negative value on failure..
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
- * necessary information in a drm_agp_info structure.
- */
- drm_public int drmAgpVersionMajor(int fd)
- {
- drm_agp_info_t i;
- memclear(i);
- if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
- return -errno;
- return i.agp_version_major;
- }
- /**
- * Get AGP driver minor version number.
- *
- * \param fd file descriptor.
- *
- * \return minor version number on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
- * necessary information in a drm_agp_info structure.
- */
- drm_public int drmAgpVersionMinor(int fd)
- {
- drm_agp_info_t i;
- memclear(i);
- if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
- return -errno;
- return i.agp_version_minor;
- }
- /**
- * Get AGP mode.
- *
- * \param fd file descriptor.
- *
- * \return mode on success, or zero on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
- * necessary information in a drm_agp_info structure.
- */
- drm_public unsigned long drmAgpGetMode(int fd)
- {
- drm_agp_info_t i;
- memclear(i);
- if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
- return 0;
- return i.mode;
- }
- /**
- * Get AGP aperture base.
- *
- * \param fd file descriptor.
- *
- * \return aperture base on success, zero on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
- * necessary information in a drm_agp_info structure.
- */
- drm_public unsigned long drmAgpBase(int fd)
- {
- drm_agp_info_t i;
- memclear(i);
- if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
- return 0;
- return i.aperture_base;
- }
- /**
- * Get AGP aperture size.
- *
- * \param fd file descriptor.
- *
- * \return aperture size on success, zero on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
- * necessary information in a drm_agp_info structure.
- */
- drm_public unsigned long drmAgpSize(int fd)
- {
- drm_agp_info_t i;
- memclear(i);
- if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
- return 0;
- return i.aperture_size;
- }
- /**
- * Get used AGP memory.
- *
- * \param fd file descriptor.
- *
- * \return memory used on success, or zero on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
- * necessary information in a drm_agp_info structure.
- */
- drm_public unsigned long drmAgpMemoryUsed(int fd)
- {
- drm_agp_info_t i;
- memclear(i);
- if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
- return 0;
- return i.memory_used;
- }
- /**
- * Get available AGP memory.
- *
- * \param fd file descriptor.
- *
- * \return memory available on success, or zero on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
- * necessary information in a drm_agp_info structure.
- */
- drm_public unsigned long drmAgpMemoryAvail(int fd)
- {
- drm_agp_info_t i;
- memclear(i);
- if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
- return 0;
- return i.memory_allowed;
- }
- /**
- * Get hardware vendor ID.
- *
- * \param fd file descriptor.
- *
- * \return vendor ID on success, or zero on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
- * necessary information in a drm_agp_info structure.
- */
- drm_public unsigned int drmAgpVendorId(int fd)
- {
- drm_agp_info_t i;
- memclear(i);
- if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
- return 0;
- return i.id_vendor;
- }
- /**
- * Get hardware device ID.
- *
- * \param fd file descriptor.
- *
- * \return zero on success, or zero on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
- * necessary information in a drm_agp_info structure.
- */
- drm_public unsigned int drmAgpDeviceId(int fd)
- {
- drm_agp_info_t i;
- memclear(i);
- if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
- return 0;
- return i.id_device;
- }
- drm_public int drmScatterGatherAlloc(int fd, unsigned long size,
- drm_handle_t *handle)
- {
- drm_scatter_gather_t sg;
- memclear(sg);
- *handle = 0;
- sg.size = size;
- if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
- return -errno;
- *handle = sg.handle;
- return 0;
- }
- drm_public int drmScatterGatherFree(int fd, drm_handle_t handle)
- {
- drm_scatter_gather_t sg;
- memclear(sg);
- sg.handle = handle;
- if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
- return -errno;
- return 0;
- }
- /**
- * Wait for VBLANK.
- *
- * \param fd file descriptor.
- * \param vbl pointer to a drmVBlank structure.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
- */
- drm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl)
- {
- struct timespec timeout, cur;
- int ret;
- ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
- if (ret < 0) {
- fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
- goto out;
- }
- timeout.tv_sec++;
- do {
- ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
- vbl->request.type &= ~DRM_VBLANK_RELATIVE;
- if (ret && errno == EINTR) {
- clock_gettime(CLOCK_MONOTONIC, &cur);
- /* Timeout after 1s */
- if (cur.tv_sec > timeout.tv_sec + 1 ||
- (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
- timeout.tv_nsec)) {
- errno = EBUSY;
- ret = -1;
- break;
- }
- }
- } while (ret && errno == EINTR);
- out:
- return ret;
- }
- drm_public int drmError(int err, const char *label)
- {
- switch (err) {
- case DRM_ERR_NO_DEVICE:
- fprintf(stderr, "%s: no device\n", label);
- break;
- case DRM_ERR_NO_ACCESS:
- fprintf(stderr, "%s: no access\n", label);
- break;
- case DRM_ERR_NOT_ROOT:
- fprintf(stderr, "%s: not root\n", label);
- break;
- case DRM_ERR_INVALID:
- fprintf(stderr, "%s: invalid args\n", label);
- break;
- default:
- if (err < 0)
- err = -err;
- fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
- break;
- }
- return 1;
- }
- /**
- * Install IRQ handler.
- *
- * \param fd file descriptor.
- * \param irq IRQ number.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
- * argument in a drm_control structure.
- */
- drm_public int drmCtlInstHandler(int fd, int irq)
- {
- drm_control_t ctl;
- memclear(ctl);
- ctl.func = DRM_INST_HANDLER;
- ctl.irq = irq;
- if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
- return -errno;
- return 0;
- }
- /**
- * Uninstall IRQ handler.
- *
- * \param fd file descriptor.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
- * argument in a drm_control structure.
- */
- drm_public int drmCtlUninstHandler(int fd)
- {
- drm_control_t ctl;
- memclear(ctl);
- ctl.func = DRM_UNINST_HANDLER;
- ctl.irq = 0;
- if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
- return -errno;
- return 0;
- }
- drm_public int drmFinish(int fd, int context, drmLockFlags flags)
- {
- drm_lock_t lock;
- memclear(lock);
- lock.context = context;
- if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
- if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
- if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
- if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
- if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
- if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
- if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
- return -errno;
- return 0;
- }
- /**
- * Get IRQ from bus ID.
- *
- * \param fd file descriptor.
- * \param busnum bus number.
- * \param devnum device number.
- * \param funcnum function number.
- *
- * \return IRQ number on success, or a negative value on failure.
- *
- * \internal
- * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
- * arguments in a drm_irq_busid structure.
- */
- drm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum,
- int funcnum)
- {
- drm_irq_busid_t p;
- memclear(p);
- p.busnum = busnum;
- p.devnum = devnum;
- p.funcnum = funcnum;
- if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
- return -errno;
- return p.irq;
- }
- drm_public int drmAddContextTag(int fd, drm_context_t context, void *tag)
- {
- drmHashEntry *entry = drmGetEntry(fd);
- if (drmHashInsert(entry->tagTable, context, tag)) {
- drmHashDelete(entry->tagTable, context);
- drmHashInsert(entry->tagTable, context, tag);
- }
- return 0;
- }
- drm_public int drmDelContextTag(int fd, drm_context_t context)
- {
- drmHashEntry *entry = drmGetEntry(fd);
- return drmHashDelete(entry->tagTable, context);
- }
- drm_public void *drmGetContextTag(int fd, drm_context_t context)
- {
- drmHashEntry *entry = drmGetEntry(fd);
- void *value;
- if (drmHashLookup(entry->tagTable, context, &value))
- return NULL;
- return value;
- }
- drm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
- drm_handle_t handle)
- {
- drm_ctx_priv_map_t map;
- memclear(map);
- map.ctx_id = ctx_id;
- map.handle = (void *)(uintptr_t)handle;
- if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
- return -errno;
- return 0;
- }
- drm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
- drm_handle_t *handle)
- {
- drm_ctx_priv_map_t map;
- memclear(map);
- map.ctx_id = ctx_id;
- if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
- return -errno;
- if (handle)
- *handle = (drm_handle_t)(uintptr_t)map.handle;
- return 0;
- }
- drm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
- drmMapType *type, drmMapFlags *flags,
- drm_handle_t *handle, int *mtrr)
- {
- drm_map_t map;
- memclear(map);
- map.offset = idx;
- if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
- return -errno;
- *offset = map.offset;
- *size = map.size;
- *type = (drmMapType)map.type;
- *flags = (drmMapFlags)map.flags;
- *handle = (unsigned long)map.handle;
- *mtrr = map.mtrr;
- return 0;
- }
- drm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
- unsigned long *magic, unsigned long *iocs)
- {
- drm_client_t client;
- memclear(client);
- client.idx = idx;
- if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
- return -errno;
- *auth = client.auth;
- *pid = client.pid;
- *uid = client.uid;
- *magic = client.magic;
- *iocs = client.iocs;
- return 0;
- }
- drm_public int drmGetStats(int fd, drmStatsT *stats)
- {
- drm_stats_t s;
- unsigned i;
- memclear(s);
- if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
- return -errno;
- stats->count = 0;
- memset(stats, 0, sizeof(*stats));
- if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
- return -1;
- #define SET_VALUE \
- stats->data[i].long_format = "%-20.20s"; \
- stats->data[i].rate_format = "%8.8s"; \
- stats->data[i].isvalue = 1; \
- stats->data[i].verbose = 0
- #define SET_COUNT \
- stats->data[i].long_format = "%-20.20s"; \
- stats->data[i].rate_format = "%5.5s"; \
- stats->data[i].isvalue = 0; \
- stats->data[i].mult_names = "kgm"; \
- stats->data[i].mult = 1000; \
- stats->data[i].verbose = 0
- #define SET_BYTE \
- stats->data[i].long_format = "%-20.20s"; \
- stats->data[i].rate_format = "%5.5s"; \
- stats->data[i].isvalue = 0; \
- stats->data[i].mult_names = "KGM"; \
- stats->data[i].mult = 1024; \
- stats->data[i].verbose = 0
- stats->count = s.count;
- for (i = 0; i < s.count; i++) {
- stats->data[i].value = s.data[i].value;
- switch (s.data[i].type) {
- case _DRM_STAT_LOCK:
- stats->data[i].long_name = "Lock";
- stats->data[i].rate_name = "Lock";
- SET_VALUE;
- break;
- case _DRM_STAT_OPENS:
- stats->data[i].long_name = "Opens";
- stats->data[i].rate_name = "O";
- SET_COUNT;
- stats->data[i].verbose = 1;
- break;
- case _DRM_STAT_CLOSES:
- stats->data[i].long_name = "Closes";
- stats->data[i].rate_name = "Lock";
- SET_COUNT;
- stats->data[i].verbose = 1;
- break;
- case _DRM_STAT_IOCTLS:
- stats->data[i].long_name = "Ioctls";
- stats->data[i].rate_name = "Ioc/s";
- SET_COUNT;
- break;
- case _DRM_STAT_LOCKS:
- stats->data[i].long_name = "Locks";
- stats->data[i].rate_name = "Lck/s";
- SET_COUNT;
- break;
- case _DRM_STAT_UNLOCKS:
- stats->data[i].long_name = "Unlocks";
- stats->data[i].rate_name = "Unl/s";
- SET_COUNT;
- break;
- case _DRM_STAT_IRQ:
- stats->data[i].long_name = "IRQs";
- stats->data[i].rate_name = "IRQ/s";
- SET_COUNT;
- break;
- case _DRM_STAT_PRIMARY:
- stats->data[i].long_name = "Primary Bytes";
- stats->data[i].rate_name = "PB/s";
- SET_BYTE;
- break;
- case _DRM_STAT_SECONDARY:
- stats->data[i].long_name = "Secondary Bytes";
- stats->data[i].rate_name = "SB/s";
- SET_BYTE;
- break;
- case _DRM_STAT_DMA:
- stats->data[i].long_name = "DMA";
- stats->data[i].rate_name = "DMA/s";
- SET_COUNT;
- break;
- case _DRM_STAT_SPECIAL:
- stats->data[i].long_name = "Special DMA";
- stats->data[i].rate_name = "dma/s";
- SET_COUNT;
- break;
- case _DRM_STAT_MISSED:
- stats->data[i].long_name = "Miss";
- stats->data[i].rate_name = "Ms/s";
- SET_COUNT;
- break;
- case _DRM_STAT_VALUE:
- stats->data[i].long_name = "Value";
- stats->data[i].rate_name = "Value";
- SET_VALUE;
- break;
- case _DRM_STAT_BYTE:
- stats->data[i].long_name = "Bytes";
- stats->data[i].rate_name = "B/s";
- SET_BYTE;
- break;
- case _DRM_STAT_COUNT:
- default:
- stats->data[i].long_name = "Count";
- stats->data[i].rate_name = "Cnt/s";
- SET_COUNT;
- break;
- }
- }
- return 0;
- }
- /**
- * Issue a set-version ioctl.
- *
- * \param fd file descriptor.
- * \param drmCommandIndex command index
- * \param data source pointer of the data to be read and written.
- * \param size size of the data to be read and written.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * It issues a read-write ioctl given by
- * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
- */
- drm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version)
- {
- int retcode = 0;
- drm_set_version_t sv;
- memclear(sv);
- sv.drm_di_major = version->drm_di_major;
- sv.drm_di_minor = version->drm_di_minor;
- sv.drm_dd_major = version->drm_dd_major;
- sv.drm_dd_minor = version->drm_dd_minor;
- if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
- retcode = -errno;
- }
- version->drm_di_major = sv.drm_di_major;
- version->drm_di_minor = sv.drm_di_minor;
- version->drm_dd_major = sv.drm_dd_major;
- version->drm_dd_minor = sv.drm_dd_minor;
- return retcode;
- }
- /**
- * Send a device-specific command.
- *
- * \param fd file descriptor.
- * \param drmCommandIndex command index
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * It issues a ioctl given by
- * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
- */
- drm_public int drmCommandNone(int fd, unsigned long drmCommandIndex)
- {
- unsigned long request;
- request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
- if (drmIoctl(fd, request, NULL)) {
- return -errno;
- }
- return 0;
- }
- /**
- * Send a device-specific read command.
- *
- * \param fd file descriptor.
- * \param drmCommandIndex command index
- * \param data destination pointer of the data to be read.
- * \param size size of the data to be read.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * It issues a read ioctl given by
- * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
- */
- drm_public int drmCommandRead(int fd, unsigned long drmCommandIndex,
- void *data, unsigned long size)
- {
- unsigned long request;
- request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
- DRM_COMMAND_BASE + drmCommandIndex, size);
- if (drmIoctl(fd, request, data)) {
- return -errno;
- }
- return 0;
- }
- /**
- * Send a device-specific write command.
- *
- * \param fd file descriptor.
- * \param drmCommandIndex command index
- * \param data source pointer of the data to be written.
- * \param size size of the data to be written.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * It issues a write ioctl given by
- * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
- */
- drm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex,
- void *data, unsigned long size)
- {
- unsigned long request;
- request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
- DRM_COMMAND_BASE + drmCommandIndex, size);
- if (drmIoctl(fd, request, data)) {
- return -errno;
- }
- return 0;
- }
- /**
- * Send a device-specific read-write command.
- *
- * \param fd file descriptor.
- * \param drmCommandIndex command index
- * \param data source pointer of the data to be read and written.
- * \param size size of the data to be read and written.
- *
- * \return zero on success, or a negative value on failure.
- *
- * \internal
- * It issues a read-write ioctl given by
- * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
- */
- drm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
- void *data, unsigned long size)
- {
- unsigned long request;
- request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
- DRM_COMMAND_BASE + drmCommandIndex, size);
- if (drmIoctl(fd, request, data))
- return -errno;
- return 0;
- }
- #define DRM_MAX_FDS 16
- static struct {
- char *BusID;
- int fd;
- int refcount;
- int type;
- } connection[DRM_MAX_FDS];
- static int nr_fds = 0;
- drm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened)
- {
- return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
- }
- drm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened,
- int type)
- {
- int i;
- int fd;
- for (i = 0; i < nr_fds; i++)
- if ((strcmp(BusID, connection[i].BusID) == 0) &&
- (connection[i].type == type)) {
- connection[i].refcount++;
- *newlyopened = 0;
- return connection[i].fd;
- }
- fd = drmOpenWithType(NULL, BusID, type);
- if (fd < 0 || nr_fds == DRM_MAX_FDS)
- return fd;
- connection[nr_fds].BusID = strdup(BusID);
- connection[nr_fds].fd = fd;
- connection[nr_fds].refcount = 1;
- connection[nr_fds].type = type;
- *newlyopened = 1;
- if (0)
- fprintf(stderr, "saved connection %d for %s %d\n",
- nr_fds, connection[nr_fds].BusID,
- strcmp(BusID, connection[nr_fds].BusID));
- nr_fds++;
- return fd;
- }
- drm_public void drmCloseOnce(int fd)
- {
- int i;
- for (i = 0; i < nr_fds; i++) {
- if (fd == connection[i].fd) {
- if (--connection[i].refcount == 0) {
- drmClose(connection[i].fd);
- free(connection[i].BusID);
- if (i < --nr_fds)
- connection[i] = connection[nr_fds];
- return;
- }
- }
- }
- }
- drm_public int drmSetMaster(int fd)
- {
- return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
- }
- drm_public int drmDropMaster(int fd)
- {
- return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
- }
- drm_public int drmIsMaster(int fd)
- {
- /* Detect master by attempting something that requires master.
- *
- * Authenticating magic tokens requires master and 0 is an
- * internal kernel detail which we could use. Attempting this on
- * a master fd would fail therefore fail with EINVAL because 0
- * is invalid.
- *
- * A non-master fd will fail with EACCES, as the kernel checks
- * for master before attempting to do anything else.
- *
- * Since we don't want to leak implementation details, use
- * EACCES.
- */
- return drmAuthMagic(fd, 0) != -EACCES;
- }
- drm_public char *drmGetDeviceNameFromFd(int fd)
- {
- #ifdef __FreeBSD__
- struct stat sbuf;
- int maj, min;
- int nodetype;
- if (fstat(fd, &sbuf))
- return NULL;
- maj = major(sbuf.st_rdev);
- min = minor(sbuf.st_rdev);
- nodetype = drmGetMinorType(maj, min);
- return drmGetMinorNameForFD(fd, nodetype);
- #else
- char name[128];
- struct stat sbuf;
- dev_t d;
- int i;
- /* The whole drmOpen thing is a fiasco and we need to find a way
- * back to just using open(2). For now, however, lets just make
- * things worse with even more ad hoc directory walking code to
- * discover the device file name. */
- fstat(fd, &sbuf);
- d = sbuf.st_rdev;
- for (i = 0; i < DRM_MAX_MINOR; i++) {
- snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
- if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
- break;
- }
- if (i == DRM_MAX_MINOR)
- return NULL;
- return strdup(name);
- #endif
- }
- static bool drmNodeIsDRM(int maj, int min)
- {
- #ifdef __linux__
- char path[64];
- struct stat sbuf;
- snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm",
- maj, min);
- return stat(path, &sbuf) == 0;
- #elif defined(__FreeBSD__)
- char name[SPECNAMELEN];
- if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name)))
- return 0;
- /* Handle drm/ and dri/ as both are present in different FreeBSD version
- * FreeBSD on amd64/i386/powerpc external kernel modules create node in
- * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
- * only device nodes in /dev/dri/ */
- return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4));
- #else
- return maj == DRM_MAJOR;
- #endif
- }
- drm_public int drmGetNodeTypeFromFd(int fd)
- {
- struct stat sbuf;
- int maj, min, type;
- if (fstat(fd, &sbuf))
- return -1;
- maj = major(sbuf.st_rdev);
- min = minor(sbuf.st_rdev);
- if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) {
- errno = EINVAL;
- return -1;
- }
- type = drmGetMinorType(maj, min);
- if (type == -1)
- errno = ENODEV;
- return type;
- }
- drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags,
- int *prime_fd)
- {
- struct drm_prime_handle args;
- int ret;
- memclear(args);
- args.fd = -1;
- args.handle = handle;
- args.flags = flags;
- ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
- if (ret)
- return ret;
- *prime_fd = args.fd;
- return 0;
- }
- drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
- {
- struct drm_prime_handle args;
- int ret;
- memclear(args);
- args.fd = prime_fd;
- ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
- if (ret)
- return ret;
- *handle = args.handle;
- return 0;
- }
- drm_public int drmCloseBufferHandle(int fd, uint32_t handle)
- {
- struct drm_gem_close args;
- memclear(args);
- args.handle = handle;
- return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args);
- }
- static char *drmGetMinorNameForFD(int fd, int type)
- {
- #ifdef __linux__
- DIR *sysdir;
- struct dirent *ent;
- struct stat sbuf;
- const char *name = drmGetMinorName(type);
- int len;
- char dev_name[64], buf[64];
- int maj, min;
- if (!name)
- return NULL;
- len = strlen(name);
- if (fstat(fd, &sbuf))
- return NULL;
- maj = major(sbuf.st_rdev);
- min = minor(sbuf.st_rdev);
- if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
- return NULL;
- snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
- sysdir = opendir(buf);
- if (!sysdir)
- return NULL;
- while ((ent = readdir(sysdir))) {
- if (strncmp(ent->d_name, name, len) == 0) {
- if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
- ent->d_name) < 0)
- return NULL;
- closedir(sysdir);
- return strdup(dev_name);
- }
- }
- closedir(sysdir);
- return NULL;
- #elif defined(__FreeBSD__)
- struct stat sbuf;
- char dname[SPECNAMELEN];
- const char *mname;
- char name[SPECNAMELEN];
- int id, maj, min, nodetype, i;
- if (fstat(fd, &sbuf))
- return NULL;
- maj = major(sbuf.st_rdev);
- min = minor(sbuf.st_rdev);
- if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
- return NULL;
- if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname)))
- return NULL;
- /* Handle both /dev/drm and /dev/dri
- * FreeBSD on amd64/i386/powerpc external kernel modules create node in
- * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
- * only device nodes in /dev/dri/ */
- /* Get the node type represented by fd so we can deduce the target name */
- nodetype = drmGetMinorType(maj, min);
- if (nodetype == -1)
- return (NULL);
- mname = drmGetMinorName(type);
- for (i = 0; i < SPECNAMELEN; i++) {
- if (isalpha(dname[i]) == 0 && dname[i] != '/')
- break;
- }
- if (dname[i] == '\0')
- return (NULL);
- id = (int)strtol(&dname[i], NULL, 10);
- id -= drmGetMinorBase(nodetype);
- snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname,
- id + drmGetMinorBase(type));
- return strdup(name);
- #else
- struct stat sbuf;
- char buf[PATH_MAX + 1];
- const char *dev_name = drmGetDeviceName(type);
- unsigned int maj, min;
- int n;
- if (fstat(fd, &sbuf))
- return NULL;
- maj = major(sbuf.st_rdev);
- min = minor(sbuf.st_rdev);
- if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
- return NULL;
- if (!dev_name)
- return NULL;
- n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min);
- if (n == -1 || n >= sizeof(buf))
- return NULL;
- return strdup(buf);
- #endif
- }
- drm_public char *drmGetPrimaryDeviceNameFromFd(int fd)
- {
- return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
- }
- drm_public char *drmGetRenderDeviceNameFromFd(int fd)
- {
- return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
- }
- #ifdef __linux__
- static char * DRM_PRINTFLIKE(2, 3)
- sysfs_uevent_get(const char *path, const char *fmt, ...)
- {
- char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
- size_t size = 0, len;
- ssize_t num;
- va_list ap;
- FILE *fp;
- va_start(ap, fmt);
- num = vasprintf(&key, fmt, ap);
- va_end(ap);
- len = num;
- snprintf(filename, sizeof(filename), "%s/uevent", path);
- fp = fopen(filename, "r");
- if (!fp) {
- free(key);
- return NULL;
- }
- while ((num = getline(&line, &size, fp)) >= 0) {
- if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
- char *start = line + len + 1, *end = line + num - 1;
- if (*end != '\n')
- end++;
- value = strndup(start, end - start);
- break;
- }
- }
- free(line);
- fclose(fp);
- free(key);
- return value;
- }
- #endif
- /* Little white lie to avoid major rework of the existing code */
- #define DRM_BUS_VIRTIO 0x10
- #ifdef __linux__
- static int get_subsystem_type(const char *device_path)
- {
- char path[PATH_MAX + 1] = "";
- char link[PATH_MAX + 1] = "";
- char *name;
- struct {
- const char *name;
- int bus_type;
- } bus_types[] = {
- { "/pci", DRM_BUS_PCI },
- { "/usb", DRM_BUS_USB },
- { "/platform", DRM_BUS_PLATFORM },
- { "/spi", DRM_BUS_PLATFORM },
- { "/host1x", DRM_BUS_HOST1X },
- { "/virtio", DRM_BUS_VIRTIO },
- { "/faux", DRM_BUS_FAUX },
- };
- strncpy(path, device_path, PATH_MAX);
- strncat(path, "/subsystem", PATH_MAX);
- if (readlink(path, link, PATH_MAX) < 0)
- return -errno;
- name = strrchr(link, '/');
- if (!name)
- return -EINVAL;
- for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) {
- if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0)
- return bus_types[i].bus_type;
- }
- return -EINVAL;
- }
- #endif
- static int drmParseSubsystemType(int maj, int min)
- {
- #ifdef __linux__
- char path[PATH_MAX + 1] = "";
- char real_path[PATH_MAX + 1] = "";
- int subsystem_type;
- snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
- subsystem_type = get_subsystem_type(path);
- /* Try to get the parent (underlying) device type */
- if (subsystem_type == DRM_BUS_VIRTIO) {
- /* Assume virtio-pci on error */
- if (!realpath(path, real_path))
- return DRM_BUS_VIRTIO;
- strncat(path, "/..", PATH_MAX);
- subsystem_type = get_subsystem_type(path);
- if (subsystem_type < 0)
- return DRM_BUS_VIRTIO;
- }
- return subsystem_type;
- #elif defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD__)
- return DRM_BUS_PCI;
- #else
- #warning "Missing implementation of drmParseSubsystemType"
- return -EINVAL;
- #endif
- }
- #ifdef __linux__
- static void
- get_pci_path(int maj, int min, char *pci_path)
- {
- char path[PATH_MAX + 1], *term;
- snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
- if (!realpath(path, pci_path)) {
- strcpy(pci_path, path);
- return;
- }
- term = strrchr(pci_path, '/');
- if (term && strncmp(term, "/virtio", 7) == 0)
- *term = 0;
- }
- #endif
- #ifdef __FreeBSD__
- static int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info)
- {
- char dname[SPECNAMELEN];
- char sysctl_name[16];
- char sysctl_val[256];
- size_t sysctl_len;
- int id, type, nelem;
- unsigned int rdev, majmin, domain, bus, dev, func;
- rdev = makedev(maj, min);
- if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname)))
- return -EINVAL;
- if (sscanf(dname, "drm/%d\n", &id) != 1)
- return -EINVAL;
- type = drmGetMinorType(maj, min);
- if (type == -1)
- return -EINVAL;
- /* BUG: This above section is iffy, since it mandates that a driver will
- * create both card and render node.
- * If it does not, the next DRM device will create card#X and
- * renderD#(128+X)-1.
- * This is a possibility in FreeBSD but for now there is no good way for
- * obtaining the info.
- */
- switch (type) {
- case DRM_NODE_PRIMARY:
- break;
- case DRM_NODE_RENDER:
- id -= 128;
- break;
- }
- if (id < 0)
- return -EINVAL;
- if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0)
- return -EINVAL;
- sysctl_len = sizeof(sysctl_val);
- if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0))
- return -EINVAL;
- #define bus_fmt "pci:%04x:%02x:%02x.%u"
- nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func);
- if (nelem != 4)
- return -EINVAL;
- info->domain = domain;
- info->bus = bus;
- info->dev = dev;
- info->func = func;
- return 0;
- }
- #endif
- static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
- {
- #ifdef __linux__
- unsigned int domain, bus, dev, func;
- char pci_path[PATH_MAX + 1], *value;
- int num;
- get_pci_path(maj, min, pci_path);
- value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME");
- if (!value)
- return -ENOENT;
- num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
- free(value);
- if (num != 4)
- return -EINVAL;
- info->domain = domain;
- info->bus = bus;
- info->dev = dev;
- info->func = func;
- return 0;
- #elif defined(__OpenBSD__) || defined(__DragonFly__)
- struct drm_pciinfo pinfo;
- int fd, type;
- type = drmGetMinorType(maj, min);
- if (type == -1)
- return -ENODEV;
- fd = drmOpenMinor(min, 0, type);
- if (fd < 0)
- return -errno;
- if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
- close(fd);
- return -errno;
- }
- close(fd);
- info->domain = pinfo.domain;
- info->bus = pinfo.bus;
- info->dev = pinfo.dev;
- info->func = pinfo.func;
- return 0;
- #elif defined(__FreeBSD__)
- return get_sysctl_pci_bus_info(maj, min, info);
- #else
- #warning "Missing implementation of drmParsePciBusInfo"
- return -EINVAL;
- #endif
- }
- drm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b)
- {
- if (a == NULL || b == NULL)
- return 0;
- if (a->bustype != b->bustype)
- return 0;
- switch (a->bustype) {
- case DRM_BUS_PCI:
- return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0;
- case DRM_BUS_USB:
- return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0;
- case DRM_BUS_PLATFORM:
- return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0;
- case DRM_BUS_HOST1X:
- return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0;
- case DRM_BUS_FAUX:
- return memcmp(a->businfo.faux, b->businfo.faux, sizeof(drmFauxBusInfo)) == 0;
- default:
- break;
- }
- return 0;
- }
- static int drmGetNodeType(const char *name)
- {
- if (strncmp(name, DRM_RENDER_MINOR_NAME,
- sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
- return DRM_NODE_RENDER;
- if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
- sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
- return DRM_NODE_PRIMARY;
- return -EINVAL;
- }
- static int drmGetMaxNodeName(void)
- {
- return sizeof(DRM_DIR_NAME) +
- MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
- sizeof(DRM_CONTROL_MINOR_NAME),
- sizeof(DRM_RENDER_MINOR_NAME)) +
- 3 /* length of the node number */;
- }
- #ifdef __linux__
- static int parse_separate_sysfs_files(int maj, int min,
- drmPciDeviceInfoPtr device,
- bool ignore_revision)
- {
- static const char *attrs[] = {
- "revision", /* Older kernels are missing the file, so check for it first */
- "vendor",
- "device",
- "subsystem_vendor",
- "subsystem_device",
- };
- char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
- unsigned int data[ARRAY_SIZE(attrs)];
- FILE *fp;
- int ret;
- get_pci_path(maj, min, pci_path);
- for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
- if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0)
- return -errno;
- fp = fopen(path, "r");
- if (!fp)
- return -errno;
- ret = fscanf(fp, "%x", &data[i]);
- fclose(fp);
- if (ret != 1)
- return -errno;
- }
- device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
- device->vendor_id = data[1] & 0xffff;
- device->device_id = data[2] & 0xffff;
- device->subvendor_id = data[3] & 0xffff;
- device->subdevice_id = data[4] & 0xffff;
- return 0;
- }
- static int parse_config_sysfs_file(int maj, int min,
- drmPciDeviceInfoPtr device)
- {
- char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
- unsigned char config[64];
- int fd, ret;
- get_pci_path(maj, min, pci_path);
- if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0)
- return -errno;
- fd = open(path, O_RDONLY);
- if (fd < 0)
- return -errno;
- ret = read(fd, config, sizeof(config));
- close(fd);
- if (ret < 0)
- return -errno;
- device->vendor_id = config[0] | (config[1] << 8);
- device->device_id = config[2] | (config[3] << 8);
- device->revision_id = config[8];
- device->subvendor_id = config[44] | (config[45] << 8);
- device->subdevice_id = config[46] | (config[47] << 8);
- return 0;
- }
- #endif
- static int drmParsePciDeviceInfo(int maj, int min,
- drmPciDeviceInfoPtr device,
- uint32_t flags)
- {
- #ifdef __linux__
- if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
- return parse_separate_sysfs_files(maj, min, device, true);
- if (parse_separate_sysfs_files(maj, min, device, false))
- return parse_config_sysfs_file(maj, min, device);
- return 0;
- #elif defined(__OpenBSD__) || defined(__DragonFly__)
- struct drm_pciinfo pinfo;
- int fd, type;
- type = drmGetMinorType(maj, min);
- if (type == -1)
- return -ENODEV;
- fd = drmOpenMinor(min, 0, type);
- if (fd < 0)
- return -errno;
- if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
- close(fd);
- return -errno;
- }
- close(fd);
- device->vendor_id = pinfo.vendor_id;
- device->device_id = pinfo.device_id;
- device->revision_id = pinfo.revision_id;
- device->subvendor_id = pinfo.subvendor_id;
- device->subdevice_id = pinfo.subdevice_id;
- return 0;
- #elif defined(__FreeBSD__)
- drmPciBusInfo info;
- struct pci_conf_io pc;
- struct pci_match_conf patterns[1];
- struct pci_conf results[1];
- int fd, error;
- if (get_sysctl_pci_bus_info(maj, min, &info) != 0)
- return -EINVAL;
- fd = open("/dev/pci", O_RDONLY);
- if (fd < 0)
- return -errno;
- bzero(&patterns, sizeof(patterns));
- patterns[0].pc_sel.pc_domain = info.domain;
- patterns[0].pc_sel.pc_bus = info.bus;
- patterns[0].pc_sel.pc_dev = info.dev;
- patterns[0].pc_sel.pc_func = info.func;
- patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS
- | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC;
- bzero(&pc, sizeof(struct pci_conf_io));
- pc.num_patterns = 1;
- pc.pat_buf_len = sizeof(patterns);
- pc.patterns = patterns;
- pc.match_buf_len = sizeof(results);
- pc.matches = results;
- if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) {
- error = errno;
- close(fd);
- return -error;
- }
- close(fd);
- device->vendor_id = results[0].pc_vendor;
- device->device_id = results[0].pc_device;
- device->subvendor_id = results[0].pc_subvendor;
- device->subdevice_id = results[0].pc_subdevice;
- device->revision_id = results[0].pc_revid;
- return 0;
- #else
- #warning "Missing implementation of drmParsePciDeviceInfo"
- return -EINVAL;
- #endif
- }
- static void drmFreePlatformDevice(drmDevicePtr device)
- {
- if (device->deviceinfo.platform) {
- if (device->deviceinfo.platform->compatible) {
- char **compatible = device->deviceinfo.platform->compatible;
- while (*compatible) {
- free(*compatible);
- compatible++;
- }
- free(device->deviceinfo.platform->compatible);
- }
- }
- }
- static void drmFreeHost1xDevice(drmDevicePtr device)
- {
- if (device->deviceinfo.host1x) {
- if (device->deviceinfo.host1x->compatible) {
- char **compatible = device->deviceinfo.host1x->compatible;
- while (*compatible) {
- free(*compatible);
- compatible++;
- }
- free(device->deviceinfo.host1x->compatible);
- }
- }
- }
- drm_public void drmFreeDevice(drmDevicePtr *device)
- {
- if (device == NULL)
- return;
- if (*device) {
- switch ((*device)->bustype) {
- case DRM_BUS_PLATFORM:
- drmFreePlatformDevice(*device);
- break;
- case DRM_BUS_HOST1X:
- drmFreeHost1xDevice(*device);
- break;
- }
- }
- free(*device);
- *device = NULL;
- }
- drm_public void drmFreeDevices(drmDevicePtr devices[], int count)
- {
- int i;
- if (devices == NULL)
- return;
- for (i = 0; i < count; i++)
- if (devices[i])
- drmFreeDevice(&devices[i]);
- }
- static drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
- size_t bus_size, size_t device_size,
- char **ptrp)
- {
- size_t max_node_length, extra, size;
- drmDevicePtr device;
- unsigned int i;
- char *ptr;
- max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
- extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
- size = sizeof(*device) + extra + bus_size + device_size;
- device = calloc(1, size);
- if (!device)
- return NULL;
- device->available_nodes = 1 << type;
- ptr = (char *)device + sizeof(*device);
- device->nodes = (char **)ptr;
- ptr += DRM_NODE_MAX * sizeof(void *);
- for (i = 0; i < DRM_NODE_MAX; i++) {
- device->nodes[i] = ptr;
- ptr += max_node_length;
- }
- memcpy(device->nodes[type], node, max_node_length);
- *ptrp = ptr;
- return device;
- }
- static int drmProcessPciDevice(drmDevicePtr *device,
- const char *node, int node_type,
- int maj, int min, bool fetch_deviceinfo,
- uint32_t flags)
- {
- drmDevicePtr dev;
- char *addr;
- int ret;
- dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
- sizeof(drmPciDeviceInfo), &addr);
- if (!dev)
- return -ENOMEM;
- dev->bustype = DRM_BUS_PCI;
- dev->businfo.pci = (drmPciBusInfoPtr)addr;
- ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
- if (ret)
- goto free_device;
- // Fetch the device info if the user has requested it
- if (fetch_deviceinfo) {
- addr += sizeof(drmPciBusInfo);
- dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
- ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
- if (ret)
- goto free_device;
- }
- *device = dev;
- return 0;
- free_device:
- free(dev);
- return ret;
- }
- #ifdef __linux__
- static int drm_usb_dev_path(int maj, int min, char *path, size_t len)
- {
- char *value, *tmp_path, *slash;
- bool usb_device, usb_interface;
- snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min);
- value = sysfs_uevent_get(path, "DEVTYPE");
- if (!value)
- return -ENOENT;
- usb_device = strcmp(value, "usb_device") == 0;
- usb_interface = strcmp(value, "usb_interface") == 0;
- free(value);
- if (usb_device)
- return 0;
- if (!usb_interface)
- return -ENOTSUP;
- /* The parent of a usb_interface is a usb_device */
- tmp_path = realpath(path, NULL);
- if (!tmp_path)
- return -errno;
- slash = strrchr(tmp_path, '/');
- if (!slash) {
- free(tmp_path);
- return -EINVAL;
- }
- *slash = '\0';
- if (snprintf(path, len, "%s", tmp_path) >= (int)len) {
- free(tmp_path);
- return -EINVAL;
- }
- free(tmp_path);
- return 0;
- }
- #endif
- static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
- {
- #ifdef __linux__
- char path[PATH_MAX + 1], *value;
- unsigned int bus, dev;
- int ret;
- ret = drm_usb_dev_path(maj, min, path, sizeof(path));
- if (ret < 0)
- return ret;
- value = sysfs_uevent_get(path, "BUSNUM");
- if (!value)
- return -ENOENT;
- ret = sscanf(value, "%03u", &bus);
- free(value);
- if (ret <= 0)
- return -errno;
- value = sysfs_uevent_get(path, "DEVNUM");
- if (!value)
- return -ENOENT;
- ret = sscanf(value, "%03u", &dev);
- free(value);
- if (ret <= 0)
- return -errno;
- info->bus = bus;
- info->dev = dev;
- return 0;
- #else
- #warning "Missing implementation of drmParseUsbBusInfo"
- return -EINVAL;
- #endif
- }
- static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
- {
- #ifdef __linux__
- char path[PATH_MAX + 1], *value;
- unsigned int vendor, product;
- int ret;
- ret = drm_usb_dev_path(maj, min, path, sizeof(path));
- if (ret < 0)
- return ret;
- value = sysfs_uevent_get(path, "PRODUCT");
- if (!value)
- return -ENOENT;
- ret = sscanf(value, "%x/%x", &vendor, &product);
- free(value);
- if (ret <= 0)
- return -errno;
- info->vendor = vendor;
- info->product = product;
- return 0;
- #else
- #warning "Missing implementation of drmParseUsbDeviceInfo"
- return -EINVAL;
- #endif
- }
- static int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
- int node_type, int maj, int min,
- bool fetch_deviceinfo, uint32_t flags)
- {
- drmDevicePtr dev;
- char *ptr;
- int ret;
- dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
- sizeof(drmUsbDeviceInfo), &ptr);
- if (!dev)
- return -ENOMEM;
- dev->bustype = DRM_BUS_USB;
- dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
- ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
- if (ret < 0)
- goto free_device;
- if (fetch_deviceinfo) {
- ptr += sizeof(drmUsbBusInfo);
- dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
- ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
- if (ret < 0)
- goto free_device;
- }
- *device = dev;
- return 0;
- free_device:
- free(dev);
- return ret;
- }
- static int drmParseOFBusInfo(int maj, int min, char *fullname)
- {
- #ifdef __linux__
- char path[PATH_MAX + 1], *name, *tmp_name;
- snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
- name = sysfs_uevent_get(path, "OF_FULLNAME");
- tmp_name = name;
- if (!name) {
- /* If the device lacks OF data, pick the MODALIAS info */
- name = sysfs_uevent_get(path, "MODALIAS");
- if (!name)
- return -ENOENT;
- /* .. and strip the MODALIAS=[platform,usb...]: part. */
- tmp_name = strrchr(name, ':');
- if (!tmp_name) {
- free(name);
- return -ENOENT;
- }
- tmp_name++;
- }
- strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN);
- fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
- free(name);
- return 0;
- #else
- #warning "Missing implementation of drmParseOFBusInfo"
- return -EINVAL;
- #endif
- }
- static int drmParseOFDeviceInfo(int maj, int min, char ***compatible)
- {
- #ifdef __linux__
- char path[PATH_MAX + 1], *value, *tmp_name;
- unsigned int count, i;
- int err;
- snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
- value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
- if (value) {
- sscanf(value, "%u", &count);
- free(value);
- } else {
- /* Assume one entry if the device lack OF data */
- count = 1;
- }
- *compatible = calloc(count + 1, sizeof(char *));
- if (!*compatible)
- return -ENOMEM;
- for (i = 0; i < count; i++) {
- value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
- tmp_name = value;
- if (!value) {
- /* If the device lacks OF data, pick the MODALIAS info */
- value = sysfs_uevent_get(path, "MODALIAS");
- if (!value) {
- err = -ENOENT;
- goto free;
- }
- /* .. and strip the MODALIAS=[platform,usb...]: part. */
- tmp_name = strrchr(value, ':');
- if (!tmp_name) {
- free(value);
- return -ENOENT;
- }
- tmp_name = strdup(tmp_name + 1);
- free(value);
- }
- (*compatible)[i] = tmp_name;
- }
- return 0;
- free:
- while (i--)
- free((*compatible)[i]);
- free(*compatible);
- return err;
- #else
- #warning "Missing implementation of drmParseOFDeviceInfo"
- return -EINVAL;
- #endif
- }
- static int drmProcessPlatformDevice(drmDevicePtr *device,
- const char *node, int node_type,
- int maj, int min, bool fetch_deviceinfo,
- uint32_t flags)
- {
- drmDevicePtr dev;
- char *ptr;
- int ret;
- dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
- sizeof(drmPlatformDeviceInfo), &ptr);
- if (!dev)
- return -ENOMEM;
- dev->bustype = DRM_BUS_PLATFORM;
- dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
- ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname);
- if (ret < 0)
- goto free_device;
- if (fetch_deviceinfo) {
- ptr += sizeof(drmPlatformBusInfo);
- dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
- ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible);
- if (ret < 0)
- goto free_device;
- }
- *device = dev;
- return 0;
- free_device:
- free(dev);
- return ret;
- }
- static int drmProcessHost1xDevice(drmDevicePtr *device,
- const char *node, int node_type,
- int maj, int min, bool fetch_deviceinfo,
- uint32_t flags)
- {
- drmDevicePtr dev;
- char *ptr;
- int ret;
- dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
- sizeof(drmHost1xDeviceInfo), &ptr);
- if (!dev)
- return -ENOMEM;
- dev->bustype = DRM_BUS_HOST1X;
- dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
- ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname);
- if (ret < 0)
- goto free_device;
- if (fetch_deviceinfo) {
- ptr += sizeof(drmHost1xBusInfo);
- dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
- ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible);
- if (ret < 0)
- goto free_device;
- }
- *device = dev;
- return 0;
- free_device:
- free(dev);
- return ret;
- }
- static int drmParseFauxBusInfo(int maj, int min, char *fullname)
- {
- #ifdef __linux__
- char path[PATH_MAX + 1] = "";
- char real_path[PATH_MAX + 1] = "";
- char *name;
- snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
- if (!realpath(path, real_path))
- return -errno;
- name = basename(real_path);
- if (!name)
- return -ENOENT;
- strncpy(fullname, name, DRM_FAUX_DEVICE_NAME_LEN - 1);
- fullname[DRM_FAUX_DEVICE_NAME_LEN - 1] = '\0';
- return 0;
- #else
- #warning "Missing implementation of drmParseFauxBusInfo"
- return -EINVAL;
- #endif
- }
- static int drmProcessFauxDevice(drmDevicePtr *device,
- const char *node, int node_type,
- int maj, int min, bool fetch_deviceinfo,
- uint32_t flags)
- {
- drmDevicePtr dev;
- char *ptr;
- int ret;
- dev = drmDeviceAlloc(node_type, node, sizeof(drmFauxBusInfo), 0, &ptr);
- if (!dev)
- return -ENOMEM;
- dev->bustype = DRM_BUS_FAUX;
- dev->businfo.faux = (drmFauxBusInfoPtr)ptr;
- ret = drmParseFauxBusInfo(maj, min, dev->businfo.faux->name);
- if (ret < 0)
- goto free_device;
- *device = dev;
- return 0;
- free_device:
- free(dev);
- return ret;
- }
- static int
- process_device(drmDevicePtr *device, const char *d_name,
- int req_subsystem_type,
- bool fetch_deviceinfo, uint32_t flags)
- {
- struct stat sbuf;
- char node[PATH_MAX + 1];
- int node_type, subsystem_type, written;
- unsigned int maj, min;
- const int max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
- node_type = drmGetNodeType(d_name);
- if (node_type < 0)
- return -1;
- written = snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name);
- if (written < 0)
- return -1;
- /* anything longer than this will be truncated in drmDeviceAlloc.
- * Account for NULL byte
- */
- if (written + 1 > max_node_length)
- return -1;
- if (stat(node, &sbuf))
- return -1;
- maj = major(sbuf.st_rdev);
- min = minor(sbuf.st_rdev);
- if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
- return -1;
- subsystem_type = drmParseSubsystemType(maj, min);
- if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type)
- return -1;
- switch (subsystem_type) {
- case DRM_BUS_PCI:
- case DRM_BUS_VIRTIO:
- return drmProcessPciDevice(device, node, node_type, maj, min,
- fetch_deviceinfo, flags);
- case DRM_BUS_USB:
- return drmProcessUsbDevice(device, node, node_type, maj, min,
- fetch_deviceinfo, flags);
- case DRM_BUS_PLATFORM:
- return drmProcessPlatformDevice(device, node, node_type, maj, min,
- fetch_deviceinfo, flags);
- case DRM_BUS_HOST1X:
- return drmProcessHost1xDevice(device, node, node_type, maj, min,
- fetch_deviceinfo, flags);
- case DRM_BUS_FAUX:
- return drmProcessFauxDevice(device, node, node_type, maj, min,
- fetch_deviceinfo, flags);
- default:
- return -1;
- }
- }
- /* Consider devices located on the same bus as duplicate and fold the respective
- * entries into a single one.
- *
- * Note: this leaves "gaps" in the array, while preserving the length.
- */
- static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
- {
- int node_type, i, j;
- for (i = 0; i < count; i++) {
- for (j = i + 1; j < count; j++) {
- if (drmDevicesEqual(local_devices[i], local_devices[j])) {
- local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
- node_type = log2_int(local_devices[j]->available_nodes);
- memcpy(local_devices[i]->nodes[node_type],
- local_devices[j]->nodes[node_type], drmGetMaxNodeName());
- drmFreeDevice(&local_devices[j]);
- }
- }
- }
- }
- /* Check that the given flags are valid returning 0 on success */
- static int
- drm_device_validate_flags(uint32_t flags)
- {
- return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
- }
- static bool
- drm_device_has_rdev(drmDevicePtr device, dev_t find_rdev)
- {
- struct stat sbuf;
- for (int i = 0; i < DRM_NODE_MAX; i++) {
- if (device->available_nodes & 1 << i) {
- if (stat(device->nodes[i], &sbuf) == 0 &&
- sbuf.st_rdev == find_rdev)
- return true;
- }
- }
- return false;
- }
- /*
- * The kernel drm core has a number of places that assume maximum of
- * 3x64 devices nodes. That's 64 for each of primary, control and
- * render nodes. Rounded it up to 256 for simplicity.
- */
- #define MAX_DRM_NODES 256
- /**
- * Get information about a device from its dev_t identifier
- *
- * \param find_rdev dev_t identifier of the device
- * \param flags feature/behaviour bitmask
- * \param device the address of a drmDevicePtr where the information
- * will be allocated in stored
- *
- * \return zero on success, negative error code otherwise.
- */
- drm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device)
- {
- #ifdef __OpenBSD__
- /*
- * DRI device nodes on OpenBSD are not in their own directory, they reside
- * in /dev along with a large number of statically generated /dev nodes.
- * Avoid stat'ing all of /dev needlessly by implementing this custom path.
- */
- drmDevicePtr d;
- char node[PATH_MAX + 1];
- const char *dev_name;
- int node_type, subsystem_type;
- int maj, min, n, ret;
- const int max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
- struct stat sbuf;
- if (device == NULL)
- return -EINVAL;
- maj = major(find_rdev);
- min = minor(find_rdev);
- if (!drmNodeIsDRM(maj, min))
- return -EINVAL;
- node_type = drmGetMinorType(maj, min);
- if (node_type == -1)
- return -ENODEV;
- dev_name = drmGetDeviceName(node_type);
- if (!dev_name)
- return -EINVAL;
- /* anything longer than this will be truncated in drmDeviceAlloc.
- * Account for NULL byte
- */
- n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
- if (n == -1 || n >= PATH_MAX)
- return -errno;
- if (n + 1 > max_node_length)
- return -EINVAL;
- if (stat(node, &sbuf))
- return -EINVAL;
- subsystem_type = drmParseSubsystemType(maj, min);
- if (subsystem_type != DRM_BUS_PCI)
- return -ENODEV;
- ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
- if (ret)
- return ret;
- *device = d;
- return 0;
- #else
- drmDevicePtr local_devices[MAX_DRM_NODES];
- drmDevicePtr d;
- DIR *sysdir;
- struct dirent *dent;
- int subsystem_type;
- int maj, min;
- int ret, i, node_count;
- if (drm_device_validate_flags(flags))
- return -EINVAL;
- if (device == NULL)
- return -EINVAL;
- maj = major(find_rdev);
- min = minor(find_rdev);
- if (!drmNodeIsDRM(maj, min))
- return -EINVAL;
- subsystem_type = drmParseSubsystemType(maj, min);
- if (subsystem_type < 0)
- return subsystem_type;
- sysdir = opendir(DRM_DIR_NAME);
- if (!sysdir)
- return -errno;
- i = 0;
- while ((dent = readdir(sysdir))) {
- ret = process_device(&d, dent->d_name, subsystem_type, true, flags);
- if (ret)
- continue;
- if (i >= MAX_DRM_NODES) {
- fprintf(stderr, "More than %d drm nodes detected. "
- "Please report a bug - that should not happen.\n"
- "Skipping extra nodes\n", MAX_DRM_NODES);
- break;
- }
- local_devices[i] = d;
- i++;
- }
- node_count = i;
- drmFoldDuplicatedDevices(local_devices, node_count);
- *device = NULL;
- for (i = 0; i < node_count; i++) {
- if (!local_devices[i])
- continue;
- if (drm_device_has_rdev(local_devices[i], find_rdev))
- *device = local_devices[i];
- else
- drmFreeDevice(&local_devices[i]);
- }
- closedir(sysdir);
- if (*device == NULL)
- return -ENODEV;
- return 0;
- #endif
- }
- drm_public int drmGetNodeTypeFromDevId(dev_t devid)
- {
- int maj, min, node_type;
- maj = major(devid);
- min = minor(devid);
- if (!drmNodeIsDRM(maj, min))
- return -EINVAL;
- node_type = drmGetMinorType(maj, min);
- if (node_type == -1)
- return -ENODEV;
- return node_type;
- }
- /**
- * Get information about the opened drm device
- *
- * \param fd file descriptor of the drm device
- * \param flags feature/behaviour bitmask
- * \param device the address of a drmDevicePtr where the information
- * will be allocated in stored
- *
- * \return zero on success, negative error code otherwise.
- *
- * \note Unlike drmGetDevice it does not retrieve the pci device revision field
- * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
- */
- drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
- {
- struct stat sbuf;
- if (fd == -1)
- return -EINVAL;
- if (fstat(fd, &sbuf))
- return -errno;
- if (!S_ISCHR(sbuf.st_mode))
- return -EINVAL;
- return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device);
- }
- /**
- * Get information about the opened drm device
- *
- * \param fd file descriptor of the drm device
- * \param device the address of a drmDevicePtr where the information
- * will be allocated in stored
- *
- * \return zero on success, negative error code otherwise.
- */
- drm_public int drmGetDevice(int fd, drmDevicePtr *device)
- {
- return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
- }
- /**
- * Get drm devices on the system
- *
- * \param flags feature/behaviour bitmask
- * \param devices the array of devices with drmDevicePtr elements
- * can be NULL to get the device number first
- * \param max_devices the maximum number of devices for the array
- *
- * \return on error - negative error code,
- * if devices is NULL - total number of devices available on the system,
- * alternatively the number of devices stored in devices[], which is
- * capped by the max_devices.
- *
- * \note Unlike drmGetDevices it does not retrieve the pci device revision field
- * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
- */
- drm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[],
- int max_devices)
- {
- drmDevicePtr local_devices[MAX_DRM_NODES];
- drmDevicePtr device;
- DIR *sysdir;
- struct dirent *dent;
- int ret, i, node_count, device_count;
- if (drm_device_validate_flags(flags))
- return -EINVAL;
- sysdir = opendir(DRM_DIR_NAME);
- if (!sysdir)
- return -errno;
- i = 0;
- while ((dent = readdir(sysdir))) {
- ret = process_device(&device, dent->d_name, -1, devices != NULL, flags);
- if (ret)
- continue;
- if (i >= MAX_DRM_NODES) {
- fprintf(stderr, "More than %d drm nodes detected. "
- "Please report a bug - that should not happen.\n"
- "Skipping extra nodes\n", MAX_DRM_NODES);
- break;
- }
- local_devices[i] = device;
- i++;
- }
- node_count = i;
- drmFoldDuplicatedDevices(local_devices, node_count);
- device_count = 0;
- for (i = 0; i < node_count; i++) {
- if (!local_devices[i])
- continue;
- if ((devices != NULL) && (device_count < max_devices))
- devices[device_count] = local_devices[i];
- else
- drmFreeDevice(&local_devices[i]);
- device_count++;
- }
- closedir(sysdir);
- if (devices != NULL)
- return MIN2(device_count, max_devices);
- return device_count;
- }
- /**
- * Get drm devices on the system
- *
- * \param devices the array of devices with drmDevicePtr elements
- * can be NULL to get the device number first
- * \param max_devices the maximum number of devices for the array
- *
- * \return on error - negative error code,
- * if devices is NULL - total number of devices available on the system,
- * alternatively the number of devices stored in devices[], which is
- * capped by the max_devices.
- */
- drm_public int drmGetDevices(drmDevicePtr devices[], int max_devices)
- {
- return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
- }
- drm_public char *drmGetDeviceNameFromFd2(int fd)
- {
- #ifdef __linux__
- struct stat sbuf;
- char path[PATH_MAX + 1], *value;
- unsigned int maj, min;
- if (fstat(fd, &sbuf))
- return NULL;
- maj = major(sbuf.st_rdev);
- min = minor(sbuf.st_rdev);
- if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
- return NULL;
- snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
- value = sysfs_uevent_get(path, "DEVNAME");
- if (!value)
- return NULL;
- snprintf(path, sizeof(path), "/dev/%s", value);
- free(value);
- return strdup(path);
- #elif defined(__FreeBSD__)
- return drmGetDeviceNameFromFd(fd);
- #else
- struct stat sbuf;
- char node[PATH_MAX + 1];
- const char *dev_name;
- int node_type;
- int maj, min, n;
- if (fstat(fd, &sbuf))
- return NULL;
- maj = major(sbuf.st_rdev);
- min = minor(sbuf.st_rdev);
- if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
- return NULL;
- node_type = drmGetMinorType(maj, min);
- if (node_type == -1)
- return NULL;
- dev_name = drmGetDeviceName(node_type);
- if (!dev_name)
- return NULL;
- n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
- if (n == -1 || n >= PATH_MAX)
- return NULL;
- return strdup(node);
- #endif
- }
- drm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle)
- {
- struct drm_syncobj_create args;
- int ret;
- memclear(args);
- args.flags = flags;
- args.handle = 0;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
- if (ret)
- return ret;
- *handle = args.handle;
- return 0;
- }
- drm_public int drmSyncobjDestroy(int fd, uint32_t handle)
- {
- struct drm_syncobj_destroy args;
- memclear(args);
- args.handle = handle;
- return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
- }
- drm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd)
- {
- struct drm_syncobj_handle args;
- int ret;
- memclear(args);
- args.fd = -1;
- args.handle = handle;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
- if (ret)
- return ret;
- *obj_fd = args.fd;
- return 0;
- }
- drm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle)
- {
- struct drm_syncobj_handle args;
- int ret;
- memclear(args);
- args.fd = obj_fd;
- args.handle = 0;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
- if (ret)
- return ret;
- *handle = args.handle;
- return 0;
- }
- drm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle,
- int sync_file_fd)
- {
- struct drm_syncobj_handle args;
- memclear(args);
- args.fd = sync_file_fd;
- args.handle = handle;
- args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
- return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
- }
- drm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle,
- int *sync_file_fd)
- {
- struct drm_syncobj_handle args;
- int ret;
- memclear(args);
- args.fd = -1;
- args.handle = handle;
- args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
- if (ret)
- return ret;
- *sync_file_fd = args.fd;
- return 0;
- }
- drm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
- int64_t timeout_nsec, unsigned flags,
- uint32_t *first_signaled)
- {
- struct drm_syncobj_wait args;
- int ret;
- memclear(args);
- args.handles = (uintptr_t)handles;
- args.timeout_nsec = timeout_nsec;
- args.count_handles = num_handles;
- args.flags = flags;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
- if (ret < 0)
- return -errno;
- if (first_signaled)
- *first_signaled = args.first_signaled;
- return ret;
- }
- drm_public int drmSyncobjReset(int fd, const uint32_t *handles,
- uint32_t handle_count)
- {
- struct drm_syncobj_array args;
- int ret;
- memclear(args);
- args.handles = (uintptr_t)handles;
- args.count_handles = handle_count;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
- return ret;
- }
- drm_public int drmSyncobjSignal(int fd, const uint32_t *handles,
- uint32_t handle_count)
- {
- struct drm_syncobj_array args;
- int ret;
- memclear(args);
- args.handles = (uintptr_t)handles;
- args.count_handles = handle_count;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
- return ret;
- }
- drm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles,
- uint64_t *points, uint32_t handle_count)
- {
- struct drm_syncobj_timeline_array args;
- int ret;
- memclear(args);
- args.handles = (uintptr_t)handles;
- args.points = (uintptr_t)points;
- args.count_handles = handle_count;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
- return ret;
- }
- drm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points,
- unsigned num_handles,
- int64_t timeout_nsec, unsigned flags,
- uint32_t *first_signaled)
- {
- struct drm_syncobj_timeline_wait args;
- int ret;
- memclear(args);
- args.handles = (uintptr_t)handles;
- args.points = (uintptr_t)points;
- args.timeout_nsec = timeout_nsec;
- args.count_handles = num_handles;
- args.flags = flags;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args);
- if (ret < 0)
- return -errno;
- if (first_signaled)
- *first_signaled = args.first_signaled;
- return ret;
- }
- drm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points,
- uint32_t handle_count)
- {
- struct drm_syncobj_timeline_array args;
- int ret;
- memclear(args);
- args.handles = (uintptr_t)handles;
- args.points = (uintptr_t)points;
- args.count_handles = handle_count;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
- if (ret)
- return ret;
- return 0;
- }
- drm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points,
- uint32_t handle_count, uint32_t flags)
- {
- struct drm_syncobj_timeline_array args;
- memclear(args);
- args.handles = (uintptr_t)handles;
- args.points = (uintptr_t)points;
- args.count_handles = handle_count;
- args.flags = flags;
- return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
- }
- drm_public int drmSyncobjTransfer(int fd,
- uint32_t dst_handle, uint64_t dst_point,
- uint32_t src_handle, uint64_t src_point,
- uint32_t flags)
- {
- struct drm_syncobj_transfer args;
- int ret;
- memclear(args);
- args.src_handle = src_handle;
- args.dst_handle = dst_handle;
- args.src_point = src_point;
- args.dst_point = dst_point;
- args.flags = flags;
- ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
- return ret;
- }
- drm_public int drmSyncobjEventfd(int fd, uint32_t handle, uint64_t point, int ev_fd,
- uint32_t flags)
- {
- struct drm_syncobj_eventfd args;
- memclear(args);
- args.handle = handle;
- args.point = point;
- args.fd = ev_fd;
- args.flags = flags;
- return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_EVENTFD, &args);
- }
- static char *
- drmGetFormatModifierFromSimpleTokens(uint64_t modifier)
- {
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(drm_format_modifier_table); i++) {
- if (drm_format_modifier_table[i].modifier == modifier)
- return strdup(drm_format_modifier_table[i].modifier_name);
- }
- return NULL;
- }
- /** Retrieves a human-readable representation of a vendor (as a string) from
- * the format token modifier
- *
- * \param modifier the format modifier token
- * \return a char pointer to the human-readable form of the vendor. Caller is
- * responsible for freeing it.
- */
- drm_public char *
- drmGetFormatModifierVendor(uint64_t modifier)
- {
- unsigned int i;
- uint8_t vendor = fourcc_mod_get_vendor(modifier);
- for (i = 0; i < ARRAY_SIZE(drm_format_modifier_vendor_table); i++) {
- if (drm_format_modifier_vendor_table[i].vendor == vendor)
- return strdup(drm_format_modifier_vendor_table[i].vendor_name);
- }
- return NULL;
- }
- /** Retrieves a human-readable representation string from a format token
- * modifier
- *
- * If the dedicated function was not able to extract a valid name or searching
- * the format modifier was not in the table, this function would return NULL.
- *
- * \param modifier the token format
- * \return a malloc'ed string representation of the modifier. Caller is
- * responsible for freeing the string returned.
- *
- */
- drm_public char *
- drmGetFormatModifierName(uint64_t modifier)
- {
- uint8_t vendorid = fourcc_mod_get_vendor(modifier);
- char *modifier_found = NULL;
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(modifier_format_vendor_table); i++) {
- if (modifier_format_vendor_table[i].vendor == vendorid)
- modifier_found = modifier_format_vendor_table[i].vendor_cb(modifier);
- }
- if (!modifier_found)
- return drmGetFormatModifierFromSimpleTokens(modifier);
- return modifier_found;
- }
- /**
- * Get a human-readable name for a DRM FourCC format.
- *
- * \param format The format.
- * \return A malloc'ed string containing the format name. Caller is responsible
- * for freeing it.
- */
- drm_public char *
- drmGetFormatName(uint32_t format)
- {
- char *str, code[5];
- const char *be;
- size_t str_size, i;
- be = (format & DRM_FORMAT_BIG_ENDIAN) ? "_BE" : "";
- format &= ~DRM_FORMAT_BIG_ENDIAN;
- if (format == DRM_FORMAT_INVALID)
- return strdup("INVALID");
- code[0] = (char) ((format >> 0) & 0xFF);
- code[1] = (char) ((format >> 8) & 0xFF);
- code[2] = (char) ((format >> 16) & 0xFF);
- code[3] = (char) ((format >> 24) & 0xFF);
- code[4] = '\0';
- /* Trim spaces at the end */
- for (i = 3; i > 0 && code[i] == ' '; i--)
- code[i] = '\0';
- str_size = strlen(code) + strlen(be) + 1;
- str = malloc(str_size);
- if (!str)
- return NULL;
- snprintf(str, str_size, "%s%s", code, be);
- return str;
- }
|