xf86drm.c 132 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298
  1. /**
  2. * \file xf86drm.c
  3. * User-level interface to DRM device
  4. *
  5. */
  6. /*
  7. * SPDX-FileContributor: Rickard E. (Rik) Faith <faith@valinux.com>
  8. * SPDX-FileContributor: Kevin E. Martin <martin@valinux.com>
  9. * SPDX-FileCopyrightText: 1999 Precision Insight, Inc., Cedar Park, Texas.
  10. * SPDX-FileCopyrightText: 2000 VA Linux Systems, Inc., Sunnyvale, California.
  11. * SPDX-License-Identifier: MIT
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <stdbool.h>
  16. #include <unistd.h>
  17. #include <string.h>
  18. #include <strings.h>
  19. #include <ctype.h>
  20. #include <dirent.h>
  21. #include <stddef.h>
  22. #include <fcntl.h>
  23. #include <errno.h>
  24. #include <libgen.h>
  25. #include <limits.h>
  26. #include <signal.h>
  27. #include <time.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #define stat_t struct stat
  31. #include <sys/ioctl.h>
  32. #include <sys/time.h>
  33. #include <stdarg.h>
  34. #ifdef MAJOR_IN_MKDEV
  35. #include <sys/mkdev.h>
  36. #endif
  37. #ifdef MAJOR_IN_SYSMACROS
  38. #include <sys/sysmacros.h>
  39. #endif
  40. #if HAVE_SYS_SYSCTL_H
  41. #include <sys/sysctl.h>
  42. #endif
  43. #include <inttypes.h>
  44. #if defined(__FreeBSD__)
  45. #include <sys/param.h>
  46. #include <sys/pciio.h>
  47. #endif
  48. #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
  49. /* Not all systems have MAP_FAILED defined */
  50. #ifndef MAP_FAILED
  51. #define MAP_FAILED ((void *)-1)
  52. #endif
  53. #include "xf86drm.h"
  54. #include "libdrm_macros.h"
  55. #include "drm_fourcc.h"
  56. #include "util_math.h"
  57. #ifdef __DragonFly__
  58. #define DRM_MAJOR 145
  59. #endif
  60. #ifdef __NetBSD__
  61. #define DRM_MAJOR 34
  62. #endif
  63. #ifdef __OpenBSD__
  64. #ifdef __i386__
  65. #define DRM_MAJOR 88
  66. #else
  67. #define DRM_MAJOR 87
  68. #endif
  69. #endif /* __OpenBSD__ */
  70. #ifndef DRM_MAJOR
  71. #define DRM_MAJOR 226 /* Linux */
  72. #endif
  73. #if defined(__OpenBSD__) || defined(__DragonFly__)
  74. struct drm_pciinfo {
  75. uint16_t domain;
  76. uint8_t bus;
  77. uint8_t dev;
  78. uint8_t func;
  79. uint16_t vendor_id;
  80. uint16_t device_id;
  81. uint16_t subvendor_id;
  82. uint16_t subdevice_id;
  83. uint8_t revision_id;
  84. };
  85. #define DRM_IOCTL_GET_PCIINFO DRM_IOR(0x15, struct drm_pciinfo)
  86. #endif
  87. #define DRM_MSG_VERBOSITY 3
  88. #define memclear(s) memset(&s, 0, sizeof(s))
  89. static drmServerInfoPtr drm_server_info;
  90. static bool drmNodeIsDRM(int maj, int min);
  91. static char *drmGetMinorNameForFD(int fd, int type);
  92. #define DRM_MODIFIER(v, f, f_name) \
  93. .modifier = DRM_FORMAT_MOD_##v ## _ ##f, \
  94. .modifier_name = #f_name
  95. #define DRM_MODIFIER_INVALID(v, f_name) \
  96. .modifier = DRM_FORMAT_MOD_INVALID, .modifier_name = #f_name
  97. #define DRM_MODIFIER_LINEAR(v, f_name) \
  98. .modifier = DRM_FORMAT_MOD_LINEAR, .modifier_name = #f_name
  99. /* Intel is abit special as the format doesn't follow other vendors naming
  100. * scheme */
  101. #define DRM_MODIFIER_INTEL(f, f_name) \
  102. .modifier = I915_FORMAT_MOD_##f, .modifier_name = #f_name
  103. struct drmFormatModifierInfo {
  104. uint64_t modifier;
  105. const char *modifier_name;
  106. };
  107. struct drmFormatModifierVendorInfo {
  108. uint8_t vendor;
  109. const char *vendor_name;
  110. };
  111. #include "generated_static_table_fourcc.h"
  112. struct drmVendorInfo {
  113. uint8_t vendor;
  114. char *(*vendor_cb)(uint64_t modifier);
  115. };
  116. struct drmFormatVendorModifierInfo {
  117. uint64_t modifier;
  118. const char *modifier_name;
  119. };
  120. static char *
  121. drmGetFormatModifierNameFromArm(uint64_t modifier);
  122. static char *
  123. drmGetFormatModifierNameFromNvidia(uint64_t modifier);
  124. static char *
  125. drmGetFormatModifierNameFromAmd(uint64_t modifier);
  126. static char *
  127. drmGetFormatModifierNameFromAmlogic(uint64_t modifier);
  128. static char *
  129. drmGetFormatModifierNameFromVivante(uint64_t modifier);
  130. static const struct drmVendorInfo modifier_format_vendor_table[] = {
  131. { DRM_FORMAT_MOD_VENDOR_ARM, drmGetFormatModifierNameFromArm },
  132. { DRM_FORMAT_MOD_VENDOR_NVIDIA, drmGetFormatModifierNameFromNvidia },
  133. { DRM_FORMAT_MOD_VENDOR_AMD, drmGetFormatModifierNameFromAmd },
  134. { DRM_FORMAT_MOD_VENDOR_AMLOGIC, drmGetFormatModifierNameFromAmlogic },
  135. { DRM_FORMAT_MOD_VENDOR_VIVANTE, drmGetFormatModifierNameFromVivante },
  136. };
  137. #ifndef AFBC_FORMAT_MOD_MODE_VALUE_MASK
  138. #define AFBC_FORMAT_MOD_MODE_VALUE_MASK 0x000fffffffffffffULL
  139. #endif
  140. static const struct drmFormatVendorModifierInfo arm_mode_value_table[] = {
  141. { AFBC_FORMAT_MOD_YTR, "YTR" },
  142. { AFBC_FORMAT_MOD_SPLIT, "SPLIT" },
  143. { AFBC_FORMAT_MOD_SPARSE, "SPARSE" },
  144. { AFBC_FORMAT_MOD_CBR, "CBR" },
  145. { AFBC_FORMAT_MOD_TILED, "TILED" },
  146. { AFBC_FORMAT_MOD_SC, "SC" },
  147. { AFBC_FORMAT_MOD_DB, "DB" },
  148. { AFBC_FORMAT_MOD_BCH, "BCH" },
  149. { AFBC_FORMAT_MOD_USM, "USM" },
  150. };
  151. static bool
  152. drmGetAfbcFormatModifierNameFromArm(uint64_t modifier, FILE *fp)
  153. {
  154. uint64_t mode_value = modifier & AFBC_FORMAT_MOD_MODE_VALUE_MASK;
  155. uint64_t block_size = mode_value & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
  156. const char *block = NULL;
  157. const char *mode = NULL;
  158. bool did_print_mode = false;
  159. /* add block, can only have a (single) block */
  160. switch (block_size) {
  161. case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
  162. block = "16x16";
  163. break;
  164. case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
  165. block = "32x8";
  166. break;
  167. case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
  168. block = "64x4";
  169. break;
  170. case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
  171. block = "32x8_64x4";
  172. break;
  173. }
  174. if (!block) {
  175. return false;
  176. }
  177. fprintf(fp, "BLOCK_SIZE=%s,", block);
  178. /* add mode */
  179. for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_value_table); i++) {
  180. if (arm_mode_value_table[i].modifier & mode_value) {
  181. mode = arm_mode_value_table[i].modifier_name;
  182. if (!did_print_mode) {
  183. fprintf(fp, "MODE=%s", mode);
  184. did_print_mode = true;
  185. } else {
  186. fprintf(fp, "|%s", mode);
  187. }
  188. }
  189. }
  190. return true;
  191. }
  192. static bool
  193. drmGetAfrcFormatModifierNameFromArm(uint64_t modifier, FILE *fp)
  194. {
  195. bool scan_layout;
  196. for (unsigned int i = 0; i < 2; ++i) {
  197. uint64_t coding_unit_block =
  198. (modifier >> (i * 4)) & AFRC_FORMAT_MOD_CU_SIZE_MASK;
  199. const char *coding_unit_size = NULL;
  200. switch (coding_unit_block) {
  201. case AFRC_FORMAT_MOD_CU_SIZE_16:
  202. coding_unit_size = "CU_16";
  203. break;
  204. case AFRC_FORMAT_MOD_CU_SIZE_24:
  205. coding_unit_size = "CU_24";
  206. break;
  207. case AFRC_FORMAT_MOD_CU_SIZE_32:
  208. coding_unit_size = "CU_32";
  209. break;
  210. }
  211. if (!coding_unit_size) {
  212. if (i == 0) {
  213. return false;
  214. }
  215. break;
  216. }
  217. if (i == 0) {
  218. fprintf(fp, "P0=%s,", coding_unit_size);
  219. } else {
  220. fprintf(fp, "P12=%s,", coding_unit_size);
  221. }
  222. }
  223. scan_layout =
  224. (modifier & AFRC_FORMAT_MOD_LAYOUT_SCAN) == AFRC_FORMAT_MOD_LAYOUT_SCAN;
  225. if (scan_layout) {
  226. fprintf(fp, "SCAN");
  227. } else {
  228. fprintf(fp, "ROT");
  229. }
  230. return true;
  231. }
  232. static char *
  233. drmGetFormatModifierNameFromArm(uint64_t modifier)
  234. {
  235. uint64_t type = (modifier >> 52) & 0xf;
  236. FILE *fp;
  237. size_t size = 0;
  238. char *modifier_name = NULL;
  239. bool result = false;
  240. fp = open_memstream(&modifier_name, &size);
  241. if (!fp)
  242. return NULL;
  243. switch (type) {
  244. case DRM_FORMAT_MOD_ARM_TYPE_AFBC:
  245. result = drmGetAfbcFormatModifierNameFromArm(modifier, fp);
  246. break;
  247. case DRM_FORMAT_MOD_ARM_TYPE_AFRC:
  248. result = drmGetAfrcFormatModifierNameFromArm(modifier, fp);
  249. break;
  250. /* misc type is already handled by the static table */
  251. case DRM_FORMAT_MOD_ARM_TYPE_MISC:
  252. default:
  253. result = false;
  254. break;
  255. }
  256. fclose(fp);
  257. if (!result) {
  258. free(modifier_name);
  259. return NULL;
  260. }
  261. return modifier_name;
  262. }
  263. static char *
  264. drmGetFormatModifierNameFromNvidia(uint64_t modifier)
  265. {
  266. uint64_t height, kind, gen, sector, compression;
  267. height = modifier & 0xf;
  268. kind = (modifier >> 12) & 0xff;
  269. gen = (modifier >> 20) & 0x3;
  270. sector = (modifier >> 22) & 0x1;
  271. compression = (modifier >> 23) & 0x7;
  272. /* just in case there could other simpler modifiers, not yet added, avoid
  273. * testing against TEGRA_TILE */
  274. if ((modifier & 0x10) == 0x10) {
  275. char *mod_nvidia;
  276. if (asprintf(&mod_nvidia, "BLOCK_LINEAR_2D,HEIGHT=%"PRIu64",KIND=%"PRIu64","
  277. "GEN=%"PRIu64",SECTOR=%"PRIu64",COMPRESSION=%"PRIu64"", height,
  278. kind, gen, sector, compression) < 0)
  279. mod_nvidia = NULL;
  280. return mod_nvidia;
  281. }
  282. return NULL;
  283. }
  284. static char *
  285. drmGetFormatModifierNameFromAmd(uint64_t modifier)
  286. {
  287. static const char *gfx9_gfx11_tile_strings[32] = {
  288. "LINEAR",
  289. "256B_S",
  290. "256B_D",
  291. "256B_R",
  292. "4KB_Z",
  293. "4KB_S",
  294. "4KB_D",
  295. "4KB_R",
  296. "64KB_Z",
  297. "64KB_S",
  298. "64KB_D",
  299. "64KB_R",
  300. "INVALID12",
  301. "INVALID13",
  302. "INVALID14",
  303. "INVALID15",
  304. "64KB_Z_T",
  305. "64KB_S_T",
  306. "64KB_D_T",
  307. "64KB_R_T",
  308. "4KB_Z_X",
  309. "4KB_S_X",
  310. "4KB_D_X",
  311. "4KB_R_X",
  312. "64KB_Z_X",
  313. "64KB_S_X",
  314. "64KB_D_X",
  315. "64KB_R_X",
  316. "256KB_Z_X",
  317. "256KB_S_X",
  318. "256KB_D_X",
  319. "256KB_R_X",
  320. };
  321. static const char *gfx12_tile_strings[32] = {
  322. "LINEAR",
  323. "256B_2D",
  324. "4KB_2D",
  325. "64KB_2D",
  326. "256KB_2D",
  327. "4KB_3D",
  328. "64KB_3D",
  329. "256KB_3D",
  330. /* other values are unused */
  331. };
  332. uint64_t tile_version = AMD_FMT_MOD_GET(TILE_VERSION, modifier);
  333. FILE *fp;
  334. char *mod_amd = NULL;
  335. size_t size = 0;
  336. fp = open_memstream(&mod_amd, &size);
  337. if (!fp)
  338. return NULL;
  339. switch (tile_version) {
  340. case AMD_FMT_MOD_TILE_VER_GFX9:
  341. fprintf(fp, "GFX9");
  342. break;
  343. case AMD_FMT_MOD_TILE_VER_GFX10:
  344. fprintf(fp, "GFX10");
  345. break;
  346. case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS:
  347. fprintf(fp, "GFX10_RBPLUS");
  348. break;
  349. case AMD_FMT_MOD_TILE_VER_GFX11:
  350. fprintf(fp, "GFX11");
  351. break;
  352. case AMD_FMT_MOD_TILE_VER_GFX12:
  353. fprintf(fp, "GFX12");
  354. break;
  355. default:
  356. fclose(fp);
  357. free(mod_amd);
  358. return NULL;
  359. }
  360. if (tile_version >= AMD_FMT_MOD_TILE_VER_GFX12) {
  361. unsigned tile = AMD_FMT_MOD_GET(TILE, modifier);
  362. fprintf(fp, ",%s", gfx12_tile_strings[tile]);
  363. if (AMD_FMT_MOD_GET(DCC, modifier)) {
  364. fprintf(fp, ",DCC,DCC_MAX_COMPRESSED_BLOCK=%uB",
  365. 64 << AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier));
  366. /* Other DCC fields are unused by GFX12. */
  367. }
  368. } else {
  369. unsigned tile = AMD_FMT_MOD_GET(TILE, modifier);
  370. fprintf(fp, ",%s", gfx9_gfx11_tile_strings[tile]);
  371. /* All *_T and *_X modes are affected by chip-specific fields. */
  372. if (tile >= 16) {
  373. fprintf(fp, ",PIPE_XOR_BITS=%u",
  374. (unsigned)AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier));
  375. switch (tile_version) {
  376. case AMD_FMT_MOD_TILE_VER_GFX9:
  377. fprintf(fp, ",BANK_XOR_BITS=%u",
  378. (unsigned)AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier));
  379. break;
  380. case AMD_FMT_MOD_TILE_VER_GFX10:
  381. /* Nothing else for GFX10. */
  382. break;
  383. case AMD_FMT_MOD_TILE_VER_GFX10_RBPLUS:
  384. case AMD_FMT_MOD_TILE_VER_GFX11:
  385. /* This also determines the DCC layout, but DCC is only legal
  386. * with tile=27 and tile=31 (*_R_X modes).
  387. */
  388. fprintf(fp, ",PACKERS=%u",
  389. (unsigned)AMD_FMT_MOD_GET(PACKERS, modifier));
  390. break;
  391. }
  392. }
  393. if (AMD_FMT_MOD_GET(DCC, modifier)) {
  394. if (tile_version == AMD_FMT_MOD_TILE_VER_GFX9 &&
  395. (AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier) ||
  396. AMD_FMT_MOD_GET(DCC_RETILE, modifier))) {
  397. /* These two only determine the layout of
  398. * the non-displayable DCC plane.
  399. */
  400. fprintf(fp, ",RB=%u",
  401. (unsigned)AMD_FMT_MOD_GET(RB, modifier));
  402. fprintf(fp, ",PIPE=%u",
  403. (unsigned)AMD_FMT_MOD_GET(PIPE, modifier));
  404. }
  405. fprintf(fp, ",DCC,DCC_MAX_COMPRESSED_BLOCK=%uB",
  406. 64 << AMD_FMT_MOD_GET(DCC_MAX_COMPRESSED_BLOCK, modifier));
  407. if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_64B, modifier))
  408. fprintf(fp, ",DCC_INDEPENDENT_64B");
  409. if (AMD_FMT_MOD_GET(DCC_INDEPENDENT_128B, modifier))
  410. fprintf(fp, ",DCC_INDEPENDENT_128B");
  411. if (AMD_FMT_MOD_GET(DCC_CONSTANT_ENCODE, modifier))
  412. fprintf(fp, ",DCC_CONSTANT_ENCODE");
  413. if (AMD_FMT_MOD_GET(DCC_PIPE_ALIGN, modifier))
  414. fprintf(fp, ",DCC_PIPE_ALIGN");
  415. if (AMD_FMT_MOD_GET(DCC_RETILE, modifier))
  416. fprintf(fp, ",DCC_RETILE");
  417. }
  418. }
  419. fclose(fp);
  420. return mod_amd;
  421. }
  422. static char *
  423. drmGetFormatModifierNameFromAmlogic(uint64_t modifier)
  424. {
  425. uint64_t layout = modifier & 0xff;
  426. uint64_t options = (modifier >> 8) & 0xff;
  427. char *mod_amlogic = NULL;
  428. const char *layout_str;
  429. const char *opts_str;
  430. switch (layout) {
  431. case AMLOGIC_FBC_LAYOUT_BASIC:
  432. layout_str = "BASIC";
  433. break;
  434. case AMLOGIC_FBC_LAYOUT_SCATTER:
  435. layout_str = "SCATTER";
  436. break;
  437. default:
  438. layout_str = "INVALID_LAYOUT";
  439. break;
  440. }
  441. if (options & AMLOGIC_FBC_OPTION_MEM_SAVING)
  442. opts_str = "MEM_SAVING";
  443. else
  444. opts_str = "0";
  445. if (asprintf(&mod_amlogic, "FBC,LAYOUT=%s,OPTIONS=%s", layout_str, opts_str) < 0)
  446. mod_amlogic = NULL;
  447. return mod_amlogic;
  448. }
  449. static char *
  450. drmGetFormatModifierNameFromVivante(uint64_t modifier)
  451. {
  452. const char *color_tiling, *tile_status, *compression;
  453. char *mod_vivante = NULL;
  454. switch (modifier & VIVANTE_MOD_TS_MASK) {
  455. case 0:
  456. tile_status = "";
  457. break;
  458. case VIVANTE_MOD_TS_64_4:
  459. tile_status = ",TS=64B_4";
  460. break;
  461. case VIVANTE_MOD_TS_64_2:
  462. tile_status = ",TS=64B_2";
  463. break;
  464. case VIVANTE_MOD_TS_128_4:
  465. tile_status = ",TS=128B_4";
  466. break;
  467. case VIVANTE_MOD_TS_256_4:
  468. tile_status = ",TS=256B_4";
  469. break;
  470. default:
  471. tile_status = ",TS=UNKNOWN";
  472. break;
  473. }
  474. switch (modifier & VIVANTE_MOD_COMP_MASK) {
  475. case 0:
  476. compression = "";
  477. break;
  478. case VIVANTE_MOD_COMP_DEC400:
  479. compression = ",COMP=DEC400";
  480. break;
  481. default:
  482. compression = ",COMP=UNKNOWN";
  483. break;
  484. }
  485. switch (modifier & ~VIVANTE_MOD_EXT_MASK) {
  486. case 0:
  487. color_tiling = "LINEAR";
  488. break;
  489. case DRM_FORMAT_MOD_VIVANTE_TILED:
  490. color_tiling = "TILED";
  491. break;
  492. case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
  493. color_tiling = "SUPER_TILED";
  494. break;
  495. case DRM_FORMAT_MOD_VIVANTE_SPLIT_TILED:
  496. color_tiling = "SPLIT_TILED";
  497. break;
  498. case DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED:
  499. color_tiling = "SPLIT_SUPER_TILED";
  500. break;
  501. default:
  502. color_tiling = "UNKNOWN";
  503. break;
  504. }
  505. if (asprintf(&mod_vivante, "%s%s%s", color_tiling, tile_status, compression) < 0)
  506. mod_vivante = NULL;
  507. return mod_vivante;
  508. }
  509. static unsigned log2_int(unsigned x)
  510. {
  511. unsigned l;
  512. if (x < 2) {
  513. return 0;
  514. }
  515. for (l = 2; ; l++) {
  516. if ((unsigned)(1 << l) > x) {
  517. return l - 1;
  518. }
  519. }
  520. return 0;
  521. }
  522. drm_public void drmSetServerInfo(drmServerInfoPtr info)
  523. {
  524. drm_server_info = info;
  525. }
  526. /**
  527. * Output a message to stderr.
  528. *
  529. * \param format printf() like format string.
  530. *
  531. * \internal
  532. * This function is a wrapper around vfprintf().
  533. */
  534. static int DRM_PRINTFLIKE(1, 0)
  535. drmDebugPrint(const char *format, va_list ap)
  536. {
  537. return vfprintf(stderr, format, ap);
  538. }
  539. drm_public void
  540. drmMsg(const char *format, ...)
  541. {
  542. va_list ap;
  543. const char *env;
  544. if (((env = getenv("LIBGL_DEBUG")) && strstr(env, "verbose")) ||
  545. (drm_server_info && drm_server_info->debug_print))
  546. {
  547. va_start(ap, format);
  548. if (drm_server_info) {
  549. drm_server_info->debug_print(format,ap);
  550. } else {
  551. drmDebugPrint(format, ap);
  552. }
  553. va_end(ap);
  554. }
  555. }
  556. static void *drmHashTable = NULL; /* Context switch callbacks */
  557. drm_public void *drmGetHashTable(void)
  558. {
  559. return drmHashTable;
  560. }
  561. drm_public void *drmMalloc(int size)
  562. {
  563. return calloc(1, size);
  564. }
  565. drm_public void drmFree(void *pt)
  566. {
  567. free(pt);
  568. }
  569. /**
  570. * Call ioctl, restarting if it is interrupted
  571. */
  572. drm_public int
  573. drmIoctl(int fd, unsigned long request, void *arg)
  574. {
  575. int ret;
  576. do {
  577. ret = ioctl(fd, request, arg);
  578. } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
  579. return ret;
  580. }
  581. static unsigned long drmGetKeyFromFd(int fd)
  582. {
  583. stat_t st;
  584. st.st_rdev = 0;
  585. fstat(fd, &st);
  586. return st.st_rdev;
  587. }
  588. drm_public drmHashEntry *drmGetEntry(int fd)
  589. {
  590. unsigned long key = drmGetKeyFromFd(fd);
  591. void *value;
  592. drmHashEntry *entry;
  593. if (!drmHashTable)
  594. drmHashTable = drmHashCreate();
  595. if (drmHashLookup(drmHashTable, key, &value)) {
  596. entry = drmMalloc(sizeof(*entry));
  597. entry->fd = fd;
  598. entry->f = NULL;
  599. entry->tagTable = drmHashCreate();
  600. drmHashInsert(drmHashTable, key, entry);
  601. } else {
  602. entry = value;
  603. }
  604. return entry;
  605. }
  606. /**
  607. * Compare two busid strings
  608. *
  609. * \param first
  610. * \param second
  611. *
  612. * \return 1 if matched.
  613. *
  614. * \internal
  615. * This function compares two bus ID strings. It understands the older
  616. * PCI:b:d:f format and the newer pci:oooo:bb:dd.f format. In the format, o is
  617. * domain, b is bus, d is device, f is function.
  618. */
  619. static int drmMatchBusID(const char *id1, const char *id2, int pci_domain_ok)
  620. {
  621. /* First, check if the IDs are exactly the same */
  622. if (strcasecmp(id1, id2) == 0)
  623. return 1;
  624. /* Try to match old/new-style PCI bus IDs. */
  625. if (strncasecmp(id1, "pci", 3) == 0) {
  626. unsigned int o1, b1, d1, f1;
  627. unsigned int o2, b2, d2, f2;
  628. int ret;
  629. ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1);
  630. if (ret != 4) {
  631. o1 = 0;
  632. ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1);
  633. if (ret != 3)
  634. return 0;
  635. }
  636. ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2);
  637. if (ret != 4) {
  638. o2 = 0;
  639. ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2);
  640. if (ret != 3)
  641. return 0;
  642. }
  643. /* If domains aren't properly supported by the kernel interface,
  644. * just ignore them, which sucks less than picking a totally random
  645. * card with "open by name"
  646. */
  647. if (!pci_domain_ok)
  648. o1 = o2 = 0;
  649. if ((o1 != o2) || (b1 != b2) || (d1 != d2) || (f1 != f2))
  650. return 0;
  651. else
  652. return 1;
  653. }
  654. return 0;
  655. }
  656. /**
  657. * Handles error checking for chown call.
  658. *
  659. * \param path to file.
  660. * \param id of the new owner.
  661. * \param id of the new group.
  662. *
  663. * \return zero if success or -1 if failure.
  664. *
  665. * \internal
  666. * Checks for failure. If failure was caused by signal call chown again.
  667. * If any other failure happened then it will output error message using
  668. * drmMsg() call.
  669. */
  670. #if !UDEV
  671. static int chown_check_return(const char *path, uid_t owner, gid_t group)
  672. {
  673. int rv;
  674. do {
  675. rv = chown(path, owner, group);
  676. } while (rv != 0 && errno == EINTR);
  677. if (rv == 0)
  678. return 0;
  679. drmMsg("Failed to change owner or group for file %s! %d: %s\n",
  680. path, errno, strerror(errno));
  681. return -1;
  682. }
  683. #endif
  684. static const char *drmGetDeviceName(int type)
  685. {
  686. switch (type) {
  687. case DRM_NODE_PRIMARY:
  688. return DRM_DEV_NAME;
  689. case DRM_NODE_RENDER:
  690. return DRM_RENDER_DEV_NAME;
  691. }
  692. return NULL;
  693. }
  694. /**
  695. * Open the DRM device, creating it if necessary.
  696. *
  697. * \param dev major and minor numbers of the device.
  698. * \param minor minor number of the device.
  699. *
  700. * \return a file descriptor on success, or a negative value on error.
  701. *
  702. * \internal
  703. * Assembles the device name from \p minor and opens it, creating the device
  704. * special file node with the major and minor numbers specified by \p dev and
  705. * parent directory if necessary and was called by root.
  706. */
  707. static int drmOpenDevice(dev_t dev, int minor, int type)
  708. {
  709. stat_t st;
  710. const char *dev_name = drmGetDeviceName(type);
  711. char buf[DRM_NODE_NAME_MAX];
  712. int fd;
  713. mode_t devmode = DRM_DEV_MODE, serv_mode;
  714. gid_t serv_group;
  715. #if !UDEV
  716. int isroot = !geteuid();
  717. uid_t user = DRM_DEV_UID;
  718. gid_t group = DRM_DEV_GID;
  719. #endif
  720. if (!dev_name)
  721. return -EINVAL;
  722. sprintf(buf, dev_name, DRM_DIR_NAME, minor);
  723. drmMsg("drmOpenDevice: node name is %s\n", buf);
  724. if (drm_server_info && drm_server_info->get_perms) {
  725. drm_server_info->get_perms(&serv_group, &serv_mode);
  726. devmode = serv_mode ? serv_mode : DRM_DEV_MODE;
  727. devmode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
  728. }
  729. #if !UDEV
  730. if (stat(DRM_DIR_NAME, &st)) {
  731. if (!isroot)
  732. return DRM_ERR_NOT_ROOT;
  733. mkdir(DRM_DIR_NAME, DRM_DEV_DIRMODE);
  734. chown_check_return(DRM_DIR_NAME, 0, 0); /* root:root */
  735. chmod(DRM_DIR_NAME, DRM_DEV_DIRMODE);
  736. }
  737. /* Check if the device node exists and create it if necessary. */
  738. if (stat(buf, &st)) {
  739. if (!isroot)
  740. return DRM_ERR_NOT_ROOT;
  741. remove(buf);
  742. mknod(buf, S_IFCHR | devmode, dev);
  743. }
  744. if (drm_server_info && drm_server_info->get_perms) {
  745. group = ((int)serv_group >= 0) ? serv_group : DRM_DEV_GID;
  746. chown_check_return(buf, user, group);
  747. chmod(buf, devmode);
  748. }
  749. #else
  750. /* if we modprobed then wait for udev */
  751. {
  752. int udev_count = 0;
  753. wait_for_udev:
  754. if (stat(DRM_DIR_NAME, &st)) {
  755. usleep(20);
  756. udev_count++;
  757. if (udev_count == 50)
  758. return -1;
  759. goto wait_for_udev;
  760. }
  761. if (stat(buf, &st)) {
  762. usleep(20);
  763. udev_count++;
  764. if (udev_count == 50)
  765. return -1;
  766. goto wait_for_udev;
  767. }
  768. }
  769. #endif
  770. fd = open(buf, O_RDWR | O_CLOEXEC);
  771. drmMsg("drmOpenDevice: open result is %d, (%s)\n",
  772. fd, fd < 0 ? strerror(errno) : "OK");
  773. if (fd >= 0)
  774. return fd;
  775. #if !UDEV
  776. /* Check if the device node is not what we expect it to be, and recreate it
  777. * and try again if so.
  778. */
  779. if (st.st_rdev != dev) {
  780. if (!isroot)
  781. return DRM_ERR_NOT_ROOT;
  782. remove(buf);
  783. mknod(buf, S_IFCHR | devmode, dev);
  784. if (drm_server_info && drm_server_info->get_perms) {
  785. chown_check_return(buf, user, group);
  786. chmod(buf, devmode);
  787. }
  788. }
  789. fd = open(buf, O_RDWR | O_CLOEXEC);
  790. drmMsg("drmOpenDevice: open result is %d, (%s)\n",
  791. fd, fd < 0 ? strerror(errno) : "OK");
  792. if (fd >= 0)
  793. return fd;
  794. drmMsg("drmOpenDevice: Open failed\n");
  795. remove(buf);
  796. #endif
  797. return -errno;
  798. }
  799. /**
  800. * Open the DRM device
  801. *
  802. * \param minor device minor number.
  803. * \param create allow to create the device if set.
  804. *
  805. * \return a file descriptor on success, or a negative value on error.
  806. *
  807. * \internal
  808. * Calls drmOpenDevice() if \p create is set, otherwise assembles the device
  809. * name from \p minor and opens it.
  810. */
  811. static int drmOpenMinor(int minor, int create, int type)
  812. {
  813. int fd;
  814. char buf[DRM_NODE_NAME_MAX];
  815. const char *dev_name = drmGetDeviceName(type);
  816. if (create)
  817. return drmOpenDevice(makedev(DRM_MAJOR, minor), minor, type);
  818. if (!dev_name)
  819. return -EINVAL;
  820. sprintf(buf, dev_name, DRM_DIR_NAME, minor);
  821. if ((fd = open(buf, O_RDWR | O_CLOEXEC)) >= 0)
  822. return fd;
  823. return -errno;
  824. }
  825. /**
  826. * Determine whether the DRM kernel driver has been loaded.
  827. *
  828. * \return 1 if the DRM driver is loaded, 0 otherwise.
  829. *
  830. * \deprecated
  831. * This function doesn't work when a device goes away (as is often the case
  832. * with simpledrm). drmGetDevices2 should be used instead to enumerate DRM
  833. * devices.
  834. *
  835. * \internal
  836. * Determine the presence of the kernel driver by attempting to open the 0
  837. * minor and get version information. For backward compatibility with older
  838. * Linux implementations, /proc/dri is also checked.
  839. */
  840. drm_public int drmAvailable(void)
  841. {
  842. drmVersionPtr version;
  843. int retval = 0;
  844. int fd;
  845. if ((fd = drmOpenMinor(0, 1, DRM_NODE_PRIMARY)) < 0) {
  846. #ifdef __linux__
  847. /* Try proc for backward Linux compatibility */
  848. if (!access("/proc/dri/0", R_OK))
  849. return 1;
  850. #endif
  851. return 0;
  852. }
  853. if ((version = drmGetVersion(fd))) {
  854. retval = 1;
  855. drmFreeVersion(version);
  856. }
  857. close(fd);
  858. return retval;
  859. }
  860. static int drmGetMinorBase(int type)
  861. {
  862. switch (type) {
  863. case DRM_NODE_PRIMARY:
  864. return 0;
  865. case DRM_NODE_RENDER:
  866. return 128;
  867. default:
  868. return -1;
  869. };
  870. }
  871. static int drmGetMinorType(int major, int minor)
  872. {
  873. #ifdef __FreeBSD__
  874. char name[SPECNAMELEN];
  875. int id;
  876. if (!devname_r(makedev(major, minor), S_IFCHR, name, sizeof(name)))
  877. return -1;
  878. if (sscanf(name, "drm/%d", &id) != 1) {
  879. // If not in /dev/drm/ we have the type in the name
  880. if (sscanf(name, "dri/card%d\n", &id) >= 1)
  881. return DRM_NODE_PRIMARY;
  882. else if (sscanf(name, "dri/renderD%d\n", &id) >= 1)
  883. return DRM_NODE_RENDER;
  884. return -1;
  885. }
  886. minor = id;
  887. #endif
  888. char path[DRM_NODE_NAME_MAX];
  889. const char *dev_name;
  890. int i;
  891. for (i = DRM_NODE_PRIMARY; i < DRM_NODE_MAX; i++) {
  892. dev_name = drmGetDeviceName(i);
  893. if (!dev_name)
  894. continue;
  895. snprintf(path, sizeof(path), dev_name, DRM_DIR_NAME, minor);
  896. if (!access(path, F_OK))
  897. return i;
  898. }
  899. return -1;
  900. }
  901. static const char *drmGetMinorName(int type)
  902. {
  903. switch (type) {
  904. case DRM_NODE_PRIMARY:
  905. return DRM_PRIMARY_MINOR_NAME;
  906. case DRM_NODE_RENDER:
  907. return DRM_RENDER_MINOR_NAME;
  908. default:
  909. return NULL;
  910. }
  911. }
  912. /**
  913. * Open the device by bus ID.
  914. *
  915. * \param busid bus ID.
  916. * \param type device node type.
  917. *
  918. * \return a file descriptor on success, or a negative value on error.
  919. *
  920. * \internal
  921. * This function attempts to open every possible minor (up to DRM_MAX_MINOR),
  922. * comparing the device bus ID with the one supplied.
  923. *
  924. * \sa drmOpenMinor() and drmGetBusid().
  925. */
  926. static int drmOpenByBusid(const char *busid, int type)
  927. {
  928. int i, pci_domain_ok = 1;
  929. int fd;
  930. const char *buf;
  931. drmSetVersion sv;
  932. int base = drmGetMinorBase(type);
  933. if (base < 0)
  934. return -1;
  935. drmMsg("drmOpenByBusid: Searching for BusID %s\n", busid);
  936. for (i = base; i < base + DRM_MAX_MINOR; i++) {
  937. fd = drmOpenMinor(i, 1, type);
  938. drmMsg("drmOpenByBusid: drmOpenMinor returns %d\n", fd);
  939. if (fd >= 0) {
  940. /* We need to try for 1.4 first for proper PCI domain support
  941. * and if that fails, we know the kernel is busted
  942. */
  943. sv.drm_di_major = 1;
  944. sv.drm_di_minor = 4;
  945. sv.drm_dd_major = -1; /* Don't care */
  946. sv.drm_dd_minor = -1; /* Don't care */
  947. if (drmSetInterfaceVersion(fd, &sv)) {
  948. #ifndef __alpha__
  949. pci_domain_ok = 0;
  950. #endif
  951. sv.drm_di_major = 1;
  952. sv.drm_di_minor = 1;
  953. sv.drm_dd_major = -1; /* Don't care */
  954. sv.drm_dd_minor = -1; /* Don't care */
  955. drmMsg("drmOpenByBusid: Interface 1.4 failed, trying 1.1\n");
  956. drmSetInterfaceVersion(fd, &sv);
  957. }
  958. buf = drmGetBusid(fd);
  959. drmMsg("drmOpenByBusid: drmGetBusid reports %s\n", buf);
  960. if (buf && drmMatchBusID(buf, busid, pci_domain_ok)) {
  961. drmFreeBusid(buf);
  962. return fd;
  963. }
  964. if (buf)
  965. drmFreeBusid(buf);
  966. close(fd);
  967. }
  968. }
  969. return -1;
  970. }
  971. /**
  972. * Open the device by name.
  973. *
  974. * \param name driver name.
  975. * \param type the device node type.
  976. *
  977. * \return a file descriptor on success, or a negative value on error.
  978. *
  979. * \internal
  980. * This function opens the first minor number that matches the driver name and
  981. * isn't already in use. If it's in use it then it will already have a bus ID
  982. * assigned.
  983. *
  984. * \sa drmOpenMinor(), drmGetVersion() and drmGetBusid().
  985. */
  986. static int drmOpenByName(const char *name, int type)
  987. {
  988. int i;
  989. int fd;
  990. drmVersionPtr version;
  991. char * id;
  992. int base = drmGetMinorBase(type);
  993. if (base < 0)
  994. return -1;
  995. /*
  996. * Open the first minor number that matches the driver name and isn't
  997. * already in use. If it's in use it will have a busid assigned already.
  998. */
  999. for (i = base; i < base + DRM_MAX_MINOR; i++) {
  1000. if ((fd = drmOpenMinor(i, 1, type)) >= 0) {
  1001. if ((version = drmGetVersion(fd))) {
  1002. if (!strcmp(version->name, name)) {
  1003. drmFreeVersion(version);
  1004. id = drmGetBusid(fd);
  1005. drmMsg("drmGetBusid returned '%s'\n", id ? id : "NULL");
  1006. if (!id || !*id) {
  1007. if (id)
  1008. drmFreeBusid(id);
  1009. return fd;
  1010. } else {
  1011. drmFreeBusid(id);
  1012. }
  1013. } else {
  1014. drmFreeVersion(version);
  1015. }
  1016. }
  1017. close(fd);
  1018. }
  1019. }
  1020. #ifdef __linux__
  1021. /* Backward-compatibility /proc support */
  1022. for (i = 0; i < 8; i++) {
  1023. char proc_name[64], buf[512];
  1024. char *driver, *pt, *devstring;
  1025. int retcode;
  1026. sprintf(proc_name, "/proc/dri/%d/name", i);
  1027. if ((fd = open(proc_name, O_RDONLY)) >= 0) {
  1028. retcode = read(fd, buf, sizeof(buf)-1);
  1029. close(fd);
  1030. if (retcode > 0) {
  1031. buf[retcode-1] = '\0';
  1032. for (driver = pt = buf; *pt && *pt != ' '; ++pt)
  1033. ;
  1034. if (*pt) { /* Device is next */
  1035. *pt = '\0';
  1036. if (!strcmp(driver, name)) { /* Match */
  1037. for (devstring = ++pt; *pt && *pt != ' '; ++pt)
  1038. ;
  1039. if (*pt) { /* Found busid */
  1040. return drmOpenByBusid(++pt, type);
  1041. } else { /* No busid */
  1042. return drmOpenDevice(strtol(devstring, NULL, 0),i, type);
  1043. }
  1044. }
  1045. }
  1046. }
  1047. }
  1048. }
  1049. #endif
  1050. return -1;
  1051. }
  1052. /**
  1053. * Open the DRM device.
  1054. *
  1055. * Looks up the specified name and bus ID, and opens the device found. The
  1056. * entry in /dev/dri is created if necessary and if called by root.
  1057. *
  1058. * \param name driver name. Not referenced if bus ID is supplied.
  1059. * \param busid bus ID. Zero if not known.
  1060. *
  1061. * \return a file descriptor on success, or a negative value on error.
  1062. *
  1063. * \internal
  1064. * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
  1065. * otherwise.
  1066. */
  1067. drm_public int drmOpen(const char *name, const char *busid)
  1068. {
  1069. return drmOpenWithType(name, busid, DRM_NODE_PRIMARY);
  1070. }
  1071. /**
  1072. * Open the DRM device with specified type.
  1073. *
  1074. * Looks up the specified name and bus ID, and opens the device found. The
  1075. * entry in /dev/dri is created if necessary and if called by root.
  1076. *
  1077. * \param name driver name. Not referenced if bus ID is supplied.
  1078. * \param busid bus ID. Zero if not known.
  1079. * \param type the device node type to open, PRIMARY or RENDER
  1080. *
  1081. * \return a file descriptor on success, or a negative value on error.
  1082. *
  1083. * \internal
  1084. * It calls drmOpenByBusid() if \p busid is specified or drmOpenByName()
  1085. * otherwise.
  1086. */
  1087. drm_public int drmOpenWithType(const char *name, const char *busid, int type)
  1088. {
  1089. if (name != NULL && drm_server_info &&
  1090. drm_server_info->load_module && !drmAvailable()) {
  1091. /* try to load the kernel module */
  1092. if (!drm_server_info->load_module(name)) {
  1093. drmMsg("[drm] failed to load kernel module \"%s\"\n", name);
  1094. return -1;
  1095. }
  1096. }
  1097. if (busid) {
  1098. int fd = drmOpenByBusid(busid, type);
  1099. if (fd >= 0)
  1100. return fd;
  1101. }
  1102. if (name)
  1103. return drmOpenByName(name, type);
  1104. return -1;
  1105. }
  1106. drm_public int drmOpenControl(int minor)
  1107. {
  1108. return -EINVAL;
  1109. }
  1110. drm_public int drmOpenRender(int minor)
  1111. {
  1112. return drmOpenMinor(minor, 0, DRM_NODE_RENDER);
  1113. }
  1114. /**
  1115. * Free the version information returned by drmGetVersion().
  1116. *
  1117. * \param v pointer to the version information.
  1118. *
  1119. * \internal
  1120. * It frees the memory pointed by \p %v as well as all the non-null strings
  1121. * pointers in it.
  1122. */
  1123. drm_public void drmFreeVersion(drmVersionPtr v)
  1124. {
  1125. if (!v)
  1126. return;
  1127. drmFree(v->name);
  1128. drmFree(v->date);
  1129. drmFree(v->desc);
  1130. drmFree(v);
  1131. }
  1132. /**
  1133. * Free the non-public version information returned by the kernel.
  1134. *
  1135. * \param v pointer to the version information.
  1136. *
  1137. * \internal
  1138. * Used by drmGetVersion() to free the memory pointed by \p %v as well as all
  1139. * the non-null strings pointers in it.
  1140. */
  1141. static void drmFreeKernelVersion(drm_version_t *v)
  1142. {
  1143. if (!v)
  1144. return;
  1145. drmFree(v->name);
  1146. drmFree(v->date);
  1147. drmFree(v->desc);
  1148. drmFree(v);
  1149. }
  1150. /**
  1151. * Copy version information.
  1152. *
  1153. * \param d destination pointer.
  1154. * \param s source pointer.
  1155. *
  1156. * \internal
  1157. * Used by drmGetVersion() to translate the information returned by the ioctl
  1158. * interface in a private structure into the public structure counterpart.
  1159. */
  1160. static void drmCopyVersion(drmVersionPtr d, const drm_version_t *s)
  1161. {
  1162. d->version_major = s->version_major;
  1163. d->version_minor = s->version_minor;
  1164. d->version_patchlevel = s->version_patchlevel;
  1165. d->name_len = s->name_len;
  1166. d->name = s->name ? strdup(s->name) : NULL;
  1167. d->date_len = s->date_len;
  1168. d->date = s->date ? strdup(s->date) : NULL;
  1169. d->desc_len = s->desc_len;
  1170. d->desc = s->desc ? strdup(s->desc) : NULL;
  1171. }
  1172. /**
  1173. * Query the driver version information.
  1174. *
  1175. * \param fd file descriptor.
  1176. *
  1177. * \return pointer to a drmVersion structure which should be freed with
  1178. * drmFreeVersion().
  1179. *
  1180. * \note Similar information is available via /proc/dri.
  1181. *
  1182. * \internal
  1183. * It gets the version information via successive DRM_IOCTL_VERSION ioctls,
  1184. * first with zeros to get the string lengths, and then the actually strings.
  1185. * It also null-terminates them since they might not be already.
  1186. */
  1187. drm_public drmVersionPtr drmGetVersion(int fd)
  1188. {
  1189. drmVersionPtr retval;
  1190. drm_version_t *version = drmMalloc(sizeof(*version));
  1191. if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
  1192. drmFreeKernelVersion(version);
  1193. return NULL;
  1194. }
  1195. if (version->name_len)
  1196. version->name = drmMalloc(version->name_len + 1);
  1197. if (version->date_len)
  1198. version->date = drmMalloc(version->date_len + 1);
  1199. if (version->desc_len)
  1200. version->desc = drmMalloc(version->desc_len + 1);
  1201. if (drmIoctl(fd, DRM_IOCTL_VERSION, version)) {
  1202. drmMsg("DRM_IOCTL_VERSION: %s\n", strerror(errno));
  1203. drmFreeKernelVersion(version);
  1204. return NULL;
  1205. }
  1206. /* The results might not be null-terminated strings, so terminate them. */
  1207. if (version->name_len) version->name[version->name_len] = '\0';
  1208. if (version->date_len) version->date[version->date_len] = '\0';
  1209. if (version->desc_len) version->desc[version->desc_len] = '\0';
  1210. retval = drmMalloc(sizeof(*retval));
  1211. drmCopyVersion(retval, version);
  1212. drmFreeKernelVersion(version);
  1213. return retval;
  1214. }
  1215. /**
  1216. * Get version information for the DRM user space library.
  1217. *
  1218. * This version number is driver independent.
  1219. *
  1220. * \param fd file descriptor.
  1221. *
  1222. * \return version information.
  1223. *
  1224. * \internal
  1225. * This function allocates and fills a drm_version structure with a hard coded
  1226. * version number.
  1227. */
  1228. drm_public drmVersionPtr drmGetLibVersion(int fd)
  1229. {
  1230. drm_version_t *version = drmMalloc(sizeof(*version));
  1231. /* Version history:
  1232. * NOTE THIS MUST NOT GO ABOVE VERSION 1.X due to drivers needing it
  1233. * revision 1.0.x = original DRM interface with no drmGetLibVersion
  1234. * entry point and many drm<Device> extensions
  1235. * revision 1.1.x = added drmCommand entry points for device extensions
  1236. * added drmGetLibVersion to identify libdrm.a version
  1237. * revision 1.2.x = added drmSetInterfaceVersion
  1238. * modified drmOpen to handle both busid and name
  1239. * revision 1.3.x = added server + memory manager
  1240. */
  1241. version->version_major = 1;
  1242. version->version_minor = 3;
  1243. version->version_patchlevel = 0;
  1244. return (drmVersionPtr)version;
  1245. }
  1246. drm_public int drmGetCap(int fd, uint64_t capability, uint64_t *value)
  1247. {
  1248. struct drm_get_cap cap;
  1249. int ret;
  1250. memclear(cap);
  1251. cap.capability = capability;
  1252. ret = drmIoctl(fd, DRM_IOCTL_GET_CAP, &cap);
  1253. if (ret)
  1254. return ret;
  1255. *value = cap.value;
  1256. return 0;
  1257. }
  1258. drm_public int drmSetClientCap(int fd, uint64_t capability, uint64_t value)
  1259. {
  1260. struct drm_set_client_cap cap;
  1261. memclear(cap);
  1262. cap.capability = capability;
  1263. cap.value = value;
  1264. return drmIoctl(fd, DRM_IOCTL_SET_CLIENT_CAP, &cap);
  1265. }
  1266. /**
  1267. * Free the bus ID information.
  1268. *
  1269. * \param busid bus ID information string as given by drmGetBusid().
  1270. *
  1271. * \internal
  1272. * This function is just frees the memory pointed by \p busid.
  1273. */
  1274. drm_public void drmFreeBusid(const char *busid)
  1275. {
  1276. drmFree((void *)busid);
  1277. }
  1278. /**
  1279. * Get the bus ID of the device.
  1280. *
  1281. * \param fd file descriptor.
  1282. *
  1283. * \return bus ID string.
  1284. *
  1285. * \internal
  1286. * This function gets the bus ID via successive DRM_IOCTL_GET_UNIQUE ioctls to
  1287. * get the string length and data, passing the arguments in a drm_unique
  1288. * structure.
  1289. */
  1290. drm_public char *drmGetBusid(int fd)
  1291. {
  1292. drm_unique_t u;
  1293. memclear(u);
  1294. if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u))
  1295. return NULL;
  1296. u.unique = drmMalloc(u.unique_len + 1);
  1297. if (drmIoctl(fd, DRM_IOCTL_GET_UNIQUE, &u)) {
  1298. drmFree(u.unique);
  1299. return NULL;
  1300. }
  1301. u.unique[u.unique_len] = '\0';
  1302. return u.unique;
  1303. }
  1304. /**
  1305. * Set the bus ID of the device.
  1306. *
  1307. * \param fd file descriptor.
  1308. * \param busid bus ID string.
  1309. *
  1310. * \return zero on success, negative on failure.
  1311. *
  1312. * \internal
  1313. * This function is a wrapper around the DRM_IOCTL_SET_UNIQUE ioctl, passing
  1314. * the arguments in a drm_unique structure.
  1315. */
  1316. drm_public int drmSetBusid(int fd, const char *busid)
  1317. {
  1318. drm_unique_t u;
  1319. memclear(u);
  1320. u.unique = (char *)busid;
  1321. u.unique_len = strlen(busid);
  1322. if (drmIoctl(fd, DRM_IOCTL_SET_UNIQUE, &u)) {
  1323. return -errno;
  1324. }
  1325. return 0;
  1326. }
  1327. drm_public int drmGetMagic(int fd, drm_magic_t * magic)
  1328. {
  1329. drm_auth_t auth;
  1330. memclear(auth);
  1331. *magic = 0;
  1332. if (drmIoctl(fd, DRM_IOCTL_GET_MAGIC, &auth))
  1333. return -errno;
  1334. *magic = auth.magic;
  1335. return 0;
  1336. }
  1337. drm_public int drmAuthMagic(int fd, drm_magic_t magic)
  1338. {
  1339. drm_auth_t auth;
  1340. memclear(auth);
  1341. auth.magic = magic;
  1342. if (drmIoctl(fd, DRM_IOCTL_AUTH_MAGIC, &auth))
  1343. return -errno;
  1344. return 0;
  1345. }
  1346. /**
  1347. * Specifies a range of memory that is available for mapping by a
  1348. * non-root process.
  1349. *
  1350. * \param fd file descriptor.
  1351. * \param offset usually the physical address. The actual meaning depends of
  1352. * the \p type parameter. See below.
  1353. * \param size of the memory in bytes.
  1354. * \param type type of the memory to be mapped.
  1355. * \param flags combination of several flags to modify the function actions.
  1356. * \param handle will be set to a value that may be used as the offset
  1357. * parameter for mmap().
  1358. *
  1359. * \return zero on success or a negative value on error.
  1360. *
  1361. * \par Mapping the frame buffer
  1362. * For the frame buffer
  1363. * - \p offset will be the physical address of the start of the frame buffer,
  1364. * - \p size will be the size of the frame buffer in bytes, and
  1365. * - \p type will be DRM_FRAME_BUFFER.
  1366. *
  1367. * \par
  1368. * The area mapped will be uncached. If MTRR support is available in the
  1369. * kernel, the frame buffer area will be set to write combining.
  1370. *
  1371. * \par Mapping the MMIO register area
  1372. * For the MMIO register area,
  1373. * - \p offset will be the physical address of the start of the register area,
  1374. * - \p size will be the size of the register area bytes, and
  1375. * - \p type will be DRM_REGISTERS.
  1376. * \par
  1377. * The area mapped will be uncached.
  1378. *
  1379. * \par Mapping the SAREA
  1380. * For the SAREA,
  1381. * - \p offset will be ignored and should be set to zero,
  1382. * - \p size will be the desired size of the SAREA in bytes,
  1383. * - \p type will be DRM_SHM.
  1384. *
  1385. * \par
  1386. * A shared memory area of the requested size will be created and locked in
  1387. * kernel memory. This area may be mapped into client-space by using the handle
  1388. * returned.
  1389. *
  1390. * \note May only be called by root.
  1391. *
  1392. * \internal
  1393. * This function is a wrapper around the DRM_IOCTL_ADD_MAP ioctl, passing
  1394. * the arguments in a drm_map structure.
  1395. */
  1396. drm_public int drmAddMap(int fd, drm_handle_t offset, drmSize size, drmMapType type,
  1397. drmMapFlags flags, drm_handle_t *handle)
  1398. {
  1399. drm_map_t map;
  1400. memclear(map);
  1401. map.offset = offset;
  1402. map.size = size;
  1403. map.type = (enum drm_map_type)type;
  1404. map.flags = (enum drm_map_flags)flags;
  1405. if (drmIoctl(fd, DRM_IOCTL_ADD_MAP, &map))
  1406. return -errno;
  1407. if (handle)
  1408. *handle = (drm_handle_t)(uintptr_t)map.handle;
  1409. return 0;
  1410. }
  1411. drm_public int drmRmMap(int fd, drm_handle_t handle)
  1412. {
  1413. drm_map_t map;
  1414. memclear(map);
  1415. map.handle = (void *)(uintptr_t)handle;
  1416. if(drmIoctl(fd, DRM_IOCTL_RM_MAP, &map))
  1417. return -errno;
  1418. return 0;
  1419. }
  1420. /**
  1421. * Make buffers available for DMA transfers.
  1422. *
  1423. * \param fd file descriptor.
  1424. * \param count number of buffers.
  1425. * \param size size of each buffer.
  1426. * \param flags buffer allocation flags.
  1427. * \param agp_offset offset in the AGP aperture
  1428. *
  1429. * \return number of buffers allocated, negative on error.
  1430. *
  1431. * \internal
  1432. * This function is a wrapper around DRM_IOCTL_ADD_BUFS ioctl.
  1433. *
  1434. * \sa drm_buf_desc.
  1435. */
  1436. drm_public int drmAddBufs(int fd, int count, int size, drmBufDescFlags flags,
  1437. int agp_offset)
  1438. {
  1439. drm_buf_desc_t request;
  1440. memclear(request);
  1441. request.count = count;
  1442. request.size = size;
  1443. request.flags = (int)flags;
  1444. request.agp_start = agp_offset;
  1445. if (drmIoctl(fd, DRM_IOCTL_ADD_BUFS, &request))
  1446. return -errno;
  1447. return request.count;
  1448. }
  1449. drm_public int drmMarkBufs(int fd, double low, double high)
  1450. {
  1451. drm_buf_info_t info;
  1452. int i;
  1453. memclear(info);
  1454. if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
  1455. return -EINVAL;
  1456. if (!info.count)
  1457. return -EINVAL;
  1458. if (!(info.list = calloc(info.count, sizeof(*info.list))))
  1459. return -ENOMEM;
  1460. if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
  1461. int retval = -errno;
  1462. drmFree(info.list);
  1463. return retval;
  1464. }
  1465. for (i = 0; i < info.count; i++) {
  1466. info.list[i].low_mark = low * info.list[i].count;
  1467. info.list[i].high_mark = high * info.list[i].count;
  1468. if (drmIoctl(fd, DRM_IOCTL_MARK_BUFS, &info.list[i])) {
  1469. int retval = -errno;
  1470. drmFree(info.list);
  1471. return retval;
  1472. }
  1473. }
  1474. drmFree(info.list);
  1475. return 0;
  1476. }
  1477. /**
  1478. * Free buffers.
  1479. *
  1480. * \param fd file descriptor.
  1481. * \param count number of buffers to free.
  1482. * \param list list of buffers to be freed.
  1483. *
  1484. * \return zero on success, or a negative value on failure.
  1485. *
  1486. * \note This function is primarily used for debugging.
  1487. *
  1488. * \internal
  1489. * This function is a wrapper around the DRM_IOCTL_FREE_BUFS ioctl, passing
  1490. * the arguments in a drm_buf_free structure.
  1491. */
  1492. drm_public int drmFreeBufs(int fd, int count, int *list)
  1493. {
  1494. drm_buf_free_t request;
  1495. memclear(request);
  1496. request.count = count;
  1497. request.list = list;
  1498. if (drmIoctl(fd, DRM_IOCTL_FREE_BUFS, &request))
  1499. return -errno;
  1500. return 0;
  1501. }
  1502. /**
  1503. * Close the device.
  1504. *
  1505. * \param fd file descriptor.
  1506. *
  1507. * \internal
  1508. * This function closes the file descriptor.
  1509. */
  1510. drm_public int drmClose(int fd)
  1511. {
  1512. unsigned long key = drmGetKeyFromFd(fd);
  1513. drmHashEntry *entry = drmGetEntry(fd);
  1514. drmHashDestroy(entry->tagTable);
  1515. entry->fd = 0;
  1516. entry->f = NULL;
  1517. entry->tagTable = NULL;
  1518. drmHashDelete(drmHashTable, key);
  1519. drmFree(entry);
  1520. return close(fd);
  1521. }
  1522. /**
  1523. * Map a region of memory.
  1524. *
  1525. * \param fd file descriptor.
  1526. * \param handle handle returned by drmAddMap().
  1527. * \param size size in bytes. Must match the size used by drmAddMap().
  1528. * \param address will contain the user-space virtual address where the mapping
  1529. * begins.
  1530. *
  1531. * \return zero on success, or a negative value on failure.
  1532. *
  1533. * \internal
  1534. * This function is a wrapper for mmap().
  1535. */
  1536. drm_public int drmMap(int fd, drm_handle_t handle, drmSize size,
  1537. drmAddressPtr address)
  1538. {
  1539. static unsigned long pagesize_mask = 0;
  1540. if (fd < 0)
  1541. return -EINVAL;
  1542. if (!pagesize_mask)
  1543. pagesize_mask = getpagesize() - 1;
  1544. size = (size + pagesize_mask) & ~pagesize_mask;
  1545. *address = drm_mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, handle);
  1546. if (*address == MAP_FAILED)
  1547. return -errno;
  1548. return 0;
  1549. }
  1550. /**
  1551. * Unmap mappings obtained with drmMap().
  1552. *
  1553. * \param address address as given by drmMap().
  1554. * \param size size in bytes. Must match the size used by drmMap().
  1555. *
  1556. * \return zero on success, or a negative value on failure.
  1557. *
  1558. * \internal
  1559. * This function is a wrapper for munmap().
  1560. */
  1561. drm_public int drmUnmap(drmAddress address, drmSize size)
  1562. {
  1563. return drm_munmap(address, size);
  1564. }
  1565. drm_public drmBufInfoPtr drmGetBufInfo(int fd)
  1566. {
  1567. drm_buf_info_t info;
  1568. drmBufInfoPtr retval;
  1569. int i;
  1570. memclear(info);
  1571. if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info))
  1572. return NULL;
  1573. if (info.count) {
  1574. if (!(info.list = calloc(info.count, sizeof(*info.list))))
  1575. return NULL;
  1576. if (drmIoctl(fd, DRM_IOCTL_INFO_BUFS, &info)) {
  1577. drmFree(info.list);
  1578. return NULL;
  1579. }
  1580. retval = drmMalloc(sizeof(*retval));
  1581. retval->count = info.count;
  1582. if (!(retval->list = calloc(info.count, sizeof(*retval->list)))) {
  1583. drmFree(retval);
  1584. drmFree(info.list);
  1585. return NULL;
  1586. }
  1587. for (i = 0; i < info.count; i++) {
  1588. retval->list[i].count = info.list[i].count;
  1589. retval->list[i].size = info.list[i].size;
  1590. retval->list[i].low_mark = info.list[i].low_mark;
  1591. retval->list[i].high_mark = info.list[i].high_mark;
  1592. }
  1593. drmFree(info.list);
  1594. return retval;
  1595. }
  1596. return NULL;
  1597. }
  1598. /**
  1599. * Map all DMA buffers into client-virtual space.
  1600. *
  1601. * \param fd file descriptor.
  1602. *
  1603. * \return a pointer to a ::drmBufMap structure.
  1604. *
  1605. * \note The client may not use these buffers until obtaining buffer indices
  1606. * with drmDMA().
  1607. *
  1608. * \internal
  1609. * This function calls the DRM_IOCTL_MAP_BUFS ioctl and copies the returned
  1610. * information about the buffers in a drm_buf_map structure into the
  1611. * client-visible data structures.
  1612. */
  1613. drm_public drmBufMapPtr drmMapBufs(int fd)
  1614. {
  1615. drm_buf_map_t bufs;
  1616. drmBufMapPtr retval;
  1617. int i;
  1618. memclear(bufs);
  1619. if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs))
  1620. return NULL;
  1621. if (!bufs.count)
  1622. return NULL;
  1623. if (!(bufs.list = calloc(bufs.count, sizeof(*bufs.list))))
  1624. return NULL;
  1625. if (drmIoctl(fd, DRM_IOCTL_MAP_BUFS, &bufs)) {
  1626. drmFree(bufs.list);
  1627. return NULL;
  1628. }
  1629. retval = drmMalloc(sizeof(*retval));
  1630. retval->count = bufs.count;
  1631. retval->list = calloc(bufs.count, sizeof(*retval->list));
  1632. for (i = 0; i < bufs.count; i++) {
  1633. retval->list[i].idx = bufs.list[i].idx;
  1634. retval->list[i].total = bufs.list[i].total;
  1635. retval->list[i].used = 0;
  1636. retval->list[i].address = bufs.list[i].address;
  1637. }
  1638. drmFree(bufs.list);
  1639. return retval;
  1640. }
  1641. /**
  1642. * Unmap buffers allocated with drmMapBufs().
  1643. *
  1644. * \return zero on success, or negative value on failure.
  1645. *
  1646. * \internal
  1647. * Calls munmap() for every buffer stored in \p bufs and frees the
  1648. * memory allocated by drmMapBufs().
  1649. */
  1650. drm_public int drmUnmapBufs(drmBufMapPtr bufs)
  1651. {
  1652. int i;
  1653. for (i = 0; i < bufs->count; i++) {
  1654. drm_munmap(bufs->list[i].address, bufs->list[i].total);
  1655. }
  1656. drmFree(bufs->list);
  1657. drmFree(bufs);
  1658. return 0;
  1659. }
  1660. #define DRM_DMA_RETRY 16
  1661. /**
  1662. * Reserve DMA buffers.
  1663. *
  1664. * \param fd file descriptor.
  1665. * \param request
  1666. *
  1667. * \return zero on success, or a negative value on failure.
  1668. *
  1669. * \internal
  1670. * Assemble the arguments into a drm_dma structure and keeps issuing the
  1671. * DRM_IOCTL_DMA ioctl until success or until maximum number of retries.
  1672. */
  1673. drm_public int drmDMA(int fd, drmDMAReqPtr request)
  1674. {
  1675. drm_dma_t dma;
  1676. int ret, i = 0;
  1677. dma.context = request->context;
  1678. dma.send_count = request->send_count;
  1679. dma.send_indices = request->send_list;
  1680. dma.send_sizes = request->send_sizes;
  1681. dma.flags = (enum drm_dma_flags)request->flags;
  1682. dma.request_count = request->request_count;
  1683. dma.request_size = request->request_size;
  1684. dma.request_indices = request->request_list;
  1685. dma.request_sizes = request->request_sizes;
  1686. dma.granted_count = 0;
  1687. do {
  1688. ret = ioctl( fd, DRM_IOCTL_DMA, &dma );
  1689. } while ( ret && errno == EAGAIN && i++ < DRM_DMA_RETRY );
  1690. if ( ret == 0 ) {
  1691. request->granted_count = dma.granted_count;
  1692. return 0;
  1693. } else {
  1694. return -errno;
  1695. }
  1696. }
  1697. /**
  1698. * Obtain heavyweight hardware lock.
  1699. *
  1700. * \param fd file descriptor.
  1701. * \param context context.
  1702. * \param flags flags that determine the state of the hardware when the function
  1703. * returns.
  1704. *
  1705. * \return always zero.
  1706. *
  1707. * \internal
  1708. * This function translates the arguments into a drm_lock structure and issue
  1709. * the DRM_IOCTL_LOCK ioctl until the lock is successfully acquired.
  1710. */
  1711. drm_public int drmGetLock(int fd, drm_context_t context, drmLockFlags flags)
  1712. {
  1713. drm_lock_t lock;
  1714. memclear(lock);
  1715. lock.context = context;
  1716. lock.flags = 0;
  1717. if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
  1718. if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
  1719. if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
  1720. if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
  1721. if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
  1722. if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
  1723. while (drmIoctl(fd, DRM_IOCTL_LOCK, &lock))
  1724. ;
  1725. return 0;
  1726. }
  1727. /**
  1728. * Release the hardware lock.
  1729. *
  1730. * \param fd file descriptor.
  1731. * \param context context.
  1732. *
  1733. * \return zero on success, or a negative value on failure.
  1734. *
  1735. * \internal
  1736. * This function is a wrapper around the DRM_IOCTL_UNLOCK ioctl, passing the
  1737. * argument in a drm_lock structure.
  1738. */
  1739. drm_public int drmUnlock(int fd, drm_context_t context)
  1740. {
  1741. drm_lock_t lock;
  1742. memclear(lock);
  1743. lock.context = context;
  1744. return drmIoctl(fd, DRM_IOCTL_UNLOCK, &lock);
  1745. }
  1746. drm_public drm_context_t *drmGetReservedContextList(int fd, int *count)
  1747. {
  1748. drm_ctx_res_t res;
  1749. drm_ctx_t *list;
  1750. drm_context_t * retval;
  1751. int i;
  1752. memclear(res);
  1753. if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
  1754. return NULL;
  1755. if (!res.count)
  1756. return NULL;
  1757. if (!(list = calloc(res.count, sizeof(*list))))
  1758. return NULL;
  1759. if (!(retval = calloc(res.count, sizeof(*retval))))
  1760. goto err_free_list;
  1761. res.contexts = list;
  1762. if (drmIoctl(fd, DRM_IOCTL_RES_CTX, &res))
  1763. goto err_free_context;
  1764. for (i = 0; i < res.count; i++)
  1765. retval[i] = list[i].handle;
  1766. drmFree(list);
  1767. *count = res.count;
  1768. return retval;
  1769. err_free_list:
  1770. drmFree(list);
  1771. err_free_context:
  1772. drmFree(retval);
  1773. return NULL;
  1774. }
  1775. drm_public void drmFreeReservedContextList(drm_context_t *pt)
  1776. {
  1777. drmFree(pt);
  1778. }
  1779. /**
  1780. * Create context.
  1781. *
  1782. * Used by the X server during GLXContext initialization. This causes
  1783. * per-context kernel-level resources to be allocated.
  1784. *
  1785. * \param fd file descriptor.
  1786. * \param handle is set on success. To be used by the client when requesting DMA
  1787. * dispatch with drmDMA().
  1788. *
  1789. * \return zero on success, or a negative value on failure.
  1790. *
  1791. * \note May only be called by root.
  1792. *
  1793. * \internal
  1794. * This function is a wrapper around the DRM_IOCTL_ADD_CTX ioctl, passing the
  1795. * argument in a drm_ctx structure.
  1796. */
  1797. drm_public int drmCreateContext(int fd, drm_context_t *handle)
  1798. {
  1799. drm_ctx_t ctx;
  1800. memclear(ctx);
  1801. if (drmIoctl(fd, DRM_IOCTL_ADD_CTX, &ctx))
  1802. return -errno;
  1803. *handle = ctx.handle;
  1804. return 0;
  1805. }
  1806. drm_public int drmSwitchToContext(int fd, drm_context_t context)
  1807. {
  1808. drm_ctx_t ctx;
  1809. memclear(ctx);
  1810. ctx.handle = context;
  1811. if (drmIoctl(fd, DRM_IOCTL_SWITCH_CTX, &ctx))
  1812. return -errno;
  1813. return 0;
  1814. }
  1815. drm_public int drmSetContextFlags(int fd, drm_context_t context,
  1816. drm_context_tFlags flags)
  1817. {
  1818. drm_ctx_t ctx;
  1819. /*
  1820. * Context preserving means that no context switches are done between DMA
  1821. * buffers from one context and the next. This is suitable for use in the
  1822. * X server (which promises to maintain hardware context), or in the
  1823. * client-side library when buffers are swapped on behalf of two threads.
  1824. */
  1825. memclear(ctx);
  1826. ctx.handle = context;
  1827. if (flags & DRM_CONTEXT_PRESERVED)
  1828. ctx.flags |= _DRM_CONTEXT_PRESERVED;
  1829. if (flags & DRM_CONTEXT_2DONLY)
  1830. ctx.flags |= _DRM_CONTEXT_2DONLY;
  1831. if (drmIoctl(fd, DRM_IOCTL_MOD_CTX, &ctx))
  1832. return -errno;
  1833. return 0;
  1834. }
  1835. drm_public int drmGetContextFlags(int fd, drm_context_t context,
  1836. drm_context_tFlagsPtr flags)
  1837. {
  1838. drm_ctx_t ctx;
  1839. memclear(ctx);
  1840. ctx.handle = context;
  1841. if (drmIoctl(fd, DRM_IOCTL_GET_CTX, &ctx))
  1842. return -errno;
  1843. *flags = 0;
  1844. if (ctx.flags & _DRM_CONTEXT_PRESERVED)
  1845. *flags |= DRM_CONTEXT_PRESERVED;
  1846. if (ctx.flags & _DRM_CONTEXT_2DONLY)
  1847. *flags |= DRM_CONTEXT_2DONLY;
  1848. return 0;
  1849. }
  1850. /**
  1851. * Destroy context.
  1852. *
  1853. * Free any kernel-level resources allocated with drmCreateContext() associated
  1854. * with the context.
  1855. *
  1856. * \param fd file descriptor.
  1857. * \param handle handle given by drmCreateContext().
  1858. *
  1859. * \return zero on success, or a negative value on failure.
  1860. *
  1861. * \note May only be called by root.
  1862. *
  1863. * \internal
  1864. * This function is a wrapper around the DRM_IOCTL_RM_CTX ioctl, passing the
  1865. * argument in a drm_ctx structure.
  1866. */
  1867. drm_public int drmDestroyContext(int fd, drm_context_t handle)
  1868. {
  1869. drm_ctx_t ctx;
  1870. memclear(ctx);
  1871. ctx.handle = handle;
  1872. if (drmIoctl(fd, DRM_IOCTL_RM_CTX, &ctx))
  1873. return -errno;
  1874. return 0;
  1875. }
  1876. drm_public int drmCreateDrawable(int fd, drm_drawable_t *handle)
  1877. {
  1878. drm_draw_t draw;
  1879. memclear(draw);
  1880. if (drmIoctl(fd, DRM_IOCTL_ADD_DRAW, &draw))
  1881. return -errno;
  1882. *handle = draw.handle;
  1883. return 0;
  1884. }
  1885. drm_public int drmDestroyDrawable(int fd, drm_drawable_t handle)
  1886. {
  1887. drm_draw_t draw;
  1888. memclear(draw);
  1889. draw.handle = handle;
  1890. if (drmIoctl(fd, DRM_IOCTL_RM_DRAW, &draw))
  1891. return -errno;
  1892. return 0;
  1893. }
  1894. drm_public int drmUpdateDrawableInfo(int fd, drm_drawable_t handle,
  1895. drm_drawable_info_type_t type,
  1896. unsigned int num, void *data)
  1897. {
  1898. drm_update_draw_t update;
  1899. memclear(update);
  1900. update.handle = handle;
  1901. update.type = type;
  1902. update.num = num;
  1903. update.data = (unsigned long long)(unsigned long)data;
  1904. if (drmIoctl(fd, DRM_IOCTL_UPDATE_DRAW, &update))
  1905. return -errno;
  1906. return 0;
  1907. }
  1908. drm_public int drmCrtcGetSequence(int fd, uint32_t crtcId, uint64_t *sequence,
  1909. uint64_t *ns)
  1910. {
  1911. struct drm_crtc_get_sequence get_seq;
  1912. int ret;
  1913. memclear(get_seq);
  1914. get_seq.crtc_id = crtcId;
  1915. ret = drmIoctl(fd, DRM_IOCTL_CRTC_GET_SEQUENCE, &get_seq);
  1916. if (ret)
  1917. return ret;
  1918. if (sequence)
  1919. *sequence = get_seq.sequence;
  1920. if (ns)
  1921. *ns = get_seq.sequence_ns;
  1922. return 0;
  1923. }
  1924. drm_public int drmCrtcQueueSequence(int fd, uint32_t crtcId, uint32_t flags,
  1925. uint64_t sequence,
  1926. uint64_t *sequence_queued,
  1927. uint64_t user_data)
  1928. {
  1929. struct drm_crtc_queue_sequence queue_seq;
  1930. int ret;
  1931. memclear(queue_seq);
  1932. queue_seq.crtc_id = crtcId;
  1933. queue_seq.flags = flags;
  1934. queue_seq.sequence = sequence;
  1935. queue_seq.user_data = user_data;
  1936. ret = drmIoctl(fd, DRM_IOCTL_CRTC_QUEUE_SEQUENCE, &queue_seq);
  1937. if (ret == 0 && sequence_queued)
  1938. *sequence_queued = queue_seq.sequence;
  1939. return ret;
  1940. }
  1941. /**
  1942. * Acquire the AGP device.
  1943. *
  1944. * Must be called before any of the other AGP related calls.
  1945. *
  1946. * \param fd file descriptor.
  1947. *
  1948. * \return zero on success, or a negative value on failure.
  1949. *
  1950. * \internal
  1951. * This function is a wrapper around the DRM_IOCTL_AGP_ACQUIRE ioctl.
  1952. */
  1953. drm_public int drmAgpAcquire(int fd)
  1954. {
  1955. if (drmIoctl(fd, DRM_IOCTL_AGP_ACQUIRE, NULL))
  1956. return -errno;
  1957. return 0;
  1958. }
  1959. /**
  1960. * Release the AGP device.
  1961. *
  1962. * \param fd file descriptor.
  1963. *
  1964. * \return zero on success, or a negative value on failure.
  1965. *
  1966. * \internal
  1967. * This function is a wrapper around the DRM_IOCTL_AGP_RELEASE ioctl.
  1968. */
  1969. drm_public int drmAgpRelease(int fd)
  1970. {
  1971. if (drmIoctl(fd, DRM_IOCTL_AGP_RELEASE, NULL))
  1972. return -errno;
  1973. return 0;
  1974. }
  1975. /**
  1976. * Set the AGP mode.
  1977. *
  1978. * \param fd file descriptor.
  1979. * \param mode AGP mode.
  1980. *
  1981. * \return zero on success, or a negative value on failure.
  1982. *
  1983. * \internal
  1984. * This function is a wrapper around the DRM_IOCTL_AGP_ENABLE ioctl, passing the
  1985. * argument in a drm_agp_mode structure.
  1986. */
  1987. drm_public int drmAgpEnable(int fd, unsigned long mode)
  1988. {
  1989. drm_agp_mode_t m;
  1990. memclear(m);
  1991. m.mode = mode;
  1992. if (drmIoctl(fd, DRM_IOCTL_AGP_ENABLE, &m))
  1993. return -errno;
  1994. return 0;
  1995. }
  1996. /**
  1997. * Allocate a chunk of AGP memory.
  1998. *
  1999. * \param fd file descriptor.
  2000. * \param size requested memory size in bytes. Will be rounded to page boundary.
  2001. * \param type type of memory to allocate.
  2002. * \param address if not zero, will be set to the physical address of the
  2003. * allocated memory.
  2004. * \param handle on success will be set to a handle of the allocated memory.
  2005. *
  2006. * \return zero on success, or a negative value on failure.
  2007. *
  2008. * \internal
  2009. * This function is a wrapper around the DRM_IOCTL_AGP_ALLOC ioctl, passing the
  2010. * arguments in a drm_agp_buffer structure.
  2011. */
  2012. drm_public int drmAgpAlloc(int fd, unsigned long size, unsigned long type,
  2013. unsigned long *address, drm_handle_t *handle)
  2014. {
  2015. drm_agp_buffer_t b;
  2016. memclear(b);
  2017. *handle = DRM_AGP_NO_HANDLE;
  2018. b.size = size;
  2019. b.type = type;
  2020. if (drmIoctl(fd, DRM_IOCTL_AGP_ALLOC, &b))
  2021. return -errno;
  2022. if (address != 0UL)
  2023. *address = b.physical;
  2024. *handle = b.handle;
  2025. return 0;
  2026. }
  2027. /**
  2028. * Free a chunk of AGP memory.
  2029. *
  2030. * \param fd file descriptor.
  2031. * \param handle handle to the allocated memory, as given by drmAgpAllocate().
  2032. *
  2033. * \return zero on success, or a negative value on failure.
  2034. *
  2035. * \internal
  2036. * This function is a wrapper around the DRM_IOCTL_AGP_FREE ioctl, passing the
  2037. * argument in a drm_agp_buffer structure.
  2038. */
  2039. drm_public int drmAgpFree(int fd, drm_handle_t handle)
  2040. {
  2041. drm_agp_buffer_t b;
  2042. memclear(b);
  2043. b.handle = handle;
  2044. if (drmIoctl(fd, DRM_IOCTL_AGP_FREE, &b))
  2045. return -errno;
  2046. return 0;
  2047. }
  2048. /**
  2049. * Bind a chunk of AGP memory.
  2050. *
  2051. * \param fd file descriptor.
  2052. * \param handle handle to the allocated memory, as given by drmAgpAllocate().
  2053. * \param offset offset in bytes. It will round to page boundary.
  2054. *
  2055. * \return zero on success, or a negative value on failure.
  2056. *
  2057. * \internal
  2058. * This function is a wrapper around the DRM_IOCTL_AGP_BIND ioctl, passing the
  2059. * argument in a drm_agp_binding structure.
  2060. */
  2061. drm_public int drmAgpBind(int fd, drm_handle_t handle, unsigned long offset)
  2062. {
  2063. drm_agp_binding_t b;
  2064. memclear(b);
  2065. b.handle = handle;
  2066. b.offset = offset;
  2067. if (drmIoctl(fd, DRM_IOCTL_AGP_BIND, &b))
  2068. return -errno;
  2069. return 0;
  2070. }
  2071. /**
  2072. * Unbind a chunk of AGP memory.
  2073. *
  2074. * \param fd file descriptor.
  2075. * \param handle handle to the allocated memory, as given by drmAgpAllocate().
  2076. *
  2077. * \return zero on success, or a negative value on failure.
  2078. *
  2079. * \internal
  2080. * This function is a wrapper around the DRM_IOCTL_AGP_UNBIND ioctl, passing
  2081. * the argument in a drm_agp_binding structure.
  2082. */
  2083. drm_public int drmAgpUnbind(int fd, drm_handle_t handle)
  2084. {
  2085. drm_agp_binding_t b;
  2086. memclear(b);
  2087. b.handle = handle;
  2088. if (drmIoctl(fd, DRM_IOCTL_AGP_UNBIND, &b))
  2089. return -errno;
  2090. return 0;
  2091. }
  2092. /**
  2093. * Get AGP driver major version number.
  2094. *
  2095. * \param fd file descriptor.
  2096. *
  2097. * \return major version number on success, or a negative value on failure..
  2098. *
  2099. * \internal
  2100. * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  2101. * necessary information in a drm_agp_info structure.
  2102. */
  2103. drm_public int drmAgpVersionMajor(int fd)
  2104. {
  2105. drm_agp_info_t i;
  2106. memclear(i);
  2107. if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
  2108. return -errno;
  2109. return i.agp_version_major;
  2110. }
  2111. /**
  2112. * Get AGP driver minor version number.
  2113. *
  2114. * \param fd file descriptor.
  2115. *
  2116. * \return minor version number on success, or a negative value on failure.
  2117. *
  2118. * \internal
  2119. * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  2120. * necessary information in a drm_agp_info structure.
  2121. */
  2122. drm_public int drmAgpVersionMinor(int fd)
  2123. {
  2124. drm_agp_info_t i;
  2125. memclear(i);
  2126. if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
  2127. return -errno;
  2128. return i.agp_version_minor;
  2129. }
  2130. /**
  2131. * Get AGP mode.
  2132. *
  2133. * \param fd file descriptor.
  2134. *
  2135. * \return mode on success, or zero on failure.
  2136. *
  2137. * \internal
  2138. * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  2139. * necessary information in a drm_agp_info structure.
  2140. */
  2141. drm_public unsigned long drmAgpGetMode(int fd)
  2142. {
  2143. drm_agp_info_t i;
  2144. memclear(i);
  2145. if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
  2146. return 0;
  2147. return i.mode;
  2148. }
  2149. /**
  2150. * Get AGP aperture base.
  2151. *
  2152. * \param fd file descriptor.
  2153. *
  2154. * \return aperture base on success, zero on failure.
  2155. *
  2156. * \internal
  2157. * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  2158. * necessary information in a drm_agp_info structure.
  2159. */
  2160. drm_public unsigned long drmAgpBase(int fd)
  2161. {
  2162. drm_agp_info_t i;
  2163. memclear(i);
  2164. if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
  2165. return 0;
  2166. return i.aperture_base;
  2167. }
  2168. /**
  2169. * Get AGP aperture size.
  2170. *
  2171. * \param fd file descriptor.
  2172. *
  2173. * \return aperture size on success, zero on failure.
  2174. *
  2175. * \internal
  2176. * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  2177. * necessary information in a drm_agp_info structure.
  2178. */
  2179. drm_public unsigned long drmAgpSize(int fd)
  2180. {
  2181. drm_agp_info_t i;
  2182. memclear(i);
  2183. if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
  2184. return 0;
  2185. return i.aperture_size;
  2186. }
  2187. /**
  2188. * Get used AGP memory.
  2189. *
  2190. * \param fd file descriptor.
  2191. *
  2192. * \return memory used on success, or zero on failure.
  2193. *
  2194. * \internal
  2195. * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  2196. * necessary information in a drm_agp_info structure.
  2197. */
  2198. drm_public unsigned long drmAgpMemoryUsed(int fd)
  2199. {
  2200. drm_agp_info_t i;
  2201. memclear(i);
  2202. if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
  2203. return 0;
  2204. return i.memory_used;
  2205. }
  2206. /**
  2207. * Get available AGP memory.
  2208. *
  2209. * \param fd file descriptor.
  2210. *
  2211. * \return memory available on success, or zero on failure.
  2212. *
  2213. * \internal
  2214. * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  2215. * necessary information in a drm_agp_info structure.
  2216. */
  2217. drm_public unsigned long drmAgpMemoryAvail(int fd)
  2218. {
  2219. drm_agp_info_t i;
  2220. memclear(i);
  2221. if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
  2222. return 0;
  2223. return i.memory_allowed;
  2224. }
  2225. /**
  2226. * Get hardware vendor ID.
  2227. *
  2228. * \param fd file descriptor.
  2229. *
  2230. * \return vendor ID on success, or zero on failure.
  2231. *
  2232. * \internal
  2233. * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  2234. * necessary information in a drm_agp_info structure.
  2235. */
  2236. drm_public unsigned int drmAgpVendorId(int fd)
  2237. {
  2238. drm_agp_info_t i;
  2239. memclear(i);
  2240. if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
  2241. return 0;
  2242. return i.id_vendor;
  2243. }
  2244. /**
  2245. * Get hardware device ID.
  2246. *
  2247. * \param fd file descriptor.
  2248. *
  2249. * \return zero on success, or zero on failure.
  2250. *
  2251. * \internal
  2252. * This function is a wrapper around the DRM_IOCTL_AGP_INFO ioctl, getting the
  2253. * necessary information in a drm_agp_info structure.
  2254. */
  2255. drm_public unsigned int drmAgpDeviceId(int fd)
  2256. {
  2257. drm_agp_info_t i;
  2258. memclear(i);
  2259. if (drmIoctl(fd, DRM_IOCTL_AGP_INFO, &i))
  2260. return 0;
  2261. return i.id_device;
  2262. }
  2263. drm_public int drmScatterGatherAlloc(int fd, unsigned long size,
  2264. drm_handle_t *handle)
  2265. {
  2266. drm_scatter_gather_t sg;
  2267. memclear(sg);
  2268. *handle = 0;
  2269. sg.size = size;
  2270. if (drmIoctl(fd, DRM_IOCTL_SG_ALLOC, &sg))
  2271. return -errno;
  2272. *handle = sg.handle;
  2273. return 0;
  2274. }
  2275. drm_public int drmScatterGatherFree(int fd, drm_handle_t handle)
  2276. {
  2277. drm_scatter_gather_t sg;
  2278. memclear(sg);
  2279. sg.handle = handle;
  2280. if (drmIoctl(fd, DRM_IOCTL_SG_FREE, &sg))
  2281. return -errno;
  2282. return 0;
  2283. }
  2284. /**
  2285. * Wait for VBLANK.
  2286. *
  2287. * \param fd file descriptor.
  2288. * \param vbl pointer to a drmVBlank structure.
  2289. *
  2290. * \return zero on success, or a negative value on failure.
  2291. *
  2292. * \internal
  2293. * This function is a wrapper around the DRM_IOCTL_WAIT_VBLANK ioctl.
  2294. */
  2295. drm_public int drmWaitVBlank(int fd, drmVBlankPtr vbl)
  2296. {
  2297. struct timespec timeout, cur;
  2298. int ret;
  2299. ret = clock_gettime(CLOCK_MONOTONIC, &timeout);
  2300. if (ret < 0) {
  2301. fprintf(stderr, "clock_gettime failed: %s\n", strerror(errno));
  2302. goto out;
  2303. }
  2304. timeout.tv_sec++;
  2305. do {
  2306. ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
  2307. vbl->request.type &= ~DRM_VBLANK_RELATIVE;
  2308. if (ret && errno == EINTR) {
  2309. clock_gettime(CLOCK_MONOTONIC, &cur);
  2310. /* Timeout after 1s */
  2311. if (cur.tv_sec > timeout.tv_sec + 1 ||
  2312. (cur.tv_sec == timeout.tv_sec && cur.tv_nsec >=
  2313. timeout.tv_nsec)) {
  2314. errno = EBUSY;
  2315. ret = -1;
  2316. break;
  2317. }
  2318. }
  2319. } while (ret && errno == EINTR);
  2320. out:
  2321. return ret;
  2322. }
  2323. drm_public int drmError(int err, const char *label)
  2324. {
  2325. switch (err) {
  2326. case DRM_ERR_NO_DEVICE:
  2327. fprintf(stderr, "%s: no device\n", label);
  2328. break;
  2329. case DRM_ERR_NO_ACCESS:
  2330. fprintf(stderr, "%s: no access\n", label);
  2331. break;
  2332. case DRM_ERR_NOT_ROOT:
  2333. fprintf(stderr, "%s: not root\n", label);
  2334. break;
  2335. case DRM_ERR_INVALID:
  2336. fprintf(stderr, "%s: invalid args\n", label);
  2337. break;
  2338. default:
  2339. if (err < 0)
  2340. err = -err;
  2341. fprintf( stderr, "%s: error %d (%s)\n", label, err, strerror(err) );
  2342. break;
  2343. }
  2344. return 1;
  2345. }
  2346. /**
  2347. * Install IRQ handler.
  2348. *
  2349. * \param fd file descriptor.
  2350. * \param irq IRQ number.
  2351. *
  2352. * \return zero on success, or a negative value on failure.
  2353. *
  2354. * \internal
  2355. * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
  2356. * argument in a drm_control structure.
  2357. */
  2358. drm_public int drmCtlInstHandler(int fd, int irq)
  2359. {
  2360. drm_control_t ctl;
  2361. memclear(ctl);
  2362. ctl.func = DRM_INST_HANDLER;
  2363. ctl.irq = irq;
  2364. if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
  2365. return -errno;
  2366. return 0;
  2367. }
  2368. /**
  2369. * Uninstall IRQ handler.
  2370. *
  2371. * \param fd file descriptor.
  2372. *
  2373. * \return zero on success, or a negative value on failure.
  2374. *
  2375. * \internal
  2376. * This function is a wrapper around the DRM_IOCTL_CONTROL ioctl, passing the
  2377. * argument in a drm_control structure.
  2378. */
  2379. drm_public int drmCtlUninstHandler(int fd)
  2380. {
  2381. drm_control_t ctl;
  2382. memclear(ctl);
  2383. ctl.func = DRM_UNINST_HANDLER;
  2384. ctl.irq = 0;
  2385. if (drmIoctl(fd, DRM_IOCTL_CONTROL, &ctl))
  2386. return -errno;
  2387. return 0;
  2388. }
  2389. drm_public int drmFinish(int fd, int context, drmLockFlags flags)
  2390. {
  2391. drm_lock_t lock;
  2392. memclear(lock);
  2393. lock.context = context;
  2394. if (flags & DRM_LOCK_READY) lock.flags |= _DRM_LOCK_READY;
  2395. if (flags & DRM_LOCK_QUIESCENT) lock.flags |= _DRM_LOCK_QUIESCENT;
  2396. if (flags & DRM_LOCK_FLUSH) lock.flags |= _DRM_LOCK_FLUSH;
  2397. if (flags & DRM_LOCK_FLUSH_ALL) lock.flags |= _DRM_LOCK_FLUSH_ALL;
  2398. if (flags & DRM_HALT_ALL_QUEUES) lock.flags |= _DRM_HALT_ALL_QUEUES;
  2399. if (flags & DRM_HALT_CUR_QUEUES) lock.flags |= _DRM_HALT_CUR_QUEUES;
  2400. if (drmIoctl(fd, DRM_IOCTL_FINISH, &lock))
  2401. return -errno;
  2402. return 0;
  2403. }
  2404. /**
  2405. * Get IRQ from bus ID.
  2406. *
  2407. * \param fd file descriptor.
  2408. * \param busnum bus number.
  2409. * \param devnum device number.
  2410. * \param funcnum function number.
  2411. *
  2412. * \return IRQ number on success, or a negative value on failure.
  2413. *
  2414. * \internal
  2415. * This function is a wrapper around the DRM_IOCTL_IRQ_BUSID ioctl, passing the
  2416. * arguments in a drm_irq_busid structure.
  2417. */
  2418. drm_public int drmGetInterruptFromBusID(int fd, int busnum, int devnum,
  2419. int funcnum)
  2420. {
  2421. drm_irq_busid_t p;
  2422. memclear(p);
  2423. p.busnum = busnum;
  2424. p.devnum = devnum;
  2425. p.funcnum = funcnum;
  2426. if (drmIoctl(fd, DRM_IOCTL_IRQ_BUSID, &p))
  2427. return -errno;
  2428. return p.irq;
  2429. }
  2430. drm_public int drmAddContextTag(int fd, drm_context_t context, void *tag)
  2431. {
  2432. drmHashEntry *entry = drmGetEntry(fd);
  2433. if (drmHashInsert(entry->tagTable, context, tag)) {
  2434. drmHashDelete(entry->tagTable, context);
  2435. drmHashInsert(entry->tagTable, context, tag);
  2436. }
  2437. return 0;
  2438. }
  2439. drm_public int drmDelContextTag(int fd, drm_context_t context)
  2440. {
  2441. drmHashEntry *entry = drmGetEntry(fd);
  2442. return drmHashDelete(entry->tagTable, context);
  2443. }
  2444. drm_public void *drmGetContextTag(int fd, drm_context_t context)
  2445. {
  2446. drmHashEntry *entry = drmGetEntry(fd);
  2447. void *value;
  2448. if (drmHashLookup(entry->tagTable, context, &value))
  2449. return NULL;
  2450. return value;
  2451. }
  2452. drm_public int drmAddContextPrivateMapping(int fd, drm_context_t ctx_id,
  2453. drm_handle_t handle)
  2454. {
  2455. drm_ctx_priv_map_t map;
  2456. memclear(map);
  2457. map.ctx_id = ctx_id;
  2458. map.handle = (void *)(uintptr_t)handle;
  2459. if (drmIoctl(fd, DRM_IOCTL_SET_SAREA_CTX, &map))
  2460. return -errno;
  2461. return 0;
  2462. }
  2463. drm_public int drmGetContextPrivateMapping(int fd, drm_context_t ctx_id,
  2464. drm_handle_t *handle)
  2465. {
  2466. drm_ctx_priv_map_t map;
  2467. memclear(map);
  2468. map.ctx_id = ctx_id;
  2469. if (drmIoctl(fd, DRM_IOCTL_GET_SAREA_CTX, &map))
  2470. return -errno;
  2471. if (handle)
  2472. *handle = (drm_handle_t)(uintptr_t)map.handle;
  2473. return 0;
  2474. }
  2475. drm_public int drmGetMap(int fd, int idx, drm_handle_t *offset, drmSize *size,
  2476. drmMapType *type, drmMapFlags *flags,
  2477. drm_handle_t *handle, int *mtrr)
  2478. {
  2479. drm_map_t map;
  2480. memclear(map);
  2481. map.offset = idx;
  2482. if (drmIoctl(fd, DRM_IOCTL_GET_MAP, &map))
  2483. return -errno;
  2484. *offset = map.offset;
  2485. *size = map.size;
  2486. *type = (drmMapType)map.type;
  2487. *flags = (drmMapFlags)map.flags;
  2488. *handle = (unsigned long)map.handle;
  2489. *mtrr = map.mtrr;
  2490. return 0;
  2491. }
  2492. drm_public int drmGetClient(int fd, int idx, int *auth, int *pid, int *uid,
  2493. unsigned long *magic, unsigned long *iocs)
  2494. {
  2495. drm_client_t client;
  2496. memclear(client);
  2497. client.idx = idx;
  2498. if (drmIoctl(fd, DRM_IOCTL_GET_CLIENT, &client))
  2499. return -errno;
  2500. *auth = client.auth;
  2501. *pid = client.pid;
  2502. *uid = client.uid;
  2503. *magic = client.magic;
  2504. *iocs = client.iocs;
  2505. return 0;
  2506. }
  2507. drm_public int drmGetStats(int fd, drmStatsT *stats)
  2508. {
  2509. drm_stats_t s;
  2510. unsigned i;
  2511. memclear(s);
  2512. if (drmIoctl(fd, DRM_IOCTL_GET_STATS, &s))
  2513. return -errno;
  2514. stats->count = 0;
  2515. memset(stats, 0, sizeof(*stats));
  2516. if (s.count > sizeof(stats->data)/sizeof(stats->data[0]))
  2517. return -1;
  2518. #define SET_VALUE \
  2519. stats->data[i].long_format = "%-20.20s"; \
  2520. stats->data[i].rate_format = "%8.8s"; \
  2521. stats->data[i].isvalue = 1; \
  2522. stats->data[i].verbose = 0
  2523. #define SET_COUNT \
  2524. stats->data[i].long_format = "%-20.20s"; \
  2525. stats->data[i].rate_format = "%5.5s"; \
  2526. stats->data[i].isvalue = 0; \
  2527. stats->data[i].mult_names = "kgm"; \
  2528. stats->data[i].mult = 1000; \
  2529. stats->data[i].verbose = 0
  2530. #define SET_BYTE \
  2531. stats->data[i].long_format = "%-20.20s"; \
  2532. stats->data[i].rate_format = "%5.5s"; \
  2533. stats->data[i].isvalue = 0; \
  2534. stats->data[i].mult_names = "KGM"; \
  2535. stats->data[i].mult = 1024; \
  2536. stats->data[i].verbose = 0
  2537. stats->count = s.count;
  2538. for (i = 0; i < s.count; i++) {
  2539. stats->data[i].value = s.data[i].value;
  2540. switch (s.data[i].type) {
  2541. case _DRM_STAT_LOCK:
  2542. stats->data[i].long_name = "Lock";
  2543. stats->data[i].rate_name = "Lock";
  2544. SET_VALUE;
  2545. break;
  2546. case _DRM_STAT_OPENS:
  2547. stats->data[i].long_name = "Opens";
  2548. stats->data[i].rate_name = "O";
  2549. SET_COUNT;
  2550. stats->data[i].verbose = 1;
  2551. break;
  2552. case _DRM_STAT_CLOSES:
  2553. stats->data[i].long_name = "Closes";
  2554. stats->data[i].rate_name = "Lock";
  2555. SET_COUNT;
  2556. stats->data[i].verbose = 1;
  2557. break;
  2558. case _DRM_STAT_IOCTLS:
  2559. stats->data[i].long_name = "Ioctls";
  2560. stats->data[i].rate_name = "Ioc/s";
  2561. SET_COUNT;
  2562. break;
  2563. case _DRM_STAT_LOCKS:
  2564. stats->data[i].long_name = "Locks";
  2565. stats->data[i].rate_name = "Lck/s";
  2566. SET_COUNT;
  2567. break;
  2568. case _DRM_STAT_UNLOCKS:
  2569. stats->data[i].long_name = "Unlocks";
  2570. stats->data[i].rate_name = "Unl/s";
  2571. SET_COUNT;
  2572. break;
  2573. case _DRM_STAT_IRQ:
  2574. stats->data[i].long_name = "IRQs";
  2575. stats->data[i].rate_name = "IRQ/s";
  2576. SET_COUNT;
  2577. break;
  2578. case _DRM_STAT_PRIMARY:
  2579. stats->data[i].long_name = "Primary Bytes";
  2580. stats->data[i].rate_name = "PB/s";
  2581. SET_BYTE;
  2582. break;
  2583. case _DRM_STAT_SECONDARY:
  2584. stats->data[i].long_name = "Secondary Bytes";
  2585. stats->data[i].rate_name = "SB/s";
  2586. SET_BYTE;
  2587. break;
  2588. case _DRM_STAT_DMA:
  2589. stats->data[i].long_name = "DMA";
  2590. stats->data[i].rate_name = "DMA/s";
  2591. SET_COUNT;
  2592. break;
  2593. case _DRM_STAT_SPECIAL:
  2594. stats->data[i].long_name = "Special DMA";
  2595. stats->data[i].rate_name = "dma/s";
  2596. SET_COUNT;
  2597. break;
  2598. case _DRM_STAT_MISSED:
  2599. stats->data[i].long_name = "Miss";
  2600. stats->data[i].rate_name = "Ms/s";
  2601. SET_COUNT;
  2602. break;
  2603. case _DRM_STAT_VALUE:
  2604. stats->data[i].long_name = "Value";
  2605. stats->data[i].rate_name = "Value";
  2606. SET_VALUE;
  2607. break;
  2608. case _DRM_STAT_BYTE:
  2609. stats->data[i].long_name = "Bytes";
  2610. stats->data[i].rate_name = "B/s";
  2611. SET_BYTE;
  2612. break;
  2613. case _DRM_STAT_COUNT:
  2614. default:
  2615. stats->data[i].long_name = "Count";
  2616. stats->data[i].rate_name = "Cnt/s";
  2617. SET_COUNT;
  2618. break;
  2619. }
  2620. }
  2621. return 0;
  2622. }
  2623. /**
  2624. * Issue a set-version ioctl.
  2625. *
  2626. * \param fd file descriptor.
  2627. * \param drmCommandIndex command index
  2628. * \param data source pointer of the data to be read and written.
  2629. * \param size size of the data to be read and written.
  2630. *
  2631. * \return zero on success, or a negative value on failure.
  2632. *
  2633. * \internal
  2634. * It issues a read-write ioctl given by
  2635. * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  2636. */
  2637. drm_public int drmSetInterfaceVersion(int fd, drmSetVersion *version)
  2638. {
  2639. int retcode = 0;
  2640. drm_set_version_t sv;
  2641. memclear(sv);
  2642. sv.drm_di_major = version->drm_di_major;
  2643. sv.drm_di_minor = version->drm_di_minor;
  2644. sv.drm_dd_major = version->drm_dd_major;
  2645. sv.drm_dd_minor = version->drm_dd_minor;
  2646. if (drmIoctl(fd, DRM_IOCTL_SET_VERSION, &sv)) {
  2647. retcode = -errno;
  2648. }
  2649. version->drm_di_major = sv.drm_di_major;
  2650. version->drm_di_minor = sv.drm_di_minor;
  2651. version->drm_dd_major = sv.drm_dd_major;
  2652. version->drm_dd_minor = sv.drm_dd_minor;
  2653. return retcode;
  2654. }
  2655. /**
  2656. * Send a device-specific command.
  2657. *
  2658. * \param fd file descriptor.
  2659. * \param drmCommandIndex command index
  2660. *
  2661. * \return zero on success, or a negative value on failure.
  2662. *
  2663. * \internal
  2664. * It issues a ioctl given by
  2665. * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  2666. */
  2667. drm_public int drmCommandNone(int fd, unsigned long drmCommandIndex)
  2668. {
  2669. unsigned long request;
  2670. request = DRM_IO( DRM_COMMAND_BASE + drmCommandIndex);
  2671. if (drmIoctl(fd, request, NULL)) {
  2672. return -errno;
  2673. }
  2674. return 0;
  2675. }
  2676. /**
  2677. * Send a device-specific read command.
  2678. *
  2679. * \param fd file descriptor.
  2680. * \param drmCommandIndex command index
  2681. * \param data destination pointer of the data to be read.
  2682. * \param size size of the data to be read.
  2683. *
  2684. * \return zero on success, or a negative value on failure.
  2685. *
  2686. * \internal
  2687. * It issues a read ioctl given by
  2688. * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  2689. */
  2690. drm_public int drmCommandRead(int fd, unsigned long drmCommandIndex,
  2691. void *data, unsigned long size)
  2692. {
  2693. unsigned long request;
  2694. request = DRM_IOC( DRM_IOC_READ, DRM_IOCTL_BASE,
  2695. DRM_COMMAND_BASE + drmCommandIndex, size);
  2696. if (drmIoctl(fd, request, data)) {
  2697. return -errno;
  2698. }
  2699. return 0;
  2700. }
  2701. /**
  2702. * Send a device-specific write command.
  2703. *
  2704. * \param fd file descriptor.
  2705. * \param drmCommandIndex command index
  2706. * \param data source pointer of the data to be written.
  2707. * \param size size of the data to be written.
  2708. *
  2709. * \return zero on success, or a negative value on failure.
  2710. *
  2711. * \internal
  2712. * It issues a write ioctl given by
  2713. * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  2714. */
  2715. drm_public int drmCommandWrite(int fd, unsigned long drmCommandIndex,
  2716. void *data, unsigned long size)
  2717. {
  2718. unsigned long request;
  2719. request = DRM_IOC( DRM_IOC_WRITE, DRM_IOCTL_BASE,
  2720. DRM_COMMAND_BASE + drmCommandIndex, size);
  2721. if (drmIoctl(fd, request, data)) {
  2722. return -errno;
  2723. }
  2724. return 0;
  2725. }
  2726. /**
  2727. * Send a device-specific read-write command.
  2728. *
  2729. * \param fd file descriptor.
  2730. * \param drmCommandIndex command index
  2731. * \param data source pointer of the data to be read and written.
  2732. * \param size size of the data to be read and written.
  2733. *
  2734. * \return zero on success, or a negative value on failure.
  2735. *
  2736. * \internal
  2737. * It issues a read-write ioctl given by
  2738. * \code DRM_COMMAND_BASE + drmCommandIndex \endcode.
  2739. */
  2740. drm_public int drmCommandWriteRead(int fd, unsigned long drmCommandIndex,
  2741. void *data, unsigned long size)
  2742. {
  2743. unsigned long request;
  2744. request = DRM_IOC( DRM_IOC_READ|DRM_IOC_WRITE, DRM_IOCTL_BASE,
  2745. DRM_COMMAND_BASE + drmCommandIndex, size);
  2746. if (drmIoctl(fd, request, data))
  2747. return -errno;
  2748. return 0;
  2749. }
  2750. #define DRM_MAX_FDS 16
  2751. static struct {
  2752. char *BusID;
  2753. int fd;
  2754. int refcount;
  2755. int type;
  2756. } connection[DRM_MAX_FDS];
  2757. static int nr_fds = 0;
  2758. drm_public int drmOpenOnce(void *unused, const char *BusID, int *newlyopened)
  2759. {
  2760. return drmOpenOnceWithType(BusID, newlyopened, DRM_NODE_PRIMARY);
  2761. }
  2762. drm_public int drmOpenOnceWithType(const char *BusID, int *newlyopened,
  2763. int type)
  2764. {
  2765. int i;
  2766. int fd;
  2767. for (i = 0; i < nr_fds; i++)
  2768. if ((strcmp(BusID, connection[i].BusID) == 0) &&
  2769. (connection[i].type == type)) {
  2770. connection[i].refcount++;
  2771. *newlyopened = 0;
  2772. return connection[i].fd;
  2773. }
  2774. fd = drmOpenWithType(NULL, BusID, type);
  2775. if (fd < 0 || nr_fds == DRM_MAX_FDS)
  2776. return fd;
  2777. connection[nr_fds].BusID = strdup(BusID);
  2778. connection[nr_fds].fd = fd;
  2779. connection[nr_fds].refcount = 1;
  2780. connection[nr_fds].type = type;
  2781. *newlyopened = 1;
  2782. if (0)
  2783. fprintf(stderr, "saved connection %d for %s %d\n",
  2784. nr_fds, connection[nr_fds].BusID,
  2785. strcmp(BusID, connection[nr_fds].BusID));
  2786. nr_fds++;
  2787. return fd;
  2788. }
  2789. drm_public void drmCloseOnce(int fd)
  2790. {
  2791. int i;
  2792. for (i = 0; i < nr_fds; i++) {
  2793. if (fd == connection[i].fd) {
  2794. if (--connection[i].refcount == 0) {
  2795. drmClose(connection[i].fd);
  2796. free(connection[i].BusID);
  2797. if (i < --nr_fds)
  2798. connection[i] = connection[nr_fds];
  2799. return;
  2800. }
  2801. }
  2802. }
  2803. }
  2804. drm_public int drmSetMaster(int fd)
  2805. {
  2806. return drmIoctl(fd, DRM_IOCTL_SET_MASTER, NULL);
  2807. }
  2808. drm_public int drmDropMaster(int fd)
  2809. {
  2810. return drmIoctl(fd, DRM_IOCTL_DROP_MASTER, NULL);
  2811. }
  2812. drm_public int drmIsMaster(int fd)
  2813. {
  2814. /* Detect master by attempting something that requires master.
  2815. *
  2816. * Authenticating magic tokens requires master and 0 is an
  2817. * internal kernel detail which we could use. Attempting this on
  2818. * a master fd would fail therefore fail with EINVAL because 0
  2819. * is invalid.
  2820. *
  2821. * A non-master fd will fail with EACCES, as the kernel checks
  2822. * for master before attempting to do anything else.
  2823. *
  2824. * Since we don't want to leak implementation details, use
  2825. * EACCES.
  2826. */
  2827. return drmAuthMagic(fd, 0) != -EACCES;
  2828. }
  2829. drm_public char *drmGetDeviceNameFromFd(int fd)
  2830. {
  2831. #ifdef __FreeBSD__
  2832. struct stat sbuf;
  2833. int maj, min;
  2834. int nodetype;
  2835. if (fstat(fd, &sbuf))
  2836. return NULL;
  2837. maj = major(sbuf.st_rdev);
  2838. min = minor(sbuf.st_rdev);
  2839. nodetype = drmGetMinorType(maj, min);
  2840. return drmGetMinorNameForFD(fd, nodetype);
  2841. #else
  2842. char name[128];
  2843. struct stat sbuf;
  2844. dev_t d;
  2845. int i;
  2846. /* The whole drmOpen thing is a fiasco and we need to find a way
  2847. * back to just using open(2). For now, however, lets just make
  2848. * things worse with even more ad hoc directory walking code to
  2849. * discover the device file name. */
  2850. fstat(fd, &sbuf);
  2851. d = sbuf.st_rdev;
  2852. for (i = 0; i < DRM_MAX_MINOR; i++) {
  2853. snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i);
  2854. if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d)
  2855. break;
  2856. }
  2857. if (i == DRM_MAX_MINOR)
  2858. return NULL;
  2859. return strdup(name);
  2860. #endif
  2861. }
  2862. static bool drmNodeIsDRM(int maj, int min)
  2863. {
  2864. #ifdef __linux__
  2865. char path[64];
  2866. struct stat sbuf;
  2867. snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device/drm",
  2868. maj, min);
  2869. return stat(path, &sbuf) == 0;
  2870. #elif defined(__FreeBSD__)
  2871. char name[SPECNAMELEN];
  2872. if (!devname_r(makedev(maj, min), S_IFCHR, name, sizeof(name)))
  2873. return 0;
  2874. /* Handle drm/ and dri/ as both are present in different FreeBSD version
  2875. * FreeBSD on amd64/i386/powerpc external kernel modules create node in
  2876. * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
  2877. * only device nodes in /dev/dri/ */
  2878. return (!strncmp(name, "drm/", 4) || !strncmp(name, "dri/", 4));
  2879. #else
  2880. return maj == DRM_MAJOR;
  2881. #endif
  2882. }
  2883. drm_public int drmGetNodeTypeFromFd(int fd)
  2884. {
  2885. struct stat sbuf;
  2886. int maj, min, type;
  2887. if (fstat(fd, &sbuf))
  2888. return -1;
  2889. maj = major(sbuf.st_rdev);
  2890. min = minor(sbuf.st_rdev);
  2891. if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode)) {
  2892. errno = EINVAL;
  2893. return -1;
  2894. }
  2895. type = drmGetMinorType(maj, min);
  2896. if (type == -1)
  2897. errno = ENODEV;
  2898. return type;
  2899. }
  2900. drm_public int drmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags,
  2901. int *prime_fd)
  2902. {
  2903. struct drm_prime_handle args;
  2904. int ret;
  2905. memclear(args);
  2906. args.fd = -1;
  2907. args.handle = handle;
  2908. args.flags = flags;
  2909. ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args);
  2910. if (ret)
  2911. return ret;
  2912. *prime_fd = args.fd;
  2913. return 0;
  2914. }
  2915. drm_public int drmPrimeFDToHandle(int fd, int prime_fd, uint32_t *handle)
  2916. {
  2917. struct drm_prime_handle args;
  2918. int ret;
  2919. memclear(args);
  2920. args.fd = prime_fd;
  2921. ret = drmIoctl(fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &args);
  2922. if (ret)
  2923. return ret;
  2924. *handle = args.handle;
  2925. return 0;
  2926. }
  2927. drm_public int drmCloseBufferHandle(int fd, uint32_t handle)
  2928. {
  2929. struct drm_gem_close args;
  2930. memclear(args);
  2931. args.handle = handle;
  2932. return drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &args);
  2933. }
  2934. static char *drmGetMinorNameForFD(int fd, int type)
  2935. {
  2936. #ifdef __linux__
  2937. DIR *sysdir;
  2938. struct dirent *ent;
  2939. struct stat sbuf;
  2940. const char *name = drmGetMinorName(type);
  2941. int len;
  2942. char dev_name[64], buf[64];
  2943. int maj, min;
  2944. if (!name)
  2945. return NULL;
  2946. len = strlen(name);
  2947. if (fstat(fd, &sbuf))
  2948. return NULL;
  2949. maj = major(sbuf.st_rdev);
  2950. min = minor(sbuf.st_rdev);
  2951. if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
  2952. return NULL;
  2953. snprintf(buf, sizeof(buf), "/sys/dev/char/%d:%d/device/drm", maj, min);
  2954. sysdir = opendir(buf);
  2955. if (!sysdir)
  2956. return NULL;
  2957. while ((ent = readdir(sysdir))) {
  2958. if (strncmp(ent->d_name, name, len) == 0) {
  2959. if (snprintf(dev_name, sizeof(dev_name), DRM_DIR_NAME "/%s",
  2960. ent->d_name) < 0)
  2961. return NULL;
  2962. closedir(sysdir);
  2963. return strdup(dev_name);
  2964. }
  2965. }
  2966. closedir(sysdir);
  2967. return NULL;
  2968. #elif defined(__FreeBSD__)
  2969. struct stat sbuf;
  2970. char dname[SPECNAMELEN];
  2971. const char *mname;
  2972. char name[SPECNAMELEN];
  2973. int id, maj, min, nodetype, i;
  2974. if (fstat(fd, &sbuf))
  2975. return NULL;
  2976. maj = major(sbuf.st_rdev);
  2977. min = minor(sbuf.st_rdev);
  2978. if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
  2979. return NULL;
  2980. if (!devname_r(sbuf.st_rdev, S_IFCHR, dname, sizeof(dname)))
  2981. return NULL;
  2982. /* Handle both /dev/drm and /dev/dri
  2983. * FreeBSD on amd64/i386/powerpc external kernel modules create node in
  2984. * in /dev/drm/ and links in /dev/dri while a WIP in kernel driver creates
  2985. * only device nodes in /dev/dri/ */
  2986. /* Get the node type represented by fd so we can deduce the target name */
  2987. nodetype = drmGetMinorType(maj, min);
  2988. if (nodetype == -1)
  2989. return (NULL);
  2990. mname = drmGetMinorName(type);
  2991. for (i = 0; i < SPECNAMELEN; i++) {
  2992. if (isalpha(dname[i]) == 0 && dname[i] != '/')
  2993. break;
  2994. }
  2995. if (dname[i] == '\0')
  2996. return (NULL);
  2997. id = (int)strtol(&dname[i], NULL, 10);
  2998. id -= drmGetMinorBase(nodetype);
  2999. snprintf(name, sizeof(name), DRM_DIR_NAME "/%s%d", mname,
  3000. id + drmGetMinorBase(type));
  3001. return strdup(name);
  3002. #else
  3003. struct stat sbuf;
  3004. char buf[PATH_MAX + 1];
  3005. const char *dev_name = drmGetDeviceName(type);
  3006. unsigned int maj, min;
  3007. int n;
  3008. if (fstat(fd, &sbuf))
  3009. return NULL;
  3010. maj = major(sbuf.st_rdev);
  3011. min = minor(sbuf.st_rdev);
  3012. if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
  3013. return NULL;
  3014. if (!dev_name)
  3015. return NULL;
  3016. n = snprintf(buf, sizeof(buf), dev_name, DRM_DIR_NAME, min);
  3017. if (n == -1 || n >= sizeof(buf))
  3018. return NULL;
  3019. return strdup(buf);
  3020. #endif
  3021. }
  3022. drm_public char *drmGetPrimaryDeviceNameFromFd(int fd)
  3023. {
  3024. return drmGetMinorNameForFD(fd, DRM_NODE_PRIMARY);
  3025. }
  3026. drm_public char *drmGetRenderDeviceNameFromFd(int fd)
  3027. {
  3028. return drmGetMinorNameForFD(fd, DRM_NODE_RENDER);
  3029. }
  3030. #ifdef __linux__
  3031. static char * DRM_PRINTFLIKE(2, 3)
  3032. sysfs_uevent_get(const char *path, const char *fmt, ...)
  3033. {
  3034. char filename[PATH_MAX + 1], *key, *line = NULL, *value = NULL;
  3035. size_t size = 0, len;
  3036. ssize_t num;
  3037. va_list ap;
  3038. FILE *fp;
  3039. va_start(ap, fmt);
  3040. num = vasprintf(&key, fmt, ap);
  3041. va_end(ap);
  3042. len = num;
  3043. snprintf(filename, sizeof(filename), "%s/uevent", path);
  3044. fp = fopen(filename, "r");
  3045. if (!fp) {
  3046. free(key);
  3047. return NULL;
  3048. }
  3049. while ((num = getline(&line, &size, fp)) >= 0) {
  3050. if ((strncmp(line, key, len) == 0) && (line[len] == '=')) {
  3051. char *start = line + len + 1, *end = line + num - 1;
  3052. if (*end != '\n')
  3053. end++;
  3054. value = strndup(start, end - start);
  3055. break;
  3056. }
  3057. }
  3058. free(line);
  3059. fclose(fp);
  3060. free(key);
  3061. return value;
  3062. }
  3063. #endif
  3064. /* Little white lie to avoid major rework of the existing code */
  3065. #define DRM_BUS_VIRTIO 0x10
  3066. #ifdef __linux__
  3067. static int get_subsystem_type(const char *device_path)
  3068. {
  3069. char path[PATH_MAX + 1] = "";
  3070. char link[PATH_MAX + 1] = "";
  3071. char *name;
  3072. struct {
  3073. const char *name;
  3074. int bus_type;
  3075. } bus_types[] = {
  3076. { "/pci", DRM_BUS_PCI },
  3077. { "/usb", DRM_BUS_USB },
  3078. { "/platform", DRM_BUS_PLATFORM },
  3079. { "/spi", DRM_BUS_PLATFORM },
  3080. { "/host1x", DRM_BUS_HOST1X },
  3081. { "/virtio", DRM_BUS_VIRTIO },
  3082. { "/faux", DRM_BUS_FAUX },
  3083. };
  3084. strncpy(path, device_path, PATH_MAX);
  3085. strncat(path, "/subsystem", PATH_MAX);
  3086. if (readlink(path, link, PATH_MAX) < 0)
  3087. return -errno;
  3088. name = strrchr(link, '/');
  3089. if (!name)
  3090. return -EINVAL;
  3091. for (unsigned i = 0; i < ARRAY_SIZE(bus_types); i++) {
  3092. if (strncmp(name, bus_types[i].name, strlen(bus_types[i].name)) == 0)
  3093. return bus_types[i].bus_type;
  3094. }
  3095. return -EINVAL;
  3096. }
  3097. #endif
  3098. static int drmParseSubsystemType(int maj, int min)
  3099. {
  3100. #ifdef __linux__
  3101. char path[PATH_MAX + 1] = "";
  3102. char real_path[PATH_MAX + 1] = "";
  3103. int subsystem_type;
  3104. snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
  3105. subsystem_type = get_subsystem_type(path);
  3106. /* Try to get the parent (underlying) device type */
  3107. if (subsystem_type == DRM_BUS_VIRTIO) {
  3108. /* Assume virtio-pci on error */
  3109. if (!realpath(path, real_path))
  3110. return DRM_BUS_VIRTIO;
  3111. strncat(path, "/..", PATH_MAX);
  3112. subsystem_type = get_subsystem_type(path);
  3113. if (subsystem_type < 0)
  3114. return DRM_BUS_VIRTIO;
  3115. }
  3116. return subsystem_type;
  3117. #elif defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD__)
  3118. return DRM_BUS_PCI;
  3119. #else
  3120. #warning "Missing implementation of drmParseSubsystemType"
  3121. return -EINVAL;
  3122. #endif
  3123. }
  3124. #ifdef __linux__
  3125. static void
  3126. get_pci_path(int maj, int min, char *pci_path)
  3127. {
  3128. char path[PATH_MAX + 1], *term;
  3129. snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
  3130. if (!realpath(path, pci_path)) {
  3131. strcpy(pci_path, path);
  3132. return;
  3133. }
  3134. term = strrchr(pci_path, '/');
  3135. if (term && strncmp(term, "/virtio", 7) == 0)
  3136. *term = 0;
  3137. }
  3138. #endif
  3139. #ifdef __FreeBSD__
  3140. static int get_sysctl_pci_bus_info(int maj, int min, drmPciBusInfoPtr info)
  3141. {
  3142. char dname[SPECNAMELEN];
  3143. char sysctl_name[16];
  3144. char sysctl_val[256];
  3145. size_t sysctl_len;
  3146. int id, type, nelem;
  3147. unsigned int rdev, majmin, domain, bus, dev, func;
  3148. rdev = makedev(maj, min);
  3149. if (!devname_r(rdev, S_IFCHR, dname, sizeof(dname)))
  3150. return -EINVAL;
  3151. if (sscanf(dname, "drm/%d\n", &id) != 1)
  3152. return -EINVAL;
  3153. type = drmGetMinorType(maj, min);
  3154. if (type == -1)
  3155. return -EINVAL;
  3156. /* BUG: This above section is iffy, since it mandates that a driver will
  3157. * create both card and render node.
  3158. * If it does not, the next DRM device will create card#X and
  3159. * renderD#(128+X)-1.
  3160. * This is a possibility in FreeBSD but for now there is no good way for
  3161. * obtaining the info.
  3162. */
  3163. switch (type) {
  3164. case DRM_NODE_PRIMARY:
  3165. break;
  3166. case DRM_NODE_RENDER:
  3167. id -= 128;
  3168. break;
  3169. }
  3170. if (id < 0)
  3171. return -EINVAL;
  3172. if (snprintf(sysctl_name, sizeof(sysctl_name), "hw.dri.%d.busid", id) <= 0)
  3173. return -EINVAL;
  3174. sysctl_len = sizeof(sysctl_val);
  3175. if (sysctlbyname(sysctl_name, sysctl_val, &sysctl_len, NULL, 0))
  3176. return -EINVAL;
  3177. #define bus_fmt "pci:%04x:%02x:%02x.%u"
  3178. nelem = sscanf(sysctl_val, bus_fmt, &domain, &bus, &dev, &func);
  3179. if (nelem != 4)
  3180. return -EINVAL;
  3181. info->domain = domain;
  3182. info->bus = bus;
  3183. info->dev = dev;
  3184. info->func = func;
  3185. return 0;
  3186. }
  3187. #endif
  3188. static int drmParsePciBusInfo(int maj, int min, drmPciBusInfoPtr info)
  3189. {
  3190. #ifdef __linux__
  3191. unsigned int domain, bus, dev, func;
  3192. char pci_path[PATH_MAX + 1], *value;
  3193. int num;
  3194. get_pci_path(maj, min, pci_path);
  3195. value = sysfs_uevent_get(pci_path, "PCI_SLOT_NAME");
  3196. if (!value)
  3197. return -ENOENT;
  3198. num = sscanf(value, "%04x:%02x:%02x.%1u", &domain, &bus, &dev, &func);
  3199. free(value);
  3200. if (num != 4)
  3201. return -EINVAL;
  3202. info->domain = domain;
  3203. info->bus = bus;
  3204. info->dev = dev;
  3205. info->func = func;
  3206. return 0;
  3207. #elif defined(__OpenBSD__) || defined(__DragonFly__)
  3208. struct drm_pciinfo pinfo;
  3209. int fd, type;
  3210. type = drmGetMinorType(maj, min);
  3211. if (type == -1)
  3212. return -ENODEV;
  3213. fd = drmOpenMinor(min, 0, type);
  3214. if (fd < 0)
  3215. return -errno;
  3216. if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
  3217. close(fd);
  3218. return -errno;
  3219. }
  3220. close(fd);
  3221. info->domain = pinfo.domain;
  3222. info->bus = pinfo.bus;
  3223. info->dev = pinfo.dev;
  3224. info->func = pinfo.func;
  3225. return 0;
  3226. #elif defined(__FreeBSD__)
  3227. return get_sysctl_pci_bus_info(maj, min, info);
  3228. #else
  3229. #warning "Missing implementation of drmParsePciBusInfo"
  3230. return -EINVAL;
  3231. #endif
  3232. }
  3233. drm_public int drmDevicesEqual(drmDevicePtr a, drmDevicePtr b)
  3234. {
  3235. if (a == NULL || b == NULL)
  3236. return 0;
  3237. if (a->bustype != b->bustype)
  3238. return 0;
  3239. switch (a->bustype) {
  3240. case DRM_BUS_PCI:
  3241. return memcmp(a->businfo.pci, b->businfo.pci, sizeof(drmPciBusInfo)) == 0;
  3242. case DRM_BUS_USB:
  3243. return memcmp(a->businfo.usb, b->businfo.usb, sizeof(drmUsbBusInfo)) == 0;
  3244. case DRM_BUS_PLATFORM:
  3245. return memcmp(a->businfo.platform, b->businfo.platform, sizeof(drmPlatformBusInfo)) == 0;
  3246. case DRM_BUS_HOST1X:
  3247. return memcmp(a->businfo.host1x, b->businfo.host1x, sizeof(drmHost1xBusInfo)) == 0;
  3248. case DRM_BUS_FAUX:
  3249. return memcmp(a->businfo.faux, b->businfo.faux, sizeof(drmFauxBusInfo)) == 0;
  3250. default:
  3251. break;
  3252. }
  3253. return 0;
  3254. }
  3255. static int drmGetNodeType(const char *name)
  3256. {
  3257. if (strncmp(name, DRM_RENDER_MINOR_NAME,
  3258. sizeof(DRM_RENDER_MINOR_NAME) - 1) == 0)
  3259. return DRM_NODE_RENDER;
  3260. if (strncmp(name, DRM_PRIMARY_MINOR_NAME,
  3261. sizeof(DRM_PRIMARY_MINOR_NAME) - 1) == 0)
  3262. return DRM_NODE_PRIMARY;
  3263. return -EINVAL;
  3264. }
  3265. static int drmGetMaxNodeName(void)
  3266. {
  3267. return sizeof(DRM_DIR_NAME) +
  3268. MAX3(sizeof(DRM_PRIMARY_MINOR_NAME),
  3269. sizeof(DRM_CONTROL_MINOR_NAME),
  3270. sizeof(DRM_RENDER_MINOR_NAME)) +
  3271. 3 /* length of the node number */;
  3272. }
  3273. #ifdef __linux__
  3274. static int parse_separate_sysfs_files(int maj, int min,
  3275. drmPciDeviceInfoPtr device,
  3276. bool ignore_revision)
  3277. {
  3278. static const char *attrs[] = {
  3279. "revision", /* Older kernels are missing the file, so check for it first */
  3280. "vendor",
  3281. "device",
  3282. "subsystem_vendor",
  3283. "subsystem_device",
  3284. };
  3285. char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
  3286. unsigned int data[ARRAY_SIZE(attrs)];
  3287. FILE *fp;
  3288. int ret;
  3289. get_pci_path(maj, min, pci_path);
  3290. for (unsigned i = ignore_revision ? 1 : 0; i < ARRAY_SIZE(attrs); i++) {
  3291. if (snprintf(path, PATH_MAX, "%s/%s", pci_path, attrs[i]) < 0)
  3292. return -errno;
  3293. fp = fopen(path, "r");
  3294. if (!fp)
  3295. return -errno;
  3296. ret = fscanf(fp, "%x", &data[i]);
  3297. fclose(fp);
  3298. if (ret != 1)
  3299. return -errno;
  3300. }
  3301. device->revision_id = ignore_revision ? 0xff : data[0] & 0xff;
  3302. device->vendor_id = data[1] & 0xffff;
  3303. device->device_id = data[2] & 0xffff;
  3304. device->subvendor_id = data[3] & 0xffff;
  3305. device->subdevice_id = data[4] & 0xffff;
  3306. return 0;
  3307. }
  3308. static int parse_config_sysfs_file(int maj, int min,
  3309. drmPciDeviceInfoPtr device)
  3310. {
  3311. char path[PATH_MAX + 1], pci_path[PATH_MAX + 1];
  3312. unsigned char config[64];
  3313. int fd, ret;
  3314. get_pci_path(maj, min, pci_path);
  3315. if (snprintf(path, PATH_MAX, "%s/config", pci_path) < 0)
  3316. return -errno;
  3317. fd = open(path, O_RDONLY);
  3318. if (fd < 0)
  3319. return -errno;
  3320. ret = read(fd, config, sizeof(config));
  3321. close(fd);
  3322. if (ret < 0)
  3323. return -errno;
  3324. device->vendor_id = config[0] | (config[1] << 8);
  3325. device->device_id = config[2] | (config[3] << 8);
  3326. device->revision_id = config[8];
  3327. device->subvendor_id = config[44] | (config[45] << 8);
  3328. device->subdevice_id = config[46] | (config[47] << 8);
  3329. return 0;
  3330. }
  3331. #endif
  3332. static int drmParsePciDeviceInfo(int maj, int min,
  3333. drmPciDeviceInfoPtr device,
  3334. uint32_t flags)
  3335. {
  3336. #ifdef __linux__
  3337. if (!(flags & DRM_DEVICE_GET_PCI_REVISION))
  3338. return parse_separate_sysfs_files(maj, min, device, true);
  3339. if (parse_separate_sysfs_files(maj, min, device, false))
  3340. return parse_config_sysfs_file(maj, min, device);
  3341. return 0;
  3342. #elif defined(__OpenBSD__) || defined(__DragonFly__)
  3343. struct drm_pciinfo pinfo;
  3344. int fd, type;
  3345. type = drmGetMinorType(maj, min);
  3346. if (type == -1)
  3347. return -ENODEV;
  3348. fd = drmOpenMinor(min, 0, type);
  3349. if (fd < 0)
  3350. return -errno;
  3351. if (drmIoctl(fd, DRM_IOCTL_GET_PCIINFO, &pinfo)) {
  3352. close(fd);
  3353. return -errno;
  3354. }
  3355. close(fd);
  3356. device->vendor_id = pinfo.vendor_id;
  3357. device->device_id = pinfo.device_id;
  3358. device->revision_id = pinfo.revision_id;
  3359. device->subvendor_id = pinfo.subvendor_id;
  3360. device->subdevice_id = pinfo.subdevice_id;
  3361. return 0;
  3362. #elif defined(__FreeBSD__)
  3363. drmPciBusInfo info;
  3364. struct pci_conf_io pc;
  3365. struct pci_match_conf patterns[1];
  3366. struct pci_conf results[1];
  3367. int fd, error;
  3368. if (get_sysctl_pci_bus_info(maj, min, &info) != 0)
  3369. return -EINVAL;
  3370. fd = open("/dev/pci", O_RDONLY);
  3371. if (fd < 0)
  3372. return -errno;
  3373. bzero(&patterns, sizeof(patterns));
  3374. patterns[0].pc_sel.pc_domain = info.domain;
  3375. patterns[0].pc_sel.pc_bus = info.bus;
  3376. patterns[0].pc_sel.pc_dev = info.dev;
  3377. patterns[0].pc_sel.pc_func = info.func;
  3378. patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | PCI_GETCONF_MATCH_BUS
  3379. | PCI_GETCONF_MATCH_DEV | PCI_GETCONF_MATCH_FUNC;
  3380. bzero(&pc, sizeof(struct pci_conf_io));
  3381. pc.num_patterns = 1;
  3382. pc.pat_buf_len = sizeof(patterns);
  3383. pc.patterns = patterns;
  3384. pc.match_buf_len = sizeof(results);
  3385. pc.matches = results;
  3386. if (ioctl(fd, PCIOCGETCONF, &pc) || pc.status == PCI_GETCONF_ERROR) {
  3387. error = errno;
  3388. close(fd);
  3389. return -error;
  3390. }
  3391. close(fd);
  3392. device->vendor_id = results[0].pc_vendor;
  3393. device->device_id = results[0].pc_device;
  3394. device->subvendor_id = results[0].pc_subvendor;
  3395. device->subdevice_id = results[0].pc_subdevice;
  3396. device->revision_id = results[0].pc_revid;
  3397. return 0;
  3398. #else
  3399. #warning "Missing implementation of drmParsePciDeviceInfo"
  3400. return -EINVAL;
  3401. #endif
  3402. }
  3403. static void drmFreePlatformDevice(drmDevicePtr device)
  3404. {
  3405. if (device->deviceinfo.platform) {
  3406. if (device->deviceinfo.platform->compatible) {
  3407. char **compatible = device->deviceinfo.platform->compatible;
  3408. while (*compatible) {
  3409. free(*compatible);
  3410. compatible++;
  3411. }
  3412. free(device->deviceinfo.platform->compatible);
  3413. }
  3414. }
  3415. }
  3416. static void drmFreeHost1xDevice(drmDevicePtr device)
  3417. {
  3418. if (device->deviceinfo.host1x) {
  3419. if (device->deviceinfo.host1x->compatible) {
  3420. char **compatible = device->deviceinfo.host1x->compatible;
  3421. while (*compatible) {
  3422. free(*compatible);
  3423. compatible++;
  3424. }
  3425. free(device->deviceinfo.host1x->compatible);
  3426. }
  3427. }
  3428. }
  3429. drm_public void drmFreeDevice(drmDevicePtr *device)
  3430. {
  3431. if (device == NULL)
  3432. return;
  3433. if (*device) {
  3434. switch ((*device)->bustype) {
  3435. case DRM_BUS_PLATFORM:
  3436. drmFreePlatformDevice(*device);
  3437. break;
  3438. case DRM_BUS_HOST1X:
  3439. drmFreeHost1xDevice(*device);
  3440. break;
  3441. }
  3442. }
  3443. free(*device);
  3444. *device = NULL;
  3445. }
  3446. drm_public void drmFreeDevices(drmDevicePtr devices[], int count)
  3447. {
  3448. int i;
  3449. if (devices == NULL)
  3450. return;
  3451. for (i = 0; i < count; i++)
  3452. if (devices[i])
  3453. drmFreeDevice(&devices[i]);
  3454. }
  3455. static drmDevicePtr drmDeviceAlloc(unsigned int type, const char *node,
  3456. size_t bus_size, size_t device_size,
  3457. char **ptrp)
  3458. {
  3459. size_t max_node_length, extra, size;
  3460. drmDevicePtr device;
  3461. unsigned int i;
  3462. char *ptr;
  3463. max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
  3464. extra = DRM_NODE_MAX * (sizeof(void *) + max_node_length);
  3465. size = sizeof(*device) + extra + bus_size + device_size;
  3466. device = calloc(1, size);
  3467. if (!device)
  3468. return NULL;
  3469. device->available_nodes = 1 << type;
  3470. ptr = (char *)device + sizeof(*device);
  3471. device->nodes = (char **)ptr;
  3472. ptr += DRM_NODE_MAX * sizeof(void *);
  3473. for (i = 0; i < DRM_NODE_MAX; i++) {
  3474. device->nodes[i] = ptr;
  3475. ptr += max_node_length;
  3476. }
  3477. memcpy(device->nodes[type], node, max_node_length);
  3478. *ptrp = ptr;
  3479. return device;
  3480. }
  3481. static int drmProcessPciDevice(drmDevicePtr *device,
  3482. const char *node, int node_type,
  3483. int maj, int min, bool fetch_deviceinfo,
  3484. uint32_t flags)
  3485. {
  3486. drmDevicePtr dev;
  3487. char *addr;
  3488. int ret;
  3489. dev = drmDeviceAlloc(node_type, node, sizeof(drmPciBusInfo),
  3490. sizeof(drmPciDeviceInfo), &addr);
  3491. if (!dev)
  3492. return -ENOMEM;
  3493. dev->bustype = DRM_BUS_PCI;
  3494. dev->businfo.pci = (drmPciBusInfoPtr)addr;
  3495. ret = drmParsePciBusInfo(maj, min, dev->businfo.pci);
  3496. if (ret)
  3497. goto free_device;
  3498. // Fetch the device info if the user has requested it
  3499. if (fetch_deviceinfo) {
  3500. addr += sizeof(drmPciBusInfo);
  3501. dev->deviceinfo.pci = (drmPciDeviceInfoPtr)addr;
  3502. ret = drmParsePciDeviceInfo(maj, min, dev->deviceinfo.pci, flags);
  3503. if (ret)
  3504. goto free_device;
  3505. }
  3506. *device = dev;
  3507. return 0;
  3508. free_device:
  3509. free(dev);
  3510. return ret;
  3511. }
  3512. #ifdef __linux__
  3513. static int drm_usb_dev_path(int maj, int min, char *path, size_t len)
  3514. {
  3515. char *value, *tmp_path, *slash;
  3516. bool usb_device, usb_interface;
  3517. snprintf(path, len, "/sys/dev/char/%d:%d/device", maj, min);
  3518. value = sysfs_uevent_get(path, "DEVTYPE");
  3519. if (!value)
  3520. return -ENOENT;
  3521. usb_device = strcmp(value, "usb_device") == 0;
  3522. usb_interface = strcmp(value, "usb_interface") == 0;
  3523. free(value);
  3524. if (usb_device)
  3525. return 0;
  3526. if (!usb_interface)
  3527. return -ENOTSUP;
  3528. /* The parent of a usb_interface is a usb_device */
  3529. tmp_path = realpath(path, NULL);
  3530. if (!tmp_path)
  3531. return -errno;
  3532. slash = strrchr(tmp_path, '/');
  3533. if (!slash) {
  3534. free(tmp_path);
  3535. return -EINVAL;
  3536. }
  3537. *slash = '\0';
  3538. if (snprintf(path, len, "%s", tmp_path) >= (int)len) {
  3539. free(tmp_path);
  3540. return -EINVAL;
  3541. }
  3542. free(tmp_path);
  3543. return 0;
  3544. }
  3545. #endif
  3546. static int drmParseUsbBusInfo(int maj, int min, drmUsbBusInfoPtr info)
  3547. {
  3548. #ifdef __linux__
  3549. char path[PATH_MAX + 1], *value;
  3550. unsigned int bus, dev;
  3551. int ret;
  3552. ret = drm_usb_dev_path(maj, min, path, sizeof(path));
  3553. if (ret < 0)
  3554. return ret;
  3555. value = sysfs_uevent_get(path, "BUSNUM");
  3556. if (!value)
  3557. return -ENOENT;
  3558. ret = sscanf(value, "%03u", &bus);
  3559. free(value);
  3560. if (ret <= 0)
  3561. return -errno;
  3562. value = sysfs_uevent_get(path, "DEVNUM");
  3563. if (!value)
  3564. return -ENOENT;
  3565. ret = sscanf(value, "%03u", &dev);
  3566. free(value);
  3567. if (ret <= 0)
  3568. return -errno;
  3569. info->bus = bus;
  3570. info->dev = dev;
  3571. return 0;
  3572. #else
  3573. #warning "Missing implementation of drmParseUsbBusInfo"
  3574. return -EINVAL;
  3575. #endif
  3576. }
  3577. static int drmParseUsbDeviceInfo(int maj, int min, drmUsbDeviceInfoPtr info)
  3578. {
  3579. #ifdef __linux__
  3580. char path[PATH_MAX + 1], *value;
  3581. unsigned int vendor, product;
  3582. int ret;
  3583. ret = drm_usb_dev_path(maj, min, path, sizeof(path));
  3584. if (ret < 0)
  3585. return ret;
  3586. value = sysfs_uevent_get(path, "PRODUCT");
  3587. if (!value)
  3588. return -ENOENT;
  3589. ret = sscanf(value, "%x/%x", &vendor, &product);
  3590. free(value);
  3591. if (ret <= 0)
  3592. return -errno;
  3593. info->vendor = vendor;
  3594. info->product = product;
  3595. return 0;
  3596. #else
  3597. #warning "Missing implementation of drmParseUsbDeviceInfo"
  3598. return -EINVAL;
  3599. #endif
  3600. }
  3601. static int drmProcessUsbDevice(drmDevicePtr *device, const char *node,
  3602. int node_type, int maj, int min,
  3603. bool fetch_deviceinfo, uint32_t flags)
  3604. {
  3605. drmDevicePtr dev;
  3606. char *ptr;
  3607. int ret;
  3608. dev = drmDeviceAlloc(node_type, node, sizeof(drmUsbBusInfo),
  3609. sizeof(drmUsbDeviceInfo), &ptr);
  3610. if (!dev)
  3611. return -ENOMEM;
  3612. dev->bustype = DRM_BUS_USB;
  3613. dev->businfo.usb = (drmUsbBusInfoPtr)ptr;
  3614. ret = drmParseUsbBusInfo(maj, min, dev->businfo.usb);
  3615. if (ret < 0)
  3616. goto free_device;
  3617. if (fetch_deviceinfo) {
  3618. ptr += sizeof(drmUsbBusInfo);
  3619. dev->deviceinfo.usb = (drmUsbDeviceInfoPtr)ptr;
  3620. ret = drmParseUsbDeviceInfo(maj, min, dev->deviceinfo.usb);
  3621. if (ret < 0)
  3622. goto free_device;
  3623. }
  3624. *device = dev;
  3625. return 0;
  3626. free_device:
  3627. free(dev);
  3628. return ret;
  3629. }
  3630. static int drmParseOFBusInfo(int maj, int min, char *fullname)
  3631. {
  3632. #ifdef __linux__
  3633. char path[PATH_MAX + 1], *name, *tmp_name;
  3634. snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
  3635. name = sysfs_uevent_get(path, "OF_FULLNAME");
  3636. tmp_name = name;
  3637. if (!name) {
  3638. /* If the device lacks OF data, pick the MODALIAS info */
  3639. name = sysfs_uevent_get(path, "MODALIAS");
  3640. if (!name)
  3641. return -ENOENT;
  3642. /* .. and strip the MODALIAS=[platform,usb...]: part. */
  3643. tmp_name = strrchr(name, ':');
  3644. if (!tmp_name) {
  3645. free(name);
  3646. return -ENOENT;
  3647. }
  3648. tmp_name++;
  3649. }
  3650. strncpy(fullname, tmp_name, DRM_PLATFORM_DEVICE_NAME_LEN);
  3651. fullname[DRM_PLATFORM_DEVICE_NAME_LEN - 1] = '\0';
  3652. free(name);
  3653. return 0;
  3654. #else
  3655. #warning "Missing implementation of drmParseOFBusInfo"
  3656. return -EINVAL;
  3657. #endif
  3658. }
  3659. static int drmParseOFDeviceInfo(int maj, int min, char ***compatible)
  3660. {
  3661. #ifdef __linux__
  3662. char path[PATH_MAX + 1], *value, *tmp_name;
  3663. unsigned int count, i;
  3664. int err;
  3665. snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
  3666. value = sysfs_uevent_get(path, "OF_COMPATIBLE_N");
  3667. if (value) {
  3668. sscanf(value, "%u", &count);
  3669. free(value);
  3670. } else {
  3671. /* Assume one entry if the device lack OF data */
  3672. count = 1;
  3673. }
  3674. *compatible = calloc(count + 1, sizeof(char *));
  3675. if (!*compatible)
  3676. return -ENOMEM;
  3677. for (i = 0; i < count; i++) {
  3678. value = sysfs_uevent_get(path, "OF_COMPATIBLE_%u", i);
  3679. tmp_name = value;
  3680. if (!value) {
  3681. /* If the device lacks OF data, pick the MODALIAS info */
  3682. value = sysfs_uevent_get(path, "MODALIAS");
  3683. if (!value) {
  3684. err = -ENOENT;
  3685. goto free;
  3686. }
  3687. /* .. and strip the MODALIAS=[platform,usb...]: part. */
  3688. tmp_name = strrchr(value, ':');
  3689. if (!tmp_name) {
  3690. free(value);
  3691. return -ENOENT;
  3692. }
  3693. tmp_name = strdup(tmp_name + 1);
  3694. free(value);
  3695. }
  3696. (*compatible)[i] = tmp_name;
  3697. }
  3698. return 0;
  3699. free:
  3700. while (i--)
  3701. free((*compatible)[i]);
  3702. free(*compatible);
  3703. return err;
  3704. #else
  3705. #warning "Missing implementation of drmParseOFDeviceInfo"
  3706. return -EINVAL;
  3707. #endif
  3708. }
  3709. static int drmProcessPlatformDevice(drmDevicePtr *device,
  3710. const char *node, int node_type,
  3711. int maj, int min, bool fetch_deviceinfo,
  3712. uint32_t flags)
  3713. {
  3714. drmDevicePtr dev;
  3715. char *ptr;
  3716. int ret;
  3717. dev = drmDeviceAlloc(node_type, node, sizeof(drmPlatformBusInfo),
  3718. sizeof(drmPlatformDeviceInfo), &ptr);
  3719. if (!dev)
  3720. return -ENOMEM;
  3721. dev->bustype = DRM_BUS_PLATFORM;
  3722. dev->businfo.platform = (drmPlatformBusInfoPtr)ptr;
  3723. ret = drmParseOFBusInfo(maj, min, dev->businfo.platform->fullname);
  3724. if (ret < 0)
  3725. goto free_device;
  3726. if (fetch_deviceinfo) {
  3727. ptr += sizeof(drmPlatformBusInfo);
  3728. dev->deviceinfo.platform = (drmPlatformDeviceInfoPtr)ptr;
  3729. ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.platform->compatible);
  3730. if (ret < 0)
  3731. goto free_device;
  3732. }
  3733. *device = dev;
  3734. return 0;
  3735. free_device:
  3736. free(dev);
  3737. return ret;
  3738. }
  3739. static int drmProcessHost1xDevice(drmDevicePtr *device,
  3740. const char *node, int node_type,
  3741. int maj, int min, bool fetch_deviceinfo,
  3742. uint32_t flags)
  3743. {
  3744. drmDevicePtr dev;
  3745. char *ptr;
  3746. int ret;
  3747. dev = drmDeviceAlloc(node_type, node, sizeof(drmHost1xBusInfo),
  3748. sizeof(drmHost1xDeviceInfo), &ptr);
  3749. if (!dev)
  3750. return -ENOMEM;
  3751. dev->bustype = DRM_BUS_HOST1X;
  3752. dev->businfo.host1x = (drmHost1xBusInfoPtr)ptr;
  3753. ret = drmParseOFBusInfo(maj, min, dev->businfo.host1x->fullname);
  3754. if (ret < 0)
  3755. goto free_device;
  3756. if (fetch_deviceinfo) {
  3757. ptr += sizeof(drmHost1xBusInfo);
  3758. dev->deviceinfo.host1x = (drmHost1xDeviceInfoPtr)ptr;
  3759. ret = drmParseOFDeviceInfo(maj, min, &dev->deviceinfo.host1x->compatible);
  3760. if (ret < 0)
  3761. goto free_device;
  3762. }
  3763. *device = dev;
  3764. return 0;
  3765. free_device:
  3766. free(dev);
  3767. return ret;
  3768. }
  3769. static int drmParseFauxBusInfo(int maj, int min, char *fullname)
  3770. {
  3771. #ifdef __linux__
  3772. char path[PATH_MAX + 1] = "";
  3773. char real_path[PATH_MAX + 1] = "";
  3774. char *name;
  3775. snprintf(path, sizeof(path), "/sys/dev/char/%d:%d/device", maj, min);
  3776. if (!realpath(path, real_path))
  3777. return -errno;
  3778. name = basename(real_path);
  3779. if (!name)
  3780. return -ENOENT;
  3781. strncpy(fullname, name, DRM_FAUX_DEVICE_NAME_LEN - 1);
  3782. fullname[DRM_FAUX_DEVICE_NAME_LEN - 1] = '\0';
  3783. return 0;
  3784. #else
  3785. #warning "Missing implementation of drmParseFauxBusInfo"
  3786. return -EINVAL;
  3787. #endif
  3788. }
  3789. static int drmProcessFauxDevice(drmDevicePtr *device,
  3790. const char *node, int node_type,
  3791. int maj, int min, bool fetch_deviceinfo,
  3792. uint32_t flags)
  3793. {
  3794. drmDevicePtr dev;
  3795. char *ptr;
  3796. int ret;
  3797. dev = drmDeviceAlloc(node_type, node, sizeof(drmFauxBusInfo), 0, &ptr);
  3798. if (!dev)
  3799. return -ENOMEM;
  3800. dev->bustype = DRM_BUS_FAUX;
  3801. dev->businfo.faux = (drmFauxBusInfoPtr)ptr;
  3802. ret = drmParseFauxBusInfo(maj, min, dev->businfo.faux->name);
  3803. if (ret < 0)
  3804. goto free_device;
  3805. *device = dev;
  3806. return 0;
  3807. free_device:
  3808. free(dev);
  3809. return ret;
  3810. }
  3811. static int
  3812. process_device(drmDevicePtr *device, const char *d_name,
  3813. int req_subsystem_type,
  3814. bool fetch_deviceinfo, uint32_t flags)
  3815. {
  3816. struct stat sbuf;
  3817. char node[PATH_MAX + 1];
  3818. int node_type, subsystem_type, written;
  3819. unsigned int maj, min;
  3820. const int max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
  3821. node_type = drmGetNodeType(d_name);
  3822. if (node_type < 0)
  3823. return -1;
  3824. written = snprintf(node, PATH_MAX, "%s/%s", DRM_DIR_NAME, d_name);
  3825. if (written < 0)
  3826. return -1;
  3827. /* anything longer than this will be truncated in drmDeviceAlloc.
  3828. * Account for NULL byte
  3829. */
  3830. if (written + 1 > max_node_length)
  3831. return -1;
  3832. if (stat(node, &sbuf))
  3833. return -1;
  3834. maj = major(sbuf.st_rdev);
  3835. min = minor(sbuf.st_rdev);
  3836. if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
  3837. return -1;
  3838. subsystem_type = drmParseSubsystemType(maj, min);
  3839. if (req_subsystem_type != -1 && req_subsystem_type != subsystem_type)
  3840. return -1;
  3841. switch (subsystem_type) {
  3842. case DRM_BUS_PCI:
  3843. case DRM_BUS_VIRTIO:
  3844. return drmProcessPciDevice(device, node, node_type, maj, min,
  3845. fetch_deviceinfo, flags);
  3846. case DRM_BUS_USB:
  3847. return drmProcessUsbDevice(device, node, node_type, maj, min,
  3848. fetch_deviceinfo, flags);
  3849. case DRM_BUS_PLATFORM:
  3850. return drmProcessPlatformDevice(device, node, node_type, maj, min,
  3851. fetch_deviceinfo, flags);
  3852. case DRM_BUS_HOST1X:
  3853. return drmProcessHost1xDevice(device, node, node_type, maj, min,
  3854. fetch_deviceinfo, flags);
  3855. case DRM_BUS_FAUX:
  3856. return drmProcessFauxDevice(device, node, node_type, maj, min,
  3857. fetch_deviceinfo, flags);
  3858. default:
  3859. return -1;
  3860. }
  3861. }
  3862. /* Consider devices located on the same bus as duplicate and fold the respective
  3863. * entries into a single one.
  3864. *
  3865. * Note: this leaves "gaps" in the array, while preserving the length.
  3866. */
  3867. static void drmFoldDuplicatedDevices(drmDevicePtr local_devices[], int count)
  3868. {
  3869. int node_type, i, j;
  3870. for (i = 0; i < count; i++) {
  3871. for (j = i + 1; j < count; j++) {
  3872. if (drmDevicesEqual(local_devices[i], local_devices[j])) {
  3873. local_devices[i]->available_nodes |= local_devices[j]->available_nodes;
  3874. node_type = log2_int(local_devices[j]->available_nodes);
  3875. memcpy(local_devices[i]->nodes[node_type],
  3876. local_devices[j]->nodes[node_type], drmGetMaxNodeName());
  3877. drmFreeDevice(&local_devices[j]);
  3878. }
  3879. }
  3880. }
  3881. }
  3882. /* Check that the given flags are valid returning 0 on success */
  3883. static int
  3884. drm_device_validate_flags(uint32_t flags)
  3885. {
  3886. return (flags & ~DRM_DEVICE_GET_PCI_REVISION);
  3887. }
  3888. static bool
  3889. drm_device_has_rdev(drmDevicePtr device, dev_t find_rdev)
  3890. {
  3891. struct stat sbuf;
  3892. for (int i = 0; i < DRM_NODE_MAX; i++) {
  3893. if (device->available_nodes & 1 << i) {
  3894. if (stat(device->nodes[i], &sbuf) == 0 &&
  3895. sbuf.st_rdev == find_rdev)
  3896. return true;
  3897. }
  3898. }
  3899. return false;
  3900. }
  3901. /*
  3902. * The kernel drm core has a number of places that assume maximum of
  3903. * 3x64 devices nodes. That's 64 for each of primary, control and
  3904. * render nodes. Rounded it up to 256 for simplicity.
  3905. */
  3906. #define MAX_DRM_NODES 256
  3907. /**
  3908. * Get information about a device from its dev_t identifier
  3909. *
  3910. * \param find_rdev dev_t identifier of the device
  3911. * \param flags feature/behaviour bitmask
  3912. * \param device the address of a drmDevicePtr where the information
  3913. * will be allocated in stored
  3914. *
  3915. * \return zero on success, negative error code otherwise.
  3916. */
  3917. drm_public int drmGetDeviceFromDevId(dev_t find_rdev, uint32_t flags, drmDevicePtr *device)
  3918. {
  3919. #ifdef __OpenBSD__
  3920. /*
  3921. * DRI device nodes on OpenBSD are not in their own directory, they reside
  3922. * in /dev along with a large number of statically generated /dev nodes.
  3923. * Avoid stat'ing all of /dev needlessly by implementing this custom path.
  3924. */
  3925. drmDevicePtr d;
  3926. char node[PATH_MAX + 1];
  3927. const char *dev_name;
  3928. int node_type, subsystem_type;
  3929. int maj, min, n, ret;
  3930. const int max_node_length = ALIGN(drmGetMaxNodeName(), sizeof(void *));
  3931. struct stat sbuf;
  3932. if (device == NULL)
  3933. return -EINVAL;
  3934. maj = major(find_rdev);
  3935. min = minor(find_rdev);
  3936. if (!drmNodeIsDRM(maj, min))
  3937. return -EINVAL;
  3938. node_type = drmGetMinorType(maj, min);
  3939. if (node_type == -1)
  3940. return -ENODEV;
  3941. dev_name = drmGetDeviceName(node_type);
  3942. if (!dev_name)
  3943. return -EINVAL;
  3944. /* anything longer than this will be truncated in drmDeviceAlloc.
  3945. * Account for NULL byte
  3946. */
  3947. n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
  3948. if (n == -1 || n >= PATH_MAX)
  3949. return -errno;
  3950. if (n + 1 > max_node_length)
  3951. return -EINVAL;
  3952. if (stat(node, &sbuf))
  3953. return -EINVAL;
  3954. subsystem_type = drmParseSubsystemType(maj, min);
  3955. if (subsystem_type != DRM_BUS_PCI)
  3956. return -ENODEV;
  3957. ret = drmProcessPciDevice(&d, node, node_type, maj, min, true, flags);
  3958. if (ret)
  3959. return ret;
  3960. *device = d;
  3961. return 0;
  3962. #else
  3963. drmDevicePtr local_devices[MAX_DRM_NODES];
  3964. drmDevicePtr d;
  3965. DIR *sysdir;
  3966. struct dirent *dent;
  3967. int subsystem_type;
  3968. int maj, min;
  3969. int ret, i, node_count;
  3970. if (drm_device_validate_flags(flags))
  3971. return -EINVAL;
  3972. if (device == NULL)
  3973. return -EINVAL;
  3974. maj = major(find_rdev);
  3975. min = minor(find_rdev);
  3976. if (!drmNodeIsDRM(maj, min))
  3977. return -EINVAL;
  3978. subsystem_type = drmParseSubsystemType(maj, min);
  3979. if (subsystem_type < 0)
  3980. return subsystem_type;
  3981. sysdir = opendir(DRM_DIR_NAME);
  3982. if (!sysdir)
  3983. return -errno;
  3984. i = 0;
  3985. while ((dent = readdir(sysdir))) {
  3986. ret = process_device(&d, dent->d_name, subsystem_type, true, flags);
  3987. if (ret)
  3988. continue;
  3989. if (i >= MAX_DRM_NODES) {
  3990. fprintf(stderr, "More than %d drm nodes detected. "
  3991. "Please report a bug - that should not happen.\n"
  3992. "Skipping extra nodes\n", MAX_DRM_NODES);
  3993. break;
  3994. }
  3995. local_devices[i] = d;
  3996. i++;
  3997. }
  3998. node_count = i;
  3999. drmFoldDuplicatedDevices(local_devices, node_count);
  4000. *device = NULL;
  4001. for (i = 0; i < node_count; i++) {
  4002. if (!local_devices[i])
  4003. continue;
  4004. if (drm_device_has_rdev(local_devices[i], find_rdev))
  4005. *device = local_devices[i];
  4006. else
  4007. drmFreeDevice(&local_devices[i]);
  4008. }
  4009. closedir(sysdir);
  4010. if (*device == NULL)
  4011. return -ENODEV;
  4012. return 0;
  4013. #endif
  4014. }
  4015. drm_public int drmGetNodeTypeFromDevId(dev_t devid)
  4016. {
  4017. int maj, min, node_type;
  4018. maj = major(devid);
  4019. min = minor(devid);
  4020. if (!drmNodeIsDRM(maj, min))
  4021. return -EINVAL;
  4022. node_type = drmGetMinorType(maj, min);
  4023. if (node_type == -1)
  4024. return -ENODEV;
  4025. return node_type;
  4026. }
  4027. /**
  4028. * Get information about the opened drm device
  4029. *
  4030. * \param fd file descriptor of the drm device
  4031. * \param flags feature/behaviour bitmask
  4032. * \param device the address of a drmDevicePtr where the information
  4033. * will be allocated in stored
  4034. *
  4035. * \return zero on success, negative error code otherwise.
  4036. *
  4037. * \note Unlike drmGetDevice it does not retrieve the pci device revision field
  4038. * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
  4039. */
  4040. drm_public int drmGetDevice2(int fd, uint32_t flags, drmDevicePtr *device)
  4041. {
  4042. struct stat sbuf;
  4043. if (fd == -1)
  4044. return -EINVAL;
  4045. if (fstat(fd, &sbuf))
  4046. return -errno;
  4047. if (!S_ISCHR(sbuf.st_mode))
  4048. return -EINVAL;
  4049. return drmGetDeviceFromDevId(sbuf.st_rdev, flags, device);
  4050. }
  4051. /**
  4052. * Get information about the opened drm device
  4053. *
  4054. * \param fd file descriptor of the drm device
  4055. * \param device the address of a drmDevicePtr where the information
  4056. * will be allocated in stored
  4057. *
  4058. * \return zero on success, negative error code otherwise.
  4059. */
  4060. drm_public int drmGetDevice(int fd, drmDevicePtr *device)
  4061. {
  4062. return drmGetDevice2(fd, DRM_DEVICE_GET_PCI_REVISION, device);
  4063. }
  4064. /**
  4065. * Get drm devices on the system
  4066. *
  4067. * \param flags feature/behaviour bitmask
  4068. * \param devices the array of devices with drmDevicePtr elements
  4069. * can be NULL to get the device number first
  4070. * \param max_devices the maximum number of devices for the array
  4071. *
  4072. * \return on error - negative error code,
  4073. * if devices is NULL - total number of devices available on the system,
  4074. * alternatively the number of devices stored in devices[], which is
  4075. * capped by the max_devices.
  4076. *
  4077. * \note Unlike drmGetDevices it does not retrieve the pci device revision field
  4078. * unless the DRM_DEVICE_GET_PCI_REVISION \p flag is set.
  4079. */
  4080. drm_public int drmGetDevices2(uint32_t flags, drmDevicePtr devices[],
  4081. int max_devices)
  4082. {
  4083. drmDevicePtr local_devices[MAX_DRM_NODES];
  4084. drmDevicePtr device;
  4085. DIR *sysdir;
  4086. struct dirent *dent;
  4087. int ret, i, node_count, device_count;
  4088. if (drm_device_validate_flags(flags))
  4089. return -EINVAL;
  4090. sysdir = opendir(DRM_DIR_NAME);
  4091. if (!sysdir)
  4092. return -errno;
  4093. i = 0;
  4094. while ((dent = readdir(sysdir))) {
  4095. ret = process_device(&device, dent->d_name, -1, devices != NULL, flags);
  4096. if (ret)
  4097. continue;
  4098. if (i >= MAX_DRM_NODES) {
  4099. fprintf(stderr, "More than %d drm nodes detected. "
  4100. "Please report a bug - that should not happen.\n"
  4101. "Skipping extra nodes\n", MAX_DRM_NODES);
  4102. break;
  4103. }
  4104. local_devices[i] = device;
  4105. i++;
  4106. }
  4107. node_count = i;
  4108. drmFoldDuplicatedDevices(local_devices, node_count);
  4109. device_count = 0;
  4110. for (i = 0; i < node_count; i++) {
  4111. if (!local_devices[i])
  4112. continue;
  4113. if ((devices != NULL) && (device_count < max_devices))
  4114. devices[device_count] = local_devices[i];
  4115. else
  4116. drmFreeDevice(&local_devices[i]);
  4117. device_count++;
  4118. }
  4119. closedir(sysdir);
  4120. if (devices != NULL)
  4121. return MIN2(device_count, max_devices);
  4122. return device_count;
  4123. }
  4124. /**
  4125. * Get drm devices on the system
  4126. *
  4127. * \param devices the array of devices with drmDevicePtr elements
  4128. * can be NULL to get the device number first
  4129. * \param max_devices the maximum number of devices for the array
  4130. *
  4131. * \return on error - negative error code,
  4132. * if devices is NULL - total number of devices available on the system,
  4133. * alternatively the number of devices stored in devices[], which is
  4134. * capped by the max_devices.
  4135. */
  4136. drm_public int drmGetDevices(drmDevicePtr devices[], int max_devices)
  4137. {
  4138. return drmGetDevices2(DRM_DEVICE_GET_PCI_REVISION, devices, max_devices);
  4139. }
  4140. drm_public char *drmGetDeviceNameFromFd2(int fd)
  4141. {
  4142. #ifdef __linux__
  4143. struct stat sbuf;
  4144. char path[PATH_MAX + 1], *value;
  4145. unsigned int maj, min;
  4146. if (fstat(fd, &sbuf))
  4147. return NULL;
  4148. maj = major(sbuf.st_rdev);
  4149. min = minor(sbuf.st_rdev);
  4150. if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
  4151. return NULL;
  4152. snprintf(path, sizeof(path), "/sys/dev/char/%d:%d", maj, min);
  4153. value = sysfs_uevent_get(path, "DEVNAME");
  4154. if (!value)
  4155. return NULL;
  4156. snprintf(path, sizeof(path), "/dev/%s", value);
  4157. free(value);
  4158. return strdup(path);
  4159. #elif defined(__FreeBSD__)
  4160. return drmGetDeviceNameFromFd(fd);
  4161. #else
  4162. struct stat sbuf;
  4163. char node[PATH_MAX + 1];
  4164. const char *dev_name;
  4165. int node_type;
  4166. int maj, min, n;
  4167. if (fstat(fd, &sbuf))
  4168. return NULL;
  4169. maj = major(sbuf.st_rdev);
  4170. min = minor(sbuf.st_rdev);
  4171. if (!drmNodeIsDRM(maj, min) || !S_ISCHR(sbuf.st_mode))
  4172. return NULL;
  4173. node_type = drmGetMinorType(maj, min);
  4174. if (node_type == -1)
  4175. return NULL;
  4176. dev_name = drmGetDeviceName(node_type);
  4177. if (!dev_name)
  4178. return NULL;
  4179. n = snprintf(node, PATH_MAX, dev_name, DRM_DIR_NAME, min);
  4180. if (n == -1 || n >= PATH_MAX)
  4181. return NULL;
  4182. return strdup(node);
  4183. #endif
  4184. }
  4185. drm_public int drmSyncobjCreate(int fd, uint32_t flags, uint32_t *handle)
  4186. {
  4187. struct drm_syncobj_create args;
  4188. int ret;
  4189. memclear(args);
  4190. args.flags = flags;
  4191. args.handle = 0;
  4192. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_CREATE, &args);
  4193. if (ret)
  4194. return ret;
  4195. *handle = args.handle;
  4196. return 0;
  4197. }
  4198. drm_public int drmSyncobjDestroy(int fd, uint32_t handle)
  4199. {
  4200. struct drm_syncobj_destroy args;
  4201. memclear(args);
  4202. args.handle = handle;
  4203. return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_DESTROY, &args);
  4204. }
  4205. drm_public int drmSyncobjHandleToFD(int fd, uint32_t handle, int *obj_fd)
  4206. {
  4207. struct drm_syncobj_handle args;
  4208. int ret;
  4209. memclear(args);
  4210. args.fd = -1;
  4211. args.handle = handle;
  4212. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
  4213. if (ret)
  4214. return ret;
  4215. *obj_fd = args.fd;
  4216. return 0;
  4217. }
  4218. drm_public int drmSyncobjFDToHandle(int fd, int obj_fd, uint32_t *handle)
  4219. {
  4220. struct drm_syncobj_handle args;
  4221. int ret;
  4222. memclear(args);
  4223. args.fd = obj_fd;
  4224. args.handle = 0;
  4225. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
  4226. if (ret)
  4227. return ret;
  4228. *handle = args.handle;
  4229. return 0;
  4230. }
  4231. drm_public int drmSyncobjImportSyncFile(int fd, uint32_t handle,
  4232. int sync_file_fd)
  4233. {
  4234. struct drm_syncobj_handle args;
  4235. memclear(args);
  4236. args.fd = sync_file_fd;
  4237. args.handle = handle;
  4238. args.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE;
  4239. return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &args);
  4240. }
  4241. drm_public int drmSyncobjExportSyncFile(int fd, uint32_t handle,
  4242. int *sync_file_fd)
  4243. {
  4244. struct drm_syncobj_handle args;
  4245. int ret;
  4246. memclear(args);
  4247. args.fd = -1;
  4248. args.handle = handle;
  4249. args.flags = DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE;
  4250. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &args);
  4251. if (ret)
  4252. return ret;
  4253. *sync_file_fd = args.fd;
  4254. return 0;
  4255. }
  4256. drm_public int drmSyncobjWait(int fd, uint32_t *handles, unsigned num_handles,
  4257. int64_t timeout_nsec, unsigned flags,
  4258. uint32_t *first_signaled)
  4259. {
  4260. struct drm_syncobj_wait args;
  4261. int ret;
  4262. memclear(args);
  4263. args.handles = (uintptr_t)handles;
  4264. args.timeout_nsec = timeout_nsec;
  4265. args.count_handles = num_handles;
  4266. args.flags = flags;
  4267. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_WAIT, &args);
  4268. if (ret < 0)
  4269. return -errno;
  4270. if (first_signaled)
  4271. *first_signaled = args.first_signaled;
  4272. return ret;
  4273. }
  4274. drm_public int drmSyncobjReset(int fd, const uint32_t *handles,
  4275. uint32_t handle_count)
  4276. {
  4277. struct drm_syncobj_array args;
  4278. int ret;
  4279. memclear(args);
  4280. args.handles = (uintptr_t)handles;
  4281. args.count_handles = handle_count;
  4282. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_RESET, &args);
  4283. return ret;
  4284. }
  4285. drm_public int drmSyncobjSignal(int fd, const uint32_t *handles,
  4286. uint32_t handle_count)
  4287. {
  4288. struct drm_syncobj_array args;
  4289. int ret;
  4290. memclear(args);
  4291. args.handles = (uintptr_t)handles;
  4292. args.count_handles = handle_count;
  4293. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &args);
  4294. return ret;
  4295. }
  4296. drm_public int drmSyncobjTimelineSignal(int fd, const uint32_t *handles,
  4297. uint64_t *points, uint32_t handle_count)
  4298. {
  4299. struct drm_syncobj_timeline_array args;
  4300. int ret;
  4301. memclear(args);
  4302. args.handles = (uintptr_t)handles;
  4303. args.points = (uintptr_t)points;
  4304. args.count_handles = handle_count;
  4305. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, &args);
  4306. return ret;
  4307. }
  4308. drm_public int drmSyncobjTimelineWait(int fd, uint32_t *handles, uint64_t *points,
  4309. unsigned num_handles,
  4310. int64_t timeout_nsec, unsigned flags,
  4311. uint32_t *first_signaled)
  4312. {
  4313. struct drm_syncobj_timeline_wait args;
  4314. int ret;
  4315. memclear(args);
  4316. args.handles = (uintptr_t)handles;
  4317. args.points = (uintptr_t)points;
  4318. args.timeout_nsec = timeout_nsec;
  4319. args.count_handles = num_handles;
  4320. args.flags = flags;
  4321. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, &args);
  4322. if (ret < 0)
  4323. return -errno;
  4324. if (first_signaled)
  4325. *first_signaled = args.first_signaled;
  4326. return ret;
  4327. }
  4328. drm_public int drmSyncobjQuery(int fd, uint32_t *handles, uint64_t *points,
  4329. uint32_t handle_count)
  4330. {
  4331. struct drm_syncobj_timeline_array args;
  4332. int ret;
  4333. memclear(args);
  4334. args.handles = (uintptr_t)handles;
  4335. args.points = (uintptr_t)points;
  4336. args.count_handles = handle_count;
  4337. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
  4338. if (ret)
  4339. return ret;
  4340. return 0;
  4341. }
  4342. drm_public int drmSyncobjQuery2(int fd, uint32_t *handles, uint64_t *points,
  4343. uint32_t handle_count, uint32_t flags)
  4344. {
  4345. struct drm_syncobj_timeline_array args;
  4346. memclear(args);
  4347. args.handles = (uintptr_t)handles;
  4348. args.points = (uintptr_t)points;
  4349. args.count_handles = handle_count;
  4350. args.flags = flags;
  4351. return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_QUERY, &args);
  4352. }
  4353. drm_public int drmSyncobjTransfer(int fd,
  4354. uint32_t dst_handle, uint64_t dst_point,
  4355. uint32_t src_handle, uint64_t src_point,
  4356. uint32_t flags)
  4357. {
  4358. struct drm_syncobj_transfer args;
  4359. int ret;
  4360. memclear(args);
  4361. args.src_handle = src_handle;
  4362. args.dst_handle = dst_handle;
  4363. args.src_point = src_point;
  4364. args.dst_point = dst_point;
  4365. args.flags = flags;
  4366. ret = drmIoctl(fd, DRM_IOCTL_SYNCOBJ_TRANSFER, &args);
  4367. return ret;
  4368. }
  4369. drm_public int drmSyncobjEventfd(int fd, uint32_t handle, uint64_t point, int ev_fd,
  4370. uint32_t flags)
  4371. {
  4372. struct drm_syncobj_eventfd args;
  4373. memclear(args);
  4374. args.handle = handle;
  4375. args.point = point;
  4376. args.fd = ev_fd;
  4377. args.flags = flags;
  4378. return drmIoctl(fd, DRM_IOCTL_SYNCOBJ_EVENTFD, &args);
  4379. }
  4380. static char *
  4381. drmGetFormatModifierFromSimpleTokens(uint64_t modifier)
  4382. {
  4383. unsigned int i;
  4384. for (i = 0; i < ARRAY_SIZE(drm_format_modifier_table); i++) {
  4385. if (drm_format_modifier_table[i].modifier == modifier)
  4386. return strdup(drm_format_modifier_table[i].modifier_name);
  4387. }
  4388. return NULL;
  4389. }
  4390. /** Retrieves a human-readable representation of a vendor (as a string) from
  4391. * the format token modifier
  4392. *
  4393. * \param modifier the format modifier token
  4394. * \return a char pointer to the human-readable form of the vendor. Caller is
  4395. * responsible for freeing it.
  4396. */
  4397. drm_public char *
  4398. drmGetFormatModifierVendor(uint64_t modifier)
  4399. {
  4400. unsigned int i;
  4401. uint8_t vendor = fourcc_mod_get_vendor(modifier);
  4402. for (i = 0; i < ARRAY_SIZE(drm_format_modifier_vendor_table); i++) {
  4403. if (drm_format_modifier_vendor_table[i].vendor == vendor)
  4404. return strdup(drm_format_modifier_vendor_table[i].vendor_name);
  4405. }
  4406. return NULL;
  4407. }
  4408. /** Retrieves a human-readable representation string from a format token
  4409. * modifier
  4410. *
  4411. * If the dedicated function was not able to extract a valid name or searching
  4412. * the format modifier was not in the table, this function would return NULL.
  4413. *
  4414. * \param modifier the token format
  4415. * \return a malloc'ed string representation of the modifier. Caller is
  4416. * responsible for freeing the string returned.
  4417. *
  4418. */
  4419. drm_public char *
  4420. drmGetFormatModifierName(uint64_t modifier)
  4421. {
  4422. uint8_t vendorid = fourcc_mod_get_vendor(modifier);
  4423. char *modifier_found = NULL;
  4424. unsigned int i;
  4425. for (i = 0; i < ARRAY_SIZE(modifier_format_vendor_table); i++) {
  4426. if (modifier_format_vendor_table[i].vendor == vendorid)
  4427. modifier_found = modifier_format_vendor_table[i].vendor_cb(modifier);
  4428. }
  4429. if (!modifier_found)
  4430. return drmGetFormatModifierFromSimpleTokens(modifier);
  4431. return modifier_found;
  4432. }
  4433. /**
  4434. * Get a human-readable name for a DRM FourCC format.
  4435. *
  4436. * \param format The format.
  4437. * \return A malloc'ed string containing the format name. Caller is responsible
  4438. * for freeing it.
  4439. */
  4440. drm_public char *
  4441. drmGetFormatName(uint32_t format)
  4442. {
  4443. char *str, code[5];
  4444. const char *be;
  4445. size_t str_size, i;
  4446. be = (format & DRM_FORMAT_BIG_ENDIAN) ? "_BE" : "";
  4447. format &= ~DRM_FORMAT_BIG_ENDIAN;
  4448. if (format == DRM_FORMAT_INVALID)
  4449. return strdup("INVALID");
  4450. code[0] = (char) ((format >> 0) & 0xFF);
  4451. code[1] = (char) ((format >> 8) & 0xFF);
  4452. code[2] = (char) ((format >> 16) & 0xFF);
  4453. code[3] = (char) ((format >> 24) & 0xFF);
  4454. code[4] = '\0';
  4455. /* Trim spaces at the end */
  4456. for (i = 3; i > 0 && code[i] == ' '; i--)
  4457. code[i] = '\0';
  4458. str_size = strlen(code) + strlen(be) + 1;
  4459. str = malloc(str_size);
  4460. if (!str)
  4461. return NULL;
  4462. snprintf(str, str_size, "%s%s", code, be);
  4463. return str;
  4464. }