orinoco.patch 362 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938
  1. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/Kconfig linux-6.18.9/drivers/net/wireless/intersil/Kconfig
  2. --- linux-6.18.9.orig/drivers/net/wireless/intersil/Kconfig 2026-02-06 16:57:45.000000000 +0100
  3. +++ linux-6.18.9/drivers/net/wireless/intersil/Kconfig 2026-02-16 14:00:36.619256404 +0100
  4. @@ -12,6 +12,7 @@
  5. if WLAN_VENDOR_INTERSIL
  6. +source "drivers/net/wireless/intersil/orinoco/Kconfig"
  7. source "drivers/net/wireless/intersil/p54/Kconfig"
  8. endif # WLAN_VENDOR_INTERSIL
  9. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/Makefile linux-6.18.9/drivers/net/wireless/intersil/Makefile
  10. --- linux-6.18.9.orig/drivers/net/wireless/intersil/Makefile 2026-02-06 16:57:45.000000000 +0100
  11. +++ linux-6.18.9/drivers/net/wireless/intersil/Makefile 2026-02-16 14:00:36.619256404 +0100
  12. @@ -1,2 +1,3 @@
  13. # SPDX-License-Identifier: GPL-2.0-only
  14. +obj-$(CONFIG_HERMES) += orinoco/
  15. obj-$(CONFIG_P54_COMMON) += p54/
  16. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/airport.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/airport.c
  17. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/airport.c 1970-01-01 01:00:00.000000000 +0100
  18. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/airport.c 2026-02-16 14:00:36.619256404 +0100
  19. @@ -0,0 +1,268 @@
  20. +/* airport.c
  21. + *
  22. + * A driver for "Hermes" chipset based Apple Airport wireless
  23. + * card.
  24. + *
  25. + * Copyright notice & release notes in file main.c
  26. + *
  27. + * Note specific to airport stub:
  28. + *
  29. + * 0.05 : first version of the new split driver
  30. + * 0.06 : fix possible hang on powerup, add sleep support
  31. + */
  32. +
  33. +#define DRIVER_NAME "airport"
  34. +#define PFX DRIVER_NAME ": "
  35. +
  36. +#include <linux/module.h>
  37. +#include <linux/kernel.h>
  38. +#include <linux/init.h>
  39. +#include <linux/delay.h>
  40. +#include <linux/mod_devicetable.h>
  41. +#include <asm/pmac_feature.h>
  42. +
  43. +#include "orinoco.h"
  44. +
  45. +#define AIRPORT_IO_LEN (0x1000) /* one page */
  46. +
  47. +struct airport {
  48. + struct macio_dev *mdev;
  49. + void __iomem *vaddr;
  50. + unsigned int irq;
  51. + int irq_requested;
  52. + int ndev_registered;
  53. +};
  54. +
  55. +static int
  56. +airport_suspend(struct macio_dev *mdev, pm_message_t state)
  57. +{
  58. + struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
  59. + struct net_device *dev = priv->ndev;
  60. + struct airport *card = priv->card;
  61. + unsigned long flags;
  62. + int err;
  63. +
  64. + printk(KERN_DEBUG "%s: Airport entering sleep mode\n", dev->name);
  65. +
  66. + err = orinoco_lock(priv, &flags);
  67. + if (err) {
  68. + printk(KERN_ERR "%s: hw_unavailable on PBOOK_SLEEP_NOW\n",
  69. + dev->name);
  70. + return 0;
  71. + }
  72. +
  73. + orinoco_down(priv);
  74. + orinoco_unlock(priv, &flags);
  75. +
  76. + disable_irq(card->irq);
  77. + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
  78. + macio_get_of_node(mdev), 0, 0);
  79. +
  80. + return 0;
  81. +}
  82. +
  83. +static int
  84. +airport_resume(struct macio_dev *mdev)
  85. +{
  86. + struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
  87. + struct net_device *dev = priv->ndev;
  88. + struct airport *card = priv->card;
  89. + unsigned long flags;
  90. + int err;
  91. +
  92. + printk(KERN_DEBUG "%s: Airport waking up\n", dev->name);
  93. +
  94. + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
  95. + macio_get_of_node(mdev), 0, 1);
  96. + msleep(200);
  97. +
  98. + enable_irq(card->irq);
  99. +
  100. + priv->hw.ops->lock_irqsave(&priv->lock, &flags);
  101. + err = orinoco_up(priv);
  102. + priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
  103. +
  104. + return err;
  105. +}
  106. +
  107. +static int
  108. +airport_detach(struct macio_dev *mdev)
  109. +{
  110. + struct orinoco_private *priv = dev_get_drvdata(&mdev->ofdev.dev);
  111. + struct airport *card = priv->card;
  112. +
  113. + if (card->ndev_registered)
  114. + orinoco_if_del(priv);
  115. + card->ndev_registered = 0;
  116. +
  117. + if (card->irq_requested)
  118. + free_irq(card->irq, priv);
  119. + card->irq_requested = 0;
  120. +
  121. + if (card->vaddr)
  122. + iounmap(card->vaddr);
  123. + card->vaddr = NULL;
  124. +
  125. + macio_release_resource(mdev, 0);
  126. +
  127. + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
  128. + macio_get_of_node(mdev), 0, 0);
  129. + ssleep(1);
  130. +
  131. + macio_set_drvdata(mdev, NULL);
  132. + free_orinocodev(priv);
  133. +
  134. + return 0;
  135. +}
  136. +
  137. +static int airport_hard_reset(struct orinoco_private *priv)
  138. +{
  139. + /* It would be nice to power cycle the Airport for a real hard
  140. + * reset, but for some reason although it appears to
  141. + * re-initialize properly, it falls in a screaming heap
  142. + * shortly afterwards. */
  143. +#if 0
  144. + struct airport *card = priv->card;
  145. +
  146. + /* Vitally important. If we don't do this it seems we get an
  147. + * interrupt somewhere during the power cycle, since
  148. + * hw_unavailable is already set it doesn't get ACKed, we get
  149. + * into an interrupt loop and the PMU decides to turn us
  150. + * off. */
  151. + disable_irq(card->irq);
  152. +
  153. + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
  154. + macio_get_of_node(card->mdev), 0, 0);
  155. + ssleep(1);
  156. + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
  157. + macio_get_of_node(card->mdev), 0, 1);
  158. + ssleep(1);
  159. +
  160. + enable_irq(card->irq);
  161. + ssleep(1);
  162. +#endif
  163. +
  164. + return 0;
  165. +}
  166. +
  167. +static int
  168. +airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
  169. +{
  170. + struct orinoco_private *priv;
  171. + struct airport *card;
  172. + unsigned long phys_addr;
  173. + struct hermes *hw;
  174. +
  175. + if (macio_resource_count(mdev) < 1 || macio_irq_count(mdev) < 1) {
  176. + printk(KERN_ERR PFX "Wrong interrupt/addresses in OF tree\n");
  177. + return -ENODEV;
  178. + }
  179. +
  180. + /* Allocate space for private device-specific data */
  181. + priv = alloc_orinocodev(sizeof(*card), &mdev->ofdev.dev,
  182. + airport_hard_reset, NULL);
  183. + if (!priv) {
  184. + printk(KERN_ERR PFX "Cannot allocate network device\n");
  185. + return -ENODEV;
  186. + }
  187. + card = priv->card;
  188. +
  189. + hw = &priv->hw;
  190. + card->mdev = mdev;
  191. +
  192. + if (macio_request_resource(mdev, 0, DRIVER_NAME)) {
  193. + printk(KERN_ERR PFX "can't request IO resource !\n");
  194. + free_orinocodev(priv);
  195. + return -EBUSY;
  196. + }
  197. +
  198. + macio_set_drvdata(mdev, priv);
  199. +
  200. + /* Setup interrupts & base address */
  201. + card->irq = macio_irq(mdev, 0);
  202. + phys_addr = macio_resource_start(mdev, 0); /* Physical address */
  203. + printk(KERN_DEBUG PFX "Physical address %lx\n", phys_addr);
  204. + card->vaddr = ioremap(phys_addr, AIRPORT_IO_LEN);
  205. + if (!card->vaddr) {
  206. + printk(KERN_ERR PFX "ioremap() failed\n");
  207. + goto failed;
  208. + }
  209. +
  210. + hermes_struct_init(hw, card->vaddr, HERMES_16BIT_REGSPACING);
  211. +
  212. + /* Power up card */
  213. + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE,
  214. + macio_get_of_node(mdev), 0, 1);
  215. + ssleep(1);
  216. +
  217. + /* Reset it before we get the interrupt */
  218. + hw->ops->init(hw);
  219. +
  220. + if (request_irq(card->irq, orinoco_interrupt, 0, DRIVER_NAME, priv)) {
  221. + printk(KERN_ERR PFX "Couldn't get IRQ %d\n", card->irq);
  222. + goto failed;
  223. + }
  224. + card->irq_requested = 1;
  225. +
  226. + /* Initialise the main driver */
  227. + if (orinoco_init(priv) != 0) {
  228. + printk(KERN_ERR PFX "orinoco_init() failed\n");
  229. + goto failed;
  230. + }
  231. +
  232. + /* Register an interface with the stack */
  233. + if (orinoco_if_add(priv, phys_addr, card->irq, NULL) != 0) {
  234. + printk(KERN_ERR PFX "orinoco_if_add() failed\n");
  235. + goto failed;
  236. + }
  237. + card->ndev_registered = 1;
  238. + return 0;
  239. + failed:
  240. + airport_detach(mdev);
  241. + return -ENODEV;
  242. +} /* airport_attach */
  243. +
  244. +
  245. +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
  246. + " (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
  247. +MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
  248. +MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
  249. +MODULE_LICENSE("Dual MPL/GPL");
  250. +
  251. +static const struct of_device_id airport_match[] = {
  252. + {
  253. + .name = "radio",
  254. + },
  255. + {},
  256. +};
  257. +
  258. +MODULE_DEVICE_TABLE(of, airport_match);
  259. +
  260. +static struct macio_driver airport_driver = {
  261. + .driver = {
  262. + .name = DRIVER_NAME,
  263. + .owner = THIS_MODULE,
  264. + .of_match_table = airport_match,
  265. + },
  266. + .probe = airport_attach,
  267. + .remove = airport_detach,
  268. + .suspend = airport_suspend,
  269. + .resume = airport_resume,
  270. +};
  271. +
  272. +static int __init
  273. +init_airport(void)
  274. +{
  275. + printk(KERN_DEBUG "%s\n", version);
  276. +
  277. + return macio_register_driver(&airport_driver);
  278. +}
  279. +
  280. +static void __exit
  281. +exit_airport(void)
  282. +{
  283. + macio_unregister_driver(&airport_driver);
  284. +}
  285. +
  286. +module_init(init_airport);
  287. +module_exit(exit_airport);
  288. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/cfg.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/cfg.c
  289. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/cfg.c 1970-01-01 01:00:00.000000000 +0100
  290. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/cfg.c 2026-02-16 14:03:20.553871680 +0100
  291. @@ -0,0 +1,297 @@
  292. +/* cfg80211 support
  293. + *
  294. + * See copyright notice in main.c
  295. + */
  296. +#include <linux/ieee80211.h>
  297. +#include <net/cfg80211.h>
  298. +#include "hw.h"
  299. +#include "main.h"
  300. +#include "orinoco.h"
  301. +
  302. +#include "cfg.h"
  303. +
  304. +/* Supported bitrates. Must agree with hw.c */
  305. +static struct ieee80211_rate orinoco_rates[] = {
  306. + { .bitrate = 10 },
  307. + { .bitrate = 20 },
  308. + { .bitrate = 55 },
  309. + { .bitrate = 110 },
  310. +};
  311. +
  312. +static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid;
  313. +
  314. +/* Called after orinoco_private is allocated. */
  315. +void orinoco_wiphy_init(struct wiphy *wiphy)
  316. +{
  317. + struct orinoco_private *priv = wiphy_priv(wiphy);
  318. +
  319. + wiphy->privid = orinoco_wiphy_privid;
  320. +
  321. + set_wiphy_dev(wiphy, priv->dev);
  322. +}
  323. +
  324. +/* Called after firmware is initialised */
  325. +int orinoco_wiphy_register(struct wiphy *wiphy)
  326. +{
  327. + struct orinoco_private *priv = wiphy_priv(wiphy);
  328. + int i, channels = 0;
  329. +
  330. + if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
  331. + wiphy->max_scan_ssids = 1;
  332. + else
  333. + wiphy->max_scan_ssids = 0;
  334. +
  335. + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
  336. +
  337. + /* TODO: should we set if we only have demo ad-hoc?
  338. + * (priv->has_port3)
  339. + */
  340. + if (priv->has_ibss)
  341. + wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
  342. +
  343. + if (!priv->broken_monitor || force_monitor)
  344. + wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
  345. +
  346. + priv->band.bitrates = orinoco_rates;
  347. + priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);
  348. +
  349. + /* Only support channels allowed by the card EEPROM */
  350. + for (i = 0; i < NUM_CHANNELS; i++) {
  351. + if (priv->channel_mask & (1 << i)) {
  352. + priv->channels[i].center_freq =
  353. + ieee80211_channel_to_frequency(i + 1,
  354. + NL80211_BAND_2GHZ);
  355. + channels++;
  356. + }
  357. + }
  358. + priv->band.channels = priv->channels;
  359. + priv->band.n_channels = channels;
  360. +
  361. + wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
  362. + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
  363. +
  364. + i = 0;
  365. + if (priv->has_wep) {
  366. + priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
  367. + i++;
  368. +
  369. + if (priv->has_big_wep) {
  370. + priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
  371. + i++;
  372. + }
  373. + }
  374. + if (priv->has_wpa) {
  375. + priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
  376. + i++;
  377. + }
  378. + wiphy->cipher_suites = priv->cipher_suites;
  379. + wiphy->n_cipher_suites = i;
  380. +
  381. + wiphy->rts_threshold = priv->rts_thresh;
  382. + if (!priv->has_mwo)
  383. + wiphy->frag_threshold = priv->frag_thresh + 1;
  384. + wiphy->retry_short = priv->short_retry_limit;
  385. + wiphy->retry_long = priv->long_retry_limit;
  386. +
  387. + return wiphy_register(wiphy);
  388. +}
  389. +
  390. +static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
  391. + enum nl80211_iftype type,
  392. + struct vif_params *params)
  393. +{
  394. + struct orinoco_private *priv = wiphy_priv(wiphy);
  395. + int err = 0;
  396. + unsigned long lock;
  397. +
  398. + if (orinoco_lock(priv, &lock) != 0)
  399. + return -EBUSY;
  400. +
  401. + switch (type) {
  402. + case NL80211_IFTYPE_ADHOC:
  403. + if (!priv->has_ibss && !priv->has_port3)
  404. + err = -EINVAL;
  405. + break;
  406. +
  407. + case NL80211_IFTYPE_STATION:
  408. + break;
  409. +
  410. + case NL80211_IFTYPE_MONITOR:
  411. + if (priv->broken_monitor && !force_monitor) {
  412. + wiphy_warn(wiphy,
  413. + "Monitor mode support is buggy in this firmware, not enabling\n");
  414. + err = -EINVAL;
  415. + }
  416. + break;
  417. +
  418. + default:
  419. + err = -EINVAL;
  420. + }
  421. +
  422. + if (!err) {
  423. + priv->iw_mode = type;
  424. + set_port_type(priv);
  425. + err = orinoco_commit(priv);
  426. + }
  427. +
  428. + orinoco_unlock(priv, &lock);
  429. +
  430. + return err;
  431. +}
  432. +
  433. +static int orinoco_scan(struct wiphy *wiphy,
  434. + struct cfg80211_scan_request *request)
  435. +{
  436. + struct orinoco_private *priv = wiphy_priv(wiphy);
  437. + int err;
  438. +
  439. + if (!request)
  440. + return -EINVAL;
  441. +
  442. + if (priv->scan_request && priv->scan_request != request)
  443. + return -EBUSY;
  444. +
  445. + priv->scan_request = request;
  446. +
  447. + err = orinoco_hw_trigger_scan(priv, request->ssids);
  448. + /* On error the we aren't processing the request */
  449. + if (err)
  450. + priv->scan_request = NULL;
  451. +
  452. + return err;
  453. +}
  454. +
  455. +static int orinoco_set_monitor_channel(struct wiphy *wiphy,
  456. + struct net_device *dev,
  457. + struct cfg80211_chan_def *chandef)
  458. +{
  459. + struct orinoco_private *priv = wiphy_priv(wiphy);
  460. + int err = 0;
  461. + unsigned long flags;
  462. + int channel;
  463. +
  464. + if (!chandef->chan)
  465. + return -EINVAL;
  466. +
  467. + if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
  468. + return -EINVAL;
  469. +
  470. + if (chandef->chan->band != NL80211_BAND_2GHZ)
  471. + return -EINVAL;
  472. +
  473. + channel = ieee80211_frequency_to_channel(chandef->chan->center_freq);
  474. +
  475. + if ((channel < 1) || (channel > NUM_CHANNELS) ||
  476. + !(priv->channel_mask & (1 << (channel - 1))))
  477. + return -EINVAL;
  478. +
  479. + if (orinoco_lock(priv, &flags) != 0)
  480. + return -EBUSY;
  481. +
  482. + priv->channel = channel;
  483. + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
  484. + /* Fast channel change - no commit if successful */
  485. + struct hermes *hw = &priv->hw;
  486. + err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
  487. + HERMES_TEST_SET_CHANNEL,
  488. + channel, NULL);
  489. + }
  490. + orinoco_unlock(priv, &flags);
  491. +
  492. + return err;
  493. +}
  494. +
  495. +static int orinoco_set_wiphy_params(struct wiphy *wiphy,
  496. + int radio_idx,
  497. + u32 changed)
  498. +{
  499. + struct orinoco_private *priv = wiphy_priv(wiphy);
  500. + int frag_value = -1;
  501. + int rts_value = -1;
  502. + int err = 0;
  503. +
  504. + if (radio_idx != 0)
  505. + return -EINVAL;
  506. +
  507. + if (changed & WIPHY_PARAM_RETRY_SHORT) {
  508. + /* Setting short retry not supported */
  509. + err = -EINVAL;
  510. + }
  511. +
  512. + if (changed & WIPHY_PARAM_RETRY_LONG) {
  513. + /* Setting long retry not supported */
  514. + err = -EINVAL;
  515. + }
  516. +
  517. + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
  518. + /* Set fragmentation */
  519. + if (priv->has_mwo) {
  520. + if (wiphy->frag_threshold == -1)
  521. + frag_value = 0;
  522. + else {
  523. + printk(KERN_WARNING "%s: Fixed fragmentation "
  524. + "is not supported on this firmware. "
  525. + "Using MWO robust instead.\n",
  526. + priv->ndev->name);
  527. + frag_value = 1;
  528. + }
  529. + } else {
  530. + if (wiphy->frag_threshold == -1)
  531. + frag_value = 2346;
  532. + else if ((wiphy->frag_threshold < 257) ||
  533. + (wiphy->frag_threshold > 2347))
  534. + err = -EINVAL;
  535. + else
  536. + /* cfg80211 value is 257-2347 (odd only)
  537. + * orinoco rid has range 256-2346 (even only) */
  538. + frag_value = wiphy->frag_threshold & ~0x1;
  539. + }
  540. + }
  541. +
  542. + if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
  543. + /* Set RTS.
  544. + *
  545. + * Prism documentation suggests default of 2432,
  546. + * and a range of 0-3000.
  547. + *
  548. + * Current implementation uses 2347 as the default and
  549. + * the upper limit.
  550. + */
  551. +
  552. + if (wiphy->rts_threshold == -1)
  553. + rts_value = 2347;
  554. + else if (wiphy->rts_threshold > 2347)
  555. + err = -EINVAL;
  556. + else
  557. + rts_value = wiphy->rts_threshold;
  558. + }
  559. +
  560. + if (!err) {
  561. + unsigned long flags;
  562. +
  563. + if (orinoco_lock(priv, &flags) != 0)
  564. + return -EBUSY;
  565. +
  566. + if (frag_value >= 0) {
  567. + if (priv->has_mwo)
  568. + priv->mwo_robust = frag_value;
  569. + else
  570. + priv->frag_thresh = frag_value;
  571. + }
  572. + if (rts_value >= 0)
  573. + priv->rts_thresh = rts_value;
  574. +
  575. + err = orinoco_commit(priv);
  576. +
  577. + orinoco_unlock(priv, &flags);
  578. + }
  579. +
  580. + return err;
  581. +}
  582. +
  583. +const struct cfg80211_ops orinoco_cfg_ops = {
  584. + .change_virtual_intf = orinoco_change_vif,
  585. + .set_monitor_channel = orinoco_set_monitor_channel,
  586. + .scan = orinoco_scan,
  587. + .set_wiphy_params = orinoco_set_wiphy_params,
  588. +};
  589. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/cfg.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/cfg.h
  590. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/cfg.h 1970-01-01 01:00:00.000000000 +0100
  591. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/cfg.h 2026-02-16 14:00:36.619256404 +0100
  592. @@ -0,0 +1,15 @@
  593. +/* cfg80211 support.
  594. + *
  595. + * See copyright notice in main.c
  596. + */
  597. +#ifndef ORINOCO_CFG_H
  598. +#define ORINOCO_CFG_H
  599. +
  600. +#include <net/cfg80211.h>
  601. +
  602. +extern const struct cfg80211_ops orinoco_cfg_ops;
  603. +
  604. +void orinoco_wiphy_init(struct wiphy *wiphy);
  605. +int orinoco_wiphy_register(struct wiphy *wiphy);
  606. +
  607. +#endif /* ORINOCO_CFG_H */
  608. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/fw.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/fw.c
  609. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/fw.c 1970-01-01 01:00:00.000000000 +0100
  610. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/fw.c 2026-02-16 14:00:36.619256404 +0100
  611. @@ -0,0 +1,387 @@
  612. +/* Firmware file reading and download helpers
  613. + *
  614. + * See copyright notice in main.c
  615. + */
  616. +#include <linux/kernel.h>
  617. +#include <linux/slab.h>
  618. +#include <linux/firmware.h>
  619. +#include <linux/device.h>
  620. +#include <linux/module.h>
  621. +
  622. +#include "hermes.h"
  623. +#include "hermes_dld.h"
  624. +#include "orinoco.h"
  625. +
  626. +#include "fw.h"
  627. +
  628. +/* End markers (for Symbol firmware only) */
  629. +#define TEXT_END 0x1A /* End of text header */
  630. +
  631. +struct fw_info {
  632. + char *pri_fw;
  633. + char *sta_fw;
  634. + char *ap_fw;
  635. + u32 pda_addr;
  636. + u16 pda_size;
  637. +};
  638. +
  639. +static const struct fw_info orinoco_fw[] = {
  640. + { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
  641. + { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
  642. + { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 }
  643. +};
  644. +MODULE_FIRMWARE("agere_sta_fw.bin");
  645. +MODULE_FIRMWARE("agere_ap_fw.bin");
  646. +MODULE_FIRMWARE("prism_sta_fw.bin");
  647. +MODULE_FIRMWARE("prism_ap_fw.bin");
  648. +MODULE_FIRMWARE("symbol_sp24t_prim_fw");
  649. +MODULE_FIRMWARE("symbol_sp24t_sec_fw");
  650. +
  651. +/* Structure used to access fields in FW
  652. + * Make sure LE decoding macros are used
  653. + */
  654. +struct orinoco_fw_header {
  655. + char hdr_vers[6]; /* ASCII string for header version */
  656. + __le16 headersize; /* Total length of header */
  657. + __le32 entry_point; /* NIC entry point */
  658. + __le32 blocks; /* Number of blocks to program */
  659. + __le32 block_offset; /* Offset of block data from eof header */
  660. + __le32 pdr_offset; /* Offset to PDR data from eof header */
  661. + __le32 pri_offset; /* Offset to primary plug data */
  662. + __le32 compat_offset; /* Offset to compatibility data*/
  663. + char signature[]; /* FW signature length headersize-20 */
  664. +} __packed;
  665. +
  666. +/* Check the range of various header entries. Return a pointer to a
  667. + * description of the problem, or NULL if everything checks out. */
  668. +static const char *validate_fw(const struct orinoco_fw_header *hdr, size_t len)
  669. +{
  670. + u16 hdrsize;
  671. +
  672. + if (len < sizeof(*hdr))
  673. + return "image too small";
  674. + if (memcmp(hdr->hdr_vers, "HFW", 3) != 0)
  675. + return "format not recognised";
  676. +
  677. + hdrsize = le16_to_cpu(hdr->headersize);
  678. + if (hdrsize > len)
  679. + return "bad headersize";
  680. + if ((hdrsize + le32_to_cpu(hdr->block_offset)) > len)
  681. + return "bad block offset";
  682. + if ((hdrsize + le32_to_cpu(hdr->pdr_offset)) > len)
  683. + return "bad PDR offset";
  684. + if ((hdrsize + le32_to_cpu(hdr->pri_offset)) > len)
  685. + return "bad PRI offset";
  686. + if ((hdrsize + le32_to_cpu(hdr->compat_offset)) > len)
  687. + return "bad compat offset";
  688. +
  689. + /* TODO: consider adding a checksum or CRC to the firmware format */
  690. + return NULL;
  691. +}
  692. +
  693. +#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
  694. +static inline const struct firmware *
  695. +orinoco_cached_fw_get(struct orinoco_private *priv, bool primary)
  696. +{
  697. + if (primary)
  698. + return priv->cached_pri_fw;
  699. + else
  700. + return priv->cached_fw;
  701. +}
  702. +#else
  703. +#define orinoco_cached_fw_get(priv, primary) (NULL)
  704. +#endif
  705. +
  706. +/* Download either STA or AP firmware into the card. */
  707. +static int
  708. +orinoco_dl_firmware(struct orinoco_private *priv,
  709. + const struct fw_info *fw,
  710. + int ap)
  711. +{
  712. + /* Plug Data Area (PDA) */
  713. + __le16 *pda;
  714. +
  715. + struct hermes *hw = &priv->hw;
  716. + const struct firmware *fw_entry;
  717. + const struct orinoco_fw_header *hdr;
  718. + const unsigned char *first_block;
  719. + const void *end;
  720. + const char *firmware;
  721. + const char *fw_err;
  722. + struct device *dev = priv->dev;
  723. + int err = 0;
  724. +
  725. + pda = kzalloc(fw->pda_size, GFP_KERNEL);
  726. + if (!pda)
  727. + return -ENOMEM;
  728. +
  729. + if (ap)
  730. + firmware = fw->ap_fw;
  731. + else
  732. + firmware = fw->sta_fw;
  733. +
  734. + dev_dbg(dev, "Attempting to download firmware %s\n", firmware);
  735. +
  736. + /* Read current plug data */
  737. + err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
  738. + dev_dbg(dev, "Read PDA returned %d\n", err);
  739. + if (err)
  740. + goto free;
  741. +
  742. + if (!orinoco_cached_fw_get(priv, false)) {
  743. + err = request_firmware(&fw_entry, firmware, priv->dev);
  744. +
  745. + if (err) {
  746. + dev_err(dev, "Cannot find firmware %s\n", firmware);
  747. + err = -ENOENT;
  748. + goto free;
  749. + }
  750. + } else
  751. + fw_entry = orinoco_cached_fw_get(priv, false);
  752. +
  753. + hdr = (const struct orinoco_fw_header *) fw_entry->data;
  754. +
  755. + fw_err = validate_fw(hdr, fw_entry->size);
  756. + if (fw_err) {
  757. + dev_warn(dev, "Invalid firmware image detected (%s). "
  758. + "Aborting download\n", fw_err);
  759. + err = -EINVAL;
  760. + goto abort;
  761. + }
  762. +
  763. + /* Enable aux port to allow programming */
  764. + err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point));
  765. + dev_dbg(dev, "Program init returned %d\n", err);
  766. + if (err != 0)
  767. + goto abort;
  768. +
  769. + /* Program data */
  770. + first_block = (fw_entry->data +
  771. + le16_to_cpu(hdr->headersize) +
  772. + le32_to_cpu(hdr->block_offset));
  773. + end = fw_entry->data + fw_entry->size;
  774. +
  775. + err = hermes_program(hw, first_block, end);
  776. + dev_dbg(dev, "Program returned %d\n", err);
  777. + if (err != 0)
  778. + goto abort;
  779. +
  780. + /* Update production data */
  781. + first_block = (fw_entry->data +
  782. + le16_to_cpu(hdr->headersize) +
  783. + le32_to_cpu(hdr->pdr_offset));
  784. +
  785. + err = hermes_apply_pda_with_defaults(hw, first_block, end, pda,
  786. + &pda[fw->pda_size / sizeof(*pda)]);
  787. + dev_dbg(dev, "Apply PDA returned %d\n", err);
  788. + if (err)
  789. + goto abort;
  790. +
  791. + /* Tell card we've finished */
  792. + err = hw->ops->program_end(hw);
  793. + dev_dbg(dev, "Program end returned %d\n", err);
  794. + if (err != 0)
  795. + goto abort;
  796. +
  797. + /* Check if we're running */
  798. + dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw));
  799. +
  800. +abort:
  801. + /* If we requested the firmware, release it. */
  802. + if (!orinoco_cached_fw_get(priv, false))
  803. + release_firmware(fw_entry);
  804. +
  805. +free:
  806. + kfree(pda);
  807. + return err;
  808. +}
  809. +
  810. +/*
  811. + * Process a firmware image - stop the card, load the firmware, reset
  812. + * the card and make sure it responds. For the secondary firmware take
  813. + * care of the PDA - read it and then write it on top of the firmware.
  814. + */
  815. +static int
  816. +symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
  817. + const unsigned char *image, const void *end,
  818. + int secondary)
  819. +{
  820. + struct hermes *hw = &priv->hw;
  821. + int ret = 0;
  822. + const unsigned char *ptr;
  823. + const unsigned char *first_block;
  824. +
  825. + /* Plug Data Area (PDA) */
  826. + __le16 *pda = NULL;
  827. +
  828. + /* Binary block begins after the 0x1A marker */
  829. + ptr = image;
  830. + while (*ptr++ != TEXT_END);
  831. + first_block = ptr;
  832. +
  833. + /* Read the PDA from EEPROM */
  834. + if (secondary) {
  835. + pda = kzalloc(fw->pda_size, GFP_KERNEL);
  836. + if (!pda)
  837. + return -ENOMEM;
  838. +
  839. + ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size);
  840. + if (ret)
  841. + goto free;
  842. + }
  843. +
  844. + /* Stop the firmware, so that it can be safely rewritten */
  845. + if (priv->stop_fw) {
  846. + ret = priv->stop_fw(priv, 1);
  847. + if (ret)
  848. + goto free;
  849. + }
  850. +
  851. + /* Program the adapter with new firmware */
  852. + ret = hermes_program(hw, first_block, end);
  853. + if (ret)
  854. + goto free;
  855. +
  856. + /* Write the PDA to the adapter */
  857. + if (secondary) {
  858. + size_t len = hermes_blocks_length(first_block, end);
  859. + ptr = first_block + len;
  860. + ret = hermes_apply_pda(hw, ptr, end, pda,
  861. + &pda[fw->pda_size / sizeof(*pda)]);
  862. + kfree(pda);
  863. + if (ret)
  864. + return ret;
  865. + }
  866. +
  867. + /* Run the firmware */
  868. + if (priv->stop_fw) {
  869. + ret = priv->stop_fw(priv, 0);
  870. + if (ret)
  871. + return ret;
  872. + }
  873. +
  874. + /* Reset hermes chip and make sure it responds */
  875. + ret = hw->ops->init(hw);
  876. +
  877. + /* hermes_reset() should return 0 with the secondary firmware */
  878. + if (secondary && ret != 0)
  879. + return -ENODEV;
  880. +
  881. + /* And this should work with any firmware */
  882. + if (!hermes_present(hw))
  883. + return -ENODEV;
  884. +
  885. + return 0;
  886. +
  887. +free:
  888. + kfree(pda);
  889. + return ret;
  890. +}
  891. +
  892. +
  893. +/*
  894. + * Download the firmware into the card, this also does a PCMCIA soft
  895. + * reset on the card, to make sure it's in a sane state.
  896. + */
  897. +static int
  898. +symbol_dl_firmware(struct orinoco_private *priv,
  899. + const struct fw_info *fw)
  900. +{
  901. + struct device *dev = priv->dev;
  902. + int ret;
  903. + const struct firmware *fw_entry;
  904. +
  905. + if (!orinoco_cached_fw_get(priv, true)) {
  906. + if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
  907. + dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw);
  908. + return -ENOENT;
  909. + }
  910. + } else
  911. + fw_entry = orinoco_cached_fw_get(priv, true);
  912. +
  913. + /* Load primary firmware */
  914. + ret = symbol_dl_image(priv, fw, fw_entry->data,
  915. + fw_entry->data + fw_entry->size, 0);
  916. +
  917. + if (!orinoco_cached_fw_get(priv, true))
  918. + release_firmware(fw_entry);
  919. + if (ret) {
  920. + dev_err(dev, "Primary firmware download failed\n");
  921. + return ret;
  922. + }
  923. +
  924. + if (!orinoco_cached_fw_get(priv, false)) {
  925. + if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
  926. + dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw);
  927. + return -ENOENT;
  928. + }
  929. + } else
  930. + fw_entry = orinoco_cached_fw_get(priv, false);
  931. +
  932. + /* Load secondary firmware */
  933. + ret = symbol_dl_image(priv, fw, fw_entry->data,
  934. + fw_entry->data + fw_entry->size, 1);
  935. + if (!orinoco_cached_fw_get(priv, false))
  936. + release_firmware(fw_entry);
  937. + if (ret)
  938. + dev_err(dev, "Secondary firmware download failed\n");
  939. +
  940. + return ret;
  941. +}
  942. +
  943. +int orinoco_download(struct orinoco_private *priv)
  944. +{
  945. + int err = 0;
  946. + /* Reload firmware */
  947. + switch (priv->firmware_type) {
  948. + case FIRMWARE_TYPE_AGERE:
  949. + /* case FIRMWARE_TYPE_INTERSIL: */
  950. + err = orinoco_dl_firmware(priv,
  951. + &orinoco_fw[priv->firmware_type], 0);
  952. + break;
  953. +
  954. + case FIRMWARE_TYPE_SYMBOL:
  955. + err = symbol_dl_firmware(priv,
  956. + &orinoco_fw[priv->firmware_type]);
  957. + break;
  958. + case FIRMWARE_TYPE_INTERSIL:
  959. + break;
  960. + }
  961. + /* TODO: if we fail we probably need to reinitialise
  962. + * the driver */
  963. +
  964. + return err;
  965. +}
  966. +
  967. +#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
  968. +void orinoco_cache_fw(struct orinoco_private *priv, int ap)
  969. +{
  970. + const struct firmware *fw_entry = NULL;
  971. + const char *pri_fw;
  972. + const char *fw;
  973. +
  974. + pri_fw = orinoco_fw[priv->firmware_type].pri_fw;
  975. + if (ap)
  976. + fw = orinoco_fw[priv->firmware_type].ap_fw;
  977. + else
  978. + fw = orinoco_fw[priv->firmware_type].sta_fw;
  979. +
  980. + if (pri_fw) {
  981. + if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0)
  982. + priv->cached_pri_fw = fw_entry;
  983. + }
  984. +
  985. + if (fw) {
  986. + if (request_firmware(&fw_entry, fw, priv->dev) == 0)
  987. + priv->cached_fw = fw_entry;
  988. + }
  989. +}
  990. +
  991. +void orinoco_uncache_fw(struct orinoco_private *priv)
  992. +{
  993. + release_firmware(priv->cached_pri_fw);
  994. + release_firmware(priv->cached_fw);
  995. + priv->cached_pri_fw = NULL;
  996. + priv->cached_fw = NULL;
  997. +}
  998. +#endif
  999. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/fw.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/fw.h
  1000. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/fw.h 1970-01-01 01:00:00.000000000 +0100
  1001. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/fw.h 2026-02-16 14:00:36.619256404 +0100
  1002. @@ -0,0 +1,21 @@
  1003. +/* Firmware file reading and download helpers
  1004. + *
  1005. + * See copyright notice in main.c
  1006. + */
  1007. +#ifndef _ORINOCO_FW_H_
  1008. +#define _ORINOCO_FW_H_
  1009. +
  1010. +/* Forward declations */
  1011. +struct orinoco_private;
  1012. +
  1013. +int orinoco_download(struct orinoco_private *priv);
  1014. +
  1015. +#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
  1016. +void orinoco_cache_fw(struct orinoco_private *priv, int ap);
  1017. +void orinoco_uncache_fw(struct orinoco_private *priv);
  1018. +#else
  1019. +#define orinoco_cache_fw(priv, ap) do { } while (0)
  1020. +#define orinoco_uncache_fw(priv) do { } while (0)
  1021. +#endif
  1022. +
  1023. +#endif /* _ORINOCO_FW_H_ */
  1024. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hermes.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/hermes.c
  1025. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hermes.c 1970-01-01 01:00:00.000000000 +0100
  1026. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/hermes.c 2026-02-16 14:00:36.619256404 +0100
  1027. @@ -0,0 +1,778 @@
  1028. +/* hermes.c
  1029. + *
  1030. + * Driver core for the "Hermes" wireless MAC controller, as used in
  1031. + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
  1032. + * work on the hfa3841 and hfa3842 MAC controller chips used in the
  1033. + * Prism II chipsets.
  1034. + *
  1035. + * This is not a complete driver, just low-level access routines for
  1036. + * the MAC controller itself.
  1037. + *
  1038. + * Based on the prism2 driver from Absolute Value Systems' linux-wlan
  1039. + * project, the Linux wvlan_cs driver, Lucent's HCF-Light
  1040. + * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
  1041. + * particular order).
  1042. + *
  1043. + * Copyright (C) 2000, David Gibson, Linuxcare Australia.
  1044. + * (C) Copyright David Gibson, IBM Corp. 2001-2003.
  1045. + *
  1046. + * The contents of this file are subject to the Mozilla Public License
  1047. + * Version 1.1 (the "License"); you may not use this file except in
  1048. + * compliance with the License. You may obtain a copy of the License
  1049. + * at http://www.mozilla.org/MPL/
  1050. + *
  1051. + * Software distributed under the License is distributed on an "AS IS"
  1052. + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  1053. + * the License for the specific language governing rights and
  1054. + * limitations under the License.
  1055. + *
  1056. + * Alternatively, the contents of this file may be used under the
  1057. + * terms of the GNU General Public License version 2 (the "GPL"), in
  1058. + * which case the provisions of the GPL are applicable instead of the
  1059. + * above. If you wish to allow the use of your version of this file
  1060. + * only under the terms of the GPL and not to allow others to use your
  1061. + * version of this file under the MPL, indicate your decision by
  1062. + * deleting the provisions above and replace them with the notice and
  1063. + * other provisions required by the GPL. If you do not delete the
  1064. + * provisions above, a recipient may use your version of this file
  1065. + * under either the MPL or the GPL.
  1066. + */
  1067. +
  1068. +#include <linux/net.h>
  1069. +#include <linux/module.h>
  1070. +#include <linux/kernel.h>
  1071. +#include <linux/delay.h>
  1072. +
  1073. +#include "hermes.h"
  1074. +
  1075. +/* These are maximum timeouts. Most often, card wil react much faster */
  1076. +#define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
  1077. +#define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
  1078. +#define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
  1079. +#define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
  1080. +
  1081. +/*
  1082. + * AUX port access. To unlock the AUX port write the access keys to the
  1083. + * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL
  1084. + * register. Then read it and make sure it's HERMES_AUX_ENABLED.
  1085. + */
  1086. +#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */
  1087. +#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */
  1088. +#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */
  1089. +#define HERMES_AUX_DISABLED 0x0000 /* Auxiliary port is closed */
  1090. +
  1091. +#define HERMES_AUX_PW0 0xFE01
  1092. +#define HERMES_AUX_PW1 0xDC23
  1093. +#define HERMES_AUX_PW2 0xBA45
  1094. +
  1095. +/* HERMES_CMD_DOWNLD */
  1096. +#define HERMES_PROGRAM_DISABLE (0x0000 | HERMES_CMD_DOWNLD)
  1097. +#define HERMES_PROGRAM_ENABLE_VOLATILE (0x0100 | HERMES_CMD_DOWNLD)
  1098. +#define HERMES_PROGRAM_ENABLE_NON_VOLATILE (0x0200 | HERMES_CMD_DOWNLD)
  1099. +#define HERMES_PROGRAM_NON_VOLATILE (0x0300 | HERMES_CMD_DOWNLD)
  1100. +
  1101. +/*
  1102. + * Debugging helpers
  1103. + */
  1104. +
  1105. +#define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %p: " , hw->iobase); \
  1106. + printk(stuff); } while (0)
  1107. +
  1108. +#undef HERMES_DEBUG
  1109. +#ifdef HERMES_DEBUG
  1110. +
  1111. +#define DEBUG(lvl, stuff...) if ((lvl) <= HERMES_DEBUG) DMSG(stuff)
  1112. +
  1113. +#else /* ! HERMES_DEBUG */
  1114. +
  1115. +#define DEBUG(lvl, stuff...) do { } while (0)
  1116. +
  1117. +#endif /* ! HERMES_DEBUG */
  1118. +
  1119. +static const struct hermes_ops hermes_ops_local;
  1120. +
  1121. +/*
  1122. + * Internal functions
  1123. + */
  1124. +
  1125. +/* Issue a command to the chip. Waiting for it to complete is the caller's
  1126. + problem.
  1127. +
  1128. + Returns -EBUSY if the command register is busy, 0 on success.
  1129. +
  1130. + Callable from any context.
  1131. +*/
  1132. +static int hermes_issue_cmd(struct hermes *hw, u16 cmd, u16 param0,
  1133. + u16 param1, u16 param2)
  1134. +{
  1135. + int k = CMD_BUSY_TIMEOUT;
  1136. + u16 reg;
  1137. +
  1138. + /* First wait for the command register to unbusy */
  1139. + reg = hermes_read_regn(hw, CMD);
  1140. + while ((reg & HERMES_CMD_BUSY) && k) {
  1141. + k--;
  1142. + udelay(1);
  1143. + reg = hermes_read_regn(hw, CMD);
  1144. + }
  1145. + if (reg & HERMES_CMD_BUSY)
  1146. + return -EBUSY;
  1147. +
  1148. + hermes_write_regn(hw, PARAM2, param2);
  1149. + hermes_write_regn(hw, PARAM1, param1);
  1150. + hermes_write_regn(hw, PARAM0, param0);
  1151. + hermes_write_regn(hw, CMD, cmd);
  1152. +
  1153. + return 0;
  1154. +}
  1155. +
  1156. +/*
  1157. + * Function definitions
  1158. + */
  1159. +
  1160. +/* For doing cmds that wipe the magic constant in SWSUPPORT0 */
  1161. +static int hermes_doicmd_wait(struct hermes *hw, u16 cmd,
  1162. + u16 parm0, u16 parm1, u16 parm2,
  1163. + struct hermes_response *resp)
  1164. +{
  1165. + int err = 0;
  1166. + int k;
  1167. + u16 status, reg;
  1168. +
  1169. + err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2);
  1170. + if (err)
  1171. + return err;
  1172. +
  1173. + reg = hermes_read_regn(hw, EVSTAT);
  1174. + k = CMD_INIT_TIMEOUT;
  1175. + while ((!(reg & HERMES_EV_CMD)) && k) {
  1176. + k--;
  1177. + udelay(10);
  1178. + reg = hermes_read_regn(hw, EVSTAT);
  1179. + }
  1180. +
  1181. + hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
  1182. +
  1183. + if (!hermes_present(hw)) {
  1184. + DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
  1185. + hw->iobase);
  1186. + err = -ENODEV;
  1187. + goto out;
  1188. + }
  1189. +
  1190. + if (!(reg & HERMES_EV_CMD)) {
  1191. + printk(KERN_ERR "hermes @ %p: "
  1192. + "Timeout waiting for card to reset (reg=0x%04x)!\n",
  1193. + hw->iobase, reg);
  1194. + err = -ETIMEDOUT;
  1195. + goto out;
  1196. + }
  1197. +
  1198. + status = hermes_read_regn(hw, STATUS);
  1199. + if (resp) {
  1200. + resp->status = status;
  1201. + resp->resp0 = hermes_read_regn(hw, RESP0);
  1202. + resp->resp1 = hermes_read_regn(hw, RESP1);
  1203. + resp->resp2 = hermes_read_regn(hw, RESP2);
  1204. + }
  1205. +
  1206. + hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
  1207. +
  1208. + if (status & HERMES_STATUS_RESULT)
  1209. + err = -EIO;
  1210. +out:
  1211. + return err;
  1212. +}
  1213. +
  1214. +void hermes_struct_init(struct hermes *hw, void __iomem *address,
  1215. + int reg_spacing)
  1216. +{
  1217. + hw->iobase = address;
  1218. + hw->reg_spacing = reg_spacing;
  1219. + hw->inten = 0x0;
  1220. + hw->eeprom_pda = false;
  1221. + hw->ops = &hermes_ops_local;
  1222. +}
  1223. +EXPORT_SYMBOL(hermes_struct_init);
  1224. +
  1225. +static int hermes_init(struct hermes *hw)
  1226. +{
  1227. + u16 reg;
  1228. + int err = 0;
  1229. + int k;
  1230. +
  1231. + /* We don't want to be interrupted while resetting the chipset */
  1232. + hw->inten = 0x0;
  1233. + hermes_write_regn(hw, INTEN, 0);
  1234. + hermes_write_regn(hw, EVACK, 0xffff);
  1235. +
  1236. + /* Normally it's a "can't happen" for the command register to
  1237. + be busy when we go to issue a command because we are
  1238. + serializing all commands. However we want to have some
  1239. + chance of resetting the card even if it gets into a stupid
  1240. + state, so we actually wait to see if the command register
  1241. + will unbusy itself here. */
  1242. + k = CMD_BUSY_TIMEOUT;
  1243. + reg = hermes_read_regn(hw, CMD);
  1244. + while (k && (reg & HERMES_CMD_BUSY)) {
  1245. + if (reg == 0xffff) /* Special case - the card has probably been
  1246. + removed, so don't wait for the timeout */
  1247. + return -ENODEV;
  1248. +
  1249. + k--;
  1250. + udelay(1);
  1251. + reg = hermes_read_regn(hw, CMD);
  1252. + }
  1253. +
  1254. + /* No need to explicitly handle the timeout - if we've timed
  1255. + out hermes_issue_cmd() will probably return -EBUSY below */
  1256. +
  1257. + /* According to the documentation, EVSTAT may contain
  1258. + obsolete event occurrence information. We have to acknowledge
  1259. + it by writing EVACK. */
  1260. + reg = hermes_read_regn(hw, EVSTAT);
  1261. + hermes_write_regn(hw, EVACK, reg);
  1262. +
  1263. + /* We don't use hermes_docmd_wait here, because the reset wipes
  1264. + the magic constant in SWSUPPORT0 away, and it gets confused */
  1265. + err = hermes_doicmd_wait(hw, HERMES_CMD_INIT, 0, 0, 0, NULL);
  1266. +
  1267. + return err;
  1268. +}
  1269. +
  1270. +/* Issue a command to the chip, and (busy!) wait for it to
  1271. + * complete.
  1272. + *
  1273. + * Returns:
  1274. + * < 0 on internal error
  1275. + * 0 on success
  1276. + * > 0 on error returned by the firmware
  1277. + *
  1278. + * Callable from any context, but locking is your problem. */
  1279. +static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
  1280. + struct hermes_response *resp)
  1281. +{
  1282. + int err;
  1283. + int k;
  1284. + u16 reg;
  1285. + u16 status;
  1286. +
  1287. + err = hermes_issue_cmd(hw, cmd, parm0, 0, 0);
  1288. + if (err) {
  1289. + if (!hermes_present(hw)) {
  1290. + if (net_ratelimit())
  1291. + printk(KERN_WARNING "hermes @ %p: "
  1292. + "Card removed while issuing command "
  1293. + "0x%04x.\n", hw->iobase, cmd);
  1294. + err = -ENODEV;
  1295. + } else
  1296. + if (net_ratelimit())
  1297. + printk(KERN_ERR "hermes @ %p: "
  1298. + "Error %d issuing command 0x%04x.\n",
  1299. + hw->iobase, err, cmd);
  1300. + goto out;
  1301. + }
  1302. +
  1303. + reg = hermes_read_regn(hw, EVSTAT);
  1304. + k = CMD_COMPL_TIMEOUT;
  1305. + while ((!(reg & HERMES_EV_CMD)) && k) {
  1306. + k--;
  1307. + udelay(10);
  1308. + reg = hermes_read_regn(hw, EVSTAT);
  1309. + }
  1310. +
  1311. + if (!hermes_present(hw)) {
  1312. + printk(KERN_WARNING "hermes @ %p: Card removed "
  1313. + "while waiting for command 0x%04x completion.\n",
  1314. + hw->iobase, cmd);
  1315. + err = -ENODEV;
  1316. + goto out;
  1317. + }
  1318. +
  1319. + if (!(reg & HERMES_EV_CMD)) {
  1320. + printk(KERN_ERR "hermes @ %p: Timeout waiting for "
  1321. + "command 0x%04x completion.\n", hw->iobase, cmd);
  1322. + err = -ETIMEDOUT;
  1323. + goto out;
  1324. + }
  1325. +
  1326. + status = hermes_read_regn(hw, STATUS);
  1327. + if (resp) {
  1328. + resp->status = status;
  1329. + resp->resp0 = hermes_read_regn(hw, RESP0);
  1330. + resp->resp1 = hermes_read_regn(hw, RESP1);
  1331. + resp->resp2 = hermes_read_regn(hw, RESP2);
  1332. + }
  1333. +
  1334. + hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
  1335. +
  1336. + if (status & HERMES_STATUS_RESULT)
  1337. + err = -EIO;
  1338. +
  1339. + out:
  1340. + return err;
  1341. +}
  1342. +
  1343. +static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid)
  1344. +{
  1345. + int err = 0;
  1346. + int k;
  1347. + u16 reg;
  1348. +
  1349. + if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX))
  1350. + return -EINVAL;
  1351. +
  1352. + err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
  1353. + if (err)
  1354. + return err;
  1355. +
  1356. + reg = hermes_read_regn(hw, EVSTAT);
  1357. + k = ALLOC_COMPL_TIMEOUT;
  1358. + while ((!(reg & HERMES_EV_ALLOC)) && k) {
  1359. + k--;
  1360. + udelay(10);
  1361. + reg = hermes_read_regn(hw, EVSTAT);
  1362. + }
  1363. +
  1364. + if (!hermes_present(hw)) {
  1365. + printk(KERN_WARNING "hermes @ %p: "
  1366. + "Card removed waiting for frame allocation.\n",
  1367. + hw->iobase);
  1368. + return -ENODEV;
  1369. + }
  1370. +
  1371. + if (!(reg & HERMES_EV_ALLOC)) {
  1372. + printk(KERN_ERR "hermes @ %p: "
  1373. + "Timeout waiting for frame allocation\n",
  1374. + hw->iobase);
  1375. + return -ETIMEDOUT;
  1376. + }
  1377. +
  1378. + *fid = hermes_read_regn(hw, ALLOCFID);
  1379. + hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
  1380. +
  1381. + return 0;
  1382. +}
  1383. +
  1384. +/* Set up a BAP to read a particular chunk of data from card's internal buffer.
  1385. + *
  1386. + * Returns:
  1387. + * < 0 on internal failure (errno)
  1388. + * 0 on success
  1389. + * > 0 on error
  1390. + * from firmware
  1391. + *
  1392. + * Callable from any context */
  1393. +static int hermes_bap_seek(struct hermes *hw, int bap, u16 id, u16 offset)
  1394. +{
  1395. + int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
  1396. + int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
  1397. + int k;
  1398. + u16 reg;
  1399. +
  1400. + /* Paranoia.. */
  1401. + if ((offset > HERMES_BAP_OFFSET_MAX) || (offset % 2))
  1402. + return -EINVAL;
  1403. +
  1404. + k = HERMES_BAP_BUSY_TIMEOUT;
  1405. + reg = hermes_read_reg(hw, oreg);
  1406. + while ((reg & HERMES_OFFSET_BUSY) && k) {
  1407. + k--;
  1408. + udelay(1);
  1409. + reg = hermes_read_reg(hw, oreg);
  1410. + }
  1411. +
  1412. + if (reg & HERMES_OFFSET_BUSY)
  1413. + return -ETIMEDOUT;
  1414. +
  1415. + /* Now we actually set up the transfer */
  1416. + hermes_write_reg(hw, sreg, id);
  1417. + hermes_write_reg(hw, oreg, offset);
  1418. +
  1419. + /* Wait for the BAP to be ready */
  1420. + k = HERMES_BAP_BUSY_TIMEOUT;
  1421. + reg = hermes_read_reg(hw, oreg);
  1422. + while ((reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
  1423. + k--;
  1424. + udelay(1);
  1425. + reg = hermes_read_reg(hw, oreg);
  1426. + }
  1427. +
  1428. + if (reg != offset) {
  1429. + printk(KERN_ERR "hermes @ %p: BAP%d offset %s: "
  1430. + "reg=0x%x id=0x%x offset=0x%x\n", hw->iobase, bap,
  1431. + (reg & HERMES_OFFSET_BUSY) ? "timeout" : "error",
  1432. + reg, id, offset);
  1433. +
  1434. + if (reg & HERMES_OFFSET_BUSY)
  1435. + return -ETIMEDOUT;
  1436. +
  1437. + return -EIO; /* error or wrong offset */
  1438. + }
  1439. +
  1440. + return 0;
  1441. +}
  1442. +
  1443. +/* Read a block of data from the chip's buffer, via the
  1444. + * BAP. Synchronization/serialization is the caller's problem. len
  1445. + * must be even.
  1446. + *
  1447. + * Returns:
  1448. + * < 0 on internal failure (errno)
  1449. + * 0 on success
  1450. + * > 0 on error from firmware
  1451. + */
  1452. +static int hermes_bap_pread(struct hermes *hw, int bap, void *buf, int len,
  1453. + u16 id, u16 offset)
  1454. +{
  1455. + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
  1456. + int err = 0;
  1457. +
  1458. + if ((len < 0) || (len % 2))
  1459. + return -EINVAL;
  1460. +
  1461. + err = hermes_bap_seek(hw, bap, id, offset);
  1462. + if (err)
  1463. + goto out;
  1464. +
  1465. + /* Actually do the transfer */
  1466. + hermes_read_words(hw, dreg, buf, len / 2);
  1467. +
  1468. + out:
  1469. + return err;
  1470. +}
  1471. +
  1472. +/* Write a block of data to the chip's buffer, via the
  1473. + * BAP. Synchronization/serialization is the caller's problem.
  1474. + *
  1475. + * Returns:
  1476. + * < 0 on internal failure (errno)
  1477. + * 0 on success
  1478. + * > 0 on error from firmware
  1479. + */
  1480. +static int hermes_bap_pwrite(struct hermes *hw, int bap, const void *buf,
  1481. + int len, u16 id, u16 offset)
  1482. +{
  1483. + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
  1484. + int err = 0;
  1485. +
  1486. + if (len < 0)
  1487. + return -EINVAL;
  1488. +
  1489. + err = hermes_bap_seek(hw, bap, id, offset);
  1490. + if (err)
  1491. + goto out;
  1492. +
  1493. + /* Actually do the transfer */
  1494. + hermes_write_bytes(hw, dreg, buf, len);
  1495. +
  1496. + out:
  1497. + return err;
  1498. +}
  1499. +
  1500. +/* Read a Length-Type-Value record from the card.
  1501. + *
  1502. + * If length is NULL, we ignore the length read from the card, and
  1503. + * read the entire buffer regardless. This is useful because some of
  1504. + * the configuration records appear to have incorrect lengths in
  1505. + * practice.
  1506. + *
  1507. + * Callable from user or bh context. */
  1508. +static int hermes_read_ltv(struct hermes *hw, int bap, u16 rid,
  1509. + unsigned bufsize, u16 *length, void *buf)
  1510. +{
  1511. + int err = 0;
  1512. + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
  1513. + u16 rlength, rtype;
  1514. + unsigned nwords;
  1515. +
  1516. + if (bufsize % 2)
  1517. + return -EINVAL;
  1518. +
  1519. + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
  1520. + if (err)
  1521. + return err;
  1522. +
  1523. + err = hermes_bap_seek(hw, bap, rid, 0);
  1524. + if (err)
  1525. + return err;
  1526. +
  1527. + rlength = hermes_read_reg(hw, dreg);
  1528. +
  1529. + if (!rlength)
  1530. + return -ENODATA;
  1531. +
  1532. + rtype = hermes_read_reg(hw, dreg);
  1533. +
  1534. + if (length)
  1535. + *length = rlength;
  1536. +
  1537. + if (rtype != rid)
  1538. + printk(KERN_WARNING "hermes @ %p: %s(): "
  1539. + "rid (0x%04x) does not match type (0x%04x)\n",
  1540. + hw->iobase, __func__, rid, rtype);
  1541. + if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
  1542. + printk(KERN_WARNING "hermes @ %p: "
  1543. + "Truncating LTV record from %d to %d bytes. "
  1544. + "(rid=0x%04x, len=0x%04x)\n", hw->iobase,
  1545. + HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
  1546. +
  1547. + nwords = min((unsigned)rlength - 1, bufsize / 2);
  1548. + hermes_read_words(hw, dreg, buf, nwords);
  1549. +
  1550. + return 0;
  1551. +}
  1552. +
  1553. +static int hermes_write_ltv(struct hermes *hw, int bap, u16 rid,
  1554. + u16 length, const void *value)
  1555. +{
  1556. + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
  1557. + int err = 0;
  1558. + unsigned count;
  1559. +
  1560. + if (length == 0)
  1561. + return -EINVAL;
  1562. +
  1563. + err = hermes_bap_seek(hw, bap, rid, 0);
  1564. + if (err)
  1565. + return err;
  1566. +
  1567. + hermes_write_reg(hw, dreg, length);
  1568. + hermes_write_reg(hw, dreg, rid);
  1569. +
  1570. + count = length - 1;
  1571. +
  1572. + hermes_write_bytes(hw, dreg, value, count << 1);
  1573. +
  1574. + err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
  1575. + rid, NULL);
  1576. +
  1577. + return err;
  1578. +}
  1579. +
  1580. +/*** Hermes AUX control ***/
  1581. +
  1582. +static inline void
  1583. +hermes_aux_setaddr(struct hermes *hw, u32 addr)
  1584. +{
  1585. + hermes_write_reg(hw, HERMES_AUXPAGE, (u16) (addr >> 7));
  1586. + hermes_write_reg(hw, HERMES_AUXOFFSET, (u16) (addr & 0x7F));
  1587. +}
  1588. +
  1589. +static inline int
  1590. +hermes_aux_control(struct hermes *hw, int enabled)
  1591. +{
  1592. + int desired_state = enabled ? HERMES_AUX_ENABLED : HERMES_AUX_DISABLED;
  1593. + int action = enabled ? HERMES_AUX_ENABLE : HERMES_AUX_DISABLE;
  1594. + int i;
  1595. +
  1596. + /* Already open? */
  1597. + if (hermes_read_reg(hw, HERMES_CONTROL) == desired_state)
  1598. + return 0;
  1599. +
  1600. + hermes_write_reg(hw, HERMES_PARAM0, HERMES_AUX_PW0);
  1601. + hermes_write_reg(hw, HERMES_PARAM1, HERMES_AUX_PW1);
  1602. + hermes_write_reg(hw, HERMES_PARAM2, HERMES_AUX_PW2);
  1603. + hermes_write_reg(hw, HERMES_CONTROL, action);
  1604. +
  1605. + for (i = 0; i < 20; i++) {
  1606. + udelay(10);
  1607. + if (hermes_read_reg(hw, HERMES_CONTROL) ==
  1608. + desired_state)
  1609. + return 0;
  1610. + }
  1611. +
  1612. + return -EBUSY;
  1613. +}
  1614. +
  1615. +/*** Hermes programming ***/
  1616. +
  1617. +/* About to start programming data (Hermes I)
  1618. + * offset is the entry point
  1619. + *
  1620. + * Spectrum_cs' Symbol fw does not require this
  1621. + * wl_lkm Agere fw does
  1622. + * Don't know about intersil
  1623. + */
  1624. +static int hermesi_program_init(struct hermes *hw, u32 offset)
  1625. +{
  1626. + int err;
  1627. +
  1628. + /* Disable interrupts?*/
  1629. + /*hw->inten = 0x0;*/
  1630. + /*hermes_write_regn(hw, INTEN, 0);*/
  1631. + /*hermes_set_irqmask(hw, 0);*/
  1632. +
  1633. + /* Acknowledge any outstanding command */
  1634. + hermes_write_regn(hw, EVACK, 0xFFFF);
  1635. +
  1636. + /* Using init_cmd_wait rather than cmd_wait */
  1637. + err = hw->ops->init_cmd_wait(hw,
  1638. + 0x0100 | HERMES_CMD_INIT,
  1639. + 0, 0, 0, NULL);
  1640. + if (err)
  1641. + return err;
  1642. +
  1643. + err = hw->ops->init_cmd_wait(hw,
  1644. + 0x0000 | HERMES_CMD_INIT,
  1645. + 0, 0, 0, NULL);
  1646. + if (err)
  1647. + return err;
  1648. +
  1649. + err = hermes_aux_control(hw, 1);
  1650. + pr_debug("AUX enable returned %d\n", err);
  1651. +
  1652. + if (err)
  1653. + return err;
  1654. +
  1655. + pr_debug("Enabling volatile, EP 0x%08x\n", offset);
  1656. + err = hw->ops->init_cmd_wait(hw,
  1657. + HERMES_PROGRAM_ENABLE_VOLATILE,
  1658. + offset & 0xFFFFu,
  1659. + offset >> 16,
  1660. + 0,
  1661. + NULL);
  1662. + pr_debug("PROGRAM_ENABLE returned %d\n", err);
  1663. +
  1664. + return err;
  1665. +}
  1666. +
  1667. +/* Done programming data (Hermes I)
  1668. + *
  1669. + * Spectrum_cs' Symbol fw does not require this
  1670. + * wl_lkm Agere fw does
  1671. + * Don't know about intersil
  1672. + */
  1673. +static int hermesi_program_end(struct hermes *hw)
  1674. +{
  1675. + struct hermes_response resp;
  1676. + int rc = 0;
  1677. + int err;
  1678. +
  1679. + rc = hw->ops->cmd_wait(hw, HERMES_PROGRAM_DISABLE, 0, &resp);
  1680. +
  1681. + pr_debug("PROGRAM_DISABLE returned %d, "
  1682. + "r0 0x%04x, r1 0x%04x, r2 0x%04x\n",
  1683. + rc, resp.resp0, resp.resp1, resp.resp2);
  1684. +
  1685. + if ((rc == 0) &&
  1686. + ((resp.status & HERMES_STATUS_CMDCODE) != HERMES_CMD_DOWNLD))
  1687. + rc = -EIO;
  1688. +
  1689. + err = hermes_aux_control(hw, 0);
  1690. + pr_debug("AUX disable returned %d\n", err);
  1691. +
  1692. + /* Acknowledge any outstanding command */
  1693. + hermes_write_regn(hw, EVACK, 0xFFFF);
  1694. +
  1695. + /* Reinitialise, ignoring return */
  1696. + (void) hw->ops->init_cmd_wait(hw, 0x0000 | HERMES_CMD_INIT,
  1697. + 0, 0, 0, NULL);
  1698. +
  1699. + return rc ? rc : err;
  1700. +}
  1701. +
  1702. +static int hermes_program_bytes(struct hermes *hw, const char *data,
  1703. + u32 addr, u32 len)
  1704. +{
  1705. + /* wl lkm splits the programming into chunks of 2000 bytes.
  1706. + * This restriction appears to come from USB. The PCMCIA
  1707. + * adapters can program the whole lot in one go */
  1708. + hermes_aux_setaddr(hw, addr);
  1709. + hermes_write_bytes(hw, HERMES_AUXDATA, data, len);
  1710. + return 0;
  1711. +}
  1712. +
  1713. +/* Read PDA from the adapter */
  1714. +static int hermes_read_pda(struct hermes *hw, __le16 *pda, u32 pda_addr,
  1715. + u16 pda_len)
  1716. +{
  1717. + int ret;
  1718. + u16 pda_size;
  1719. + u16 data_len = pda_len;
  1720. + __le16 *data = pda;
  1721. +
  1722. + if (hw->eeprom_pda) {
  1723. + /* PDA of spectrum symbol is in eeprom */
  1724. +
  1725. + /* Issue command to read EEPROM */
  1726. + ret = hw->ops->cmd_wait(hw, HERMES_CMD_READMIF, 0, NULL);
  1727. + if (ret)
  1728. + return ret;
  1729. + } else {
  1730. + /* wl_lkm does not include PDA size in the PDA area.
  1731. + * We will pad the information into pda, so other routines
  1732. + * don't have to be modified */
  1733. + pda[0] = cpu_to_le16(pda_len - 2);
  1734. + /* Includes CFG_PROD_DATA but not itself */
  1735. + pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
  1736. + data_len = pda_len - 4;
  1737. + data = pda + 2;
  1738. + }
  1739. +
  1740. + /* Open auxiliary port */
  1741. + ret = hermes_aux_control(hw, 1);
  1742. + pr_debug("AUX enable returned %d\n", ret);
  1743. + if (ret)
  1744. + return ret;
  1745. +
  1746. + /* Read PDA */
  1747. + hermes_aux_setaddr(hw, pda_addr);
  1748. + hermes_read_words(hw, HERMES_AUXDATA, data, data_len / 2);
  1749. +
  1750. + /* Close aux port */
  1751. + ret = hermes_aux_control(hw, 0);
  1752. + pr_debug("AUX disable returned %d\n", ret);
  1753. +
  1754. + /* Check PDA length */
  1755. + pda_size = le16_to_cpu(pda[0]);
  1756. + pr_debug("Actual PDA length %d, Max allowed %d\n",
  1757. + pda_size, pda_len);
  1758. + if (pda_size > pda_len)
  1759. + return -EINVAL;
  1760. +
  1761. + return 0;
  1762. +}
  1763. +
  1764. +static void hermes_lock_irqsave(spinlock_t *lock,
  1765. + unsigned long *flags) __acquires(lock)
  1766. +{
  1767. + spin_lock_irqsave(lock, *flags);
  1768. +}
  1769. +
  1770. +static void hermes_unlock_irqrestore(spinlock_t *lock,
  1771. + unsigned long *flags) __releases(lock)
  1772. +{
  1773. + spin_unlock_irqrestore(lock, *flags);
  1774. +}
  1775. +
  1776. +static void hermes_lock_irq(spinlock_t *lock) __acquires(lock)
  1777. +{
  1778. + spin_lock_irq(lock);
  1779. +}
  1780. +
  1781. +static void hermes_unlock_irq(spinlock_t *lock) __releases(lock)
  1782. +{
  1783. + spin_unlock_irq(lock);
  1784. +}
  1785. +
  1786. +/* Hermes operations for local buses */
  1787. +static const struct hermes_ops hermes_ops_local = {
  1788. + .init = hermes_init,
  1789. + .cmd_wait = hermes_docmd_wait,
  1790. + .init_cmd_wait = hermes_doicmd_wait,
  1791. + .allocate = hermes_allocate,
  1792. + .read_ltv = hermes_read_ltv,
  1793. + .read_ltv_pr = hermes_read_ltv,
  1794. + .write_ltv = hermes_write_ltv,
  1795. + .bap_pread = hermes_bap_pread,
  1796. + .bap_pwrite = hermes_bap_pwrite,
  1797. + .read_pda = hermes_read_pda,
  1798. + .program_init = hermesi_program_init,
  1799. + .program_end = hermesi_program_end,
  1800. + .program = hermes_program_bytes,
  1801. + .lock_irqsave = hermes_lock_irqsave,
  1802. + .unlock_irqrestore = hermes_unlock_irqrestore,
  1803. + .lock_irq = hermes_lock_irq,
  1804. + .unlock_irq = hermes_unlock_irq,
  1805. +};
  1806. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hermes_dld.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/hermes_dld.c
  1807. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hermes_dld.c 1970-01-01 01:00:00.000000000 +0100
  1808. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/hermes_dld.c 2026-02-16 14:00:36.623256352 +0100
  1809. @@ -0,0 +1,477 @@
  1810. +/*
  1811. + * Hermes download helper.
  1812. + *
  1813. + * This helper:
  1814. + * - is capable of writing to the volatile area of the hermes device
  1815. + * - is currently not capable of writing to non-volatile areas
  1816. + * - provide helpers to identify and update plugin data
  1817. + * - is not capable of interpreting a fw image directly. That is up to
  1818. + * the main card driver.
  1819. + * - deals with Hermes I devices. It can probably be modified to deal
  1820. + * with Hermes II devices
  1821. + *
  1822. + * Copyright (C) 2007, David Kilroy
  1823. + *
  1824. + * Plug data code slightly modified from spectrum_cs driver
  1825. + * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
  1826. + * Portions based on information in wl_lkm_718 Agere driver
  1827. + * COPYRIGHT (C) 2001-2004 by Agere Systems Inc. All Rights Reserved
  1828. + *
  1829. + * The contents of this file are subject to the Mozilla Public License
  1830. + * Version 1.1 (the "License"); you may not use this file except in
  1831. + * compliance with the License. You may obtain a copy of the License
  1832. + * at http://www.mozilla.org/MPL/
  1833. + *
  1834. + * Software distributed under the License is distributed on an "AS IS"
  1835. + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  1836. + * the License for the specific language governing rights and
  1837. + * limitations under the License.
  1838. + *
  1839. + * Alternatively, the contents of this file may be used under the
  1840. + * terms of the GNU General Public License version 2 (the "GPL"), in
  1841. + * which case the provisions of the GPL are applicable instead of the
  1842. + * above. If you wish to allow the use of your version of this file
  1843. + * only under the terms of the GPL and not to allow others to use your
  1844. + * version of this file under the MPL, indicate your decision by
  1845. + * deleting the provisions above and replace them with the notice and
  1846. + * other provisions required by the GPL. If you do not delete the
  1847. + * provisions above, a recipient may use your version of this file
  1848. + * under either the MPL or the GPL.
  1849. + */
  1850. +
  1851. +#include <linux/module.h>
  1852. +#include <linux/delay.h>
  1853. +#include "hermes.h"
  1854. +#include "hermes_dld.h"
  1855. +
  1856. +#define PFX "hermes_dld: "
  1857. +
  1858. +/* End markers used in dblocks */
  1859. +#define PDI_END 0x00000000 /* End of PDA */
  1860. +#define BLOCK_END 0xFFFFFFFF /* Last image block */
  1861. +#define TEXT_END 0x1A /* End of text header */
  1862. +
  1863. +/*
  1864. + * The following structures have little-endian fields denoted by
  1865. + * the leading underscore. Don't access them directly - use inline
  1866. + * functions defined below.
  1867. + */
  1868. +
  1869. +/*
  1870. + * The binary image to be downloaded consists of series of data blocks.
  1871. + * Each block has the following structure.
  1872. + */
  1873. +struct dblock {
  1874. + __le32 addr; /* adapter address where to write the block */
  1875. + __le16 len; /* length of the data only, in bytes */
  1876. + char data[]; /* data to be written */
  1877. +} __packed;
  1878. +
  1879. +/*
  1880. + * Plug Data References are located in the image after the last data
  1881. + * block. They refer to areas in the adapter memory where the plug data
  1882. + * items with matching ID should be written.
  1883. + */
  1884. +struct pdr {
  1885. + __le32 id; /* record ID */
  1886. + __le32 addr; /* adapter address where to write the data */
  1887. + __le32 len; /* expected length of the data, in bytes */
  1888. + char next[]; /* next PDR starts here */
  1889. +} __packed;
  1890. +
  1891. +/*
  1892. + * Plug Data Items are located in the EEPROM read from the adapter by
  1893. + * primary firmware. They refer to the device-specific data that should
  1894. + * be plugged into the secondary firmware.
  1895. + */
  1896. +struct pdi {
  1897. + __le16 len; /* length of ID and data, in words */
  1898. + __le16 id; /* record ID */
  1899. + char data[]; /* plug data */
  1900. +} __packed;
  1901. +
  1902. +/*** FW data block access functions ***/
  1903. +
  1904. +static inline u32
  1905. +dblock_addr(const struct dblock *blk)
  1906. +{
  1907. + return le32_to_cpu(blk->addr);
  1908. +}
  1909. +
  1910. +static inline u32
  1911. +dblock_len(const struct dblock *blk)
  1912. +{
  1913. + return le16_to_cpu(blk->len);
  1914. +}
  1915. +
  1916. +/*** PDR Access functions ***/
  1917. +
  1918. +static inline u32
  1919. +pdr_id(const struct pdr *pdr)
  1920. +{
  1921. + return le32_to_cpu(pdr->id);
  1922. +}
  1923. +
  1924. +static inline u32
  1925. +pdr_addr(const struct pdr *pdr)
  1926. +{
  1927. + return le32_to_cpu(pdr->addr);
  1928. +}
  1929. +
  1930. +static inline u32
  1931. +pdr_len(const struct pdr *pdr)
  1932. +{
  1933. + return le32_to_cpu(pdr->len);
  1934. +}
  1935. +
  1936. +/*** PDI Access functions ***/
  1937. +
  1938. +static inline u32
  1939. +pdi_id(const struct pdi *pdi)
  1940. +{
  1941. + return le16_to_cpu(pdi->id);
  1942. +}
  1943. +
  1944. +/* Return length of the data only, in bytes */
  1945. +static inline u32
  1946. +pdi_len(const struct pdi *pdi)
  1947. +{
  1948. + return 2 * (le16_to_cpu(pdi->len) - 1);
  1949. +}
  1950. +
  1951. +/*** Plug Data Functions ***/
  1952. +
  1953. +/*
  1954. + * Scan PDR for the record with the specified RECORD_ID.
  1955. + * If it's not found, return NULL.
  1956. + */
  1957. +static const struct pdr *
  1958. +hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end)
  1959. +{
  1960. + const struct pdr *pdr = first_pdr;
  1961. +
  1962. + end -= sizeof(struct pdr);
  1963. +
  1964. + while (((void *) pdr <= end) &&
  1965. + (pdr_id(pdr) != PDI_END)) {
  1966. + /*
  1967. + * PDR area is currently not terminated by PDI_END.
  1968. + * It's followed by CRC records, which have the type
  1969. + * field where PDR has length. The type can be 0 or 1.
  1970. + */
  1971. + if (pdr_len(pdr) < 2)
  1972. + return NULL;
  1973. +
  1974. + /* If the record ID matches, we are done */
  1975. + if (pdr_id(pdr) == record_id)
  1976. + return pdr;
  1977. +
  1978. + pdr = (struct pdr *) pdr->next;
  1979. + }
  1980. + return NULL;
  1981. +}
  1982. +
  1983. +/* Scan production data items for a particular entry */
  1984. +static const struct pdi *
  1985. +hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end)
  1986. +{
  1987. + const struct pdi *pdi = first_pdi;
  1988. +
  1989. + end -= sizeof(struct pdi);
  1990. +
  1991. + while (((void *) pdi <= end) &&
  1992. + (pdi_id(pdi) != PDI_END)) {
  1993. +
  1994. + /* If the record ID matches, we are done */
  1995. + if (pdi_id(pdi) == record_id)
  1996. + return pdi;
  1997. +
  1998. + pdi = (struct pdi *) &pdi->data[pdi_len(pdi)];
  1999. + }
  2000. + return NULL;
  2001. +}
  2002. +
  2003. +/* Process one Plug Data Item - find corresponding PDR and plug it */
  2004. +static int
  2005. +hermes_plug_pdi(struct hermes *hw, const struct pdr *first_pdr,
  2006. + const struct pdi *pdi, const void *pdr_end)
  2007. +{
  2008. + const struct pdr *pdr;
  2009. +
  2010. + /* Find the PDR corresponding to this PDI */
  2011. + pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end);
  2012. +
  2013. + /* No match is found, safe to ignore */
  2014. + if (!pdr)
  2015. + return 0;
  2016. +
  2017. + /* Lengths of the data in PDI and PDR must match */
  2018. + if (pdi_len(pdi) != pdr_len(pdr))
  2019. + return -EINVAL;
  2020. +
  2021. + /* do the actual plugging */
  2022. + hw->ops->program(hw, pdi->data, pdr_addr(pdr), pdi_len(pdi));
  2023. +
  2024. + return 0;
  2025. +}
  2026. +
  2027. +/* Parse PDA and write the records into the adapter
  2028. + *
  2029. + * Attempt to write every records that is in the specified pda
  2030. + * which also has a valid production data record for the firmware.
  2031. + */
  2032. +int hermes_apply_pda(struct hermes *hw,
  2033. + const char *first_pdr,
  2034. + const void *pdr_end,
  2035. + const __le16 *pda,
  2036. + const void *pda_end)
  2037. +{
  2038. + int ret;
  2039. + const struct pdi *pdi;
  2040. + const struct pdr *pdr;
  2041. +
  2042. + pdr = (const struct pdr *) first_pdr;
  2043. + pda_end -= sizeof(struct pdi);
  2044. +
  2045. + /* Go through every PDI and plug them into the adapter */
  2046. + pdi = (const struct pdi *) (pda + 2);
  2047. + while (((void *) pdi <= pda_end) &&
  2048. + (pdi_id(pdi) != PDI_END)) {
  2049. + ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end);
  2050. + if (ret)
  2051. + return ret;
  2052. +
  2053. + /* Increment to the next PDI */
  2054. + pdi = (const struct pdi *) &pdi->data[pdi_len(pdi)];
  2055. + }
  2056. + return 0;
  2057. +}
  2058. +
  2059. +/* Identify the total number of bytes in all blocks
  2060. + * including the header data.
  2061. + */
  2062. +size_t
  2063. +hermes_blocks_length(const char *first_block, const void *end)
  2064. +{
  2065. + const struct dblock *blk = (const struct dblock *) first_block;
  2066. + int total_len = 0;
  2067. + int len;
  2068. +
  2069. + end -= sizeof(*blk);
  2070. +
  2071. + /* Skip all blocks to locate Plug Data References
  2072. + * (Spectrum CS) */
  2073. + while (((void *) blk <= end) &&
  2074. + (dblock_addr(blk) != BLOCK_END)) {
  2075. + len = dblock_len(blk);
  2076. + total_len += sizeof(*blk) + len;
  2077. + blk = (struct dblock *) &blk->data[len];
  2078. + }
  2079. +
  2080. + return total_len;
  2081. +}
  2082. +
  2083. +/*** Hermes programming ***/
  2084. +
  2085. +/* Program the data blocks */
  2086. +int hermes_program(struct hermes *hw, const char *first_block, const void *end)
  2087. +{
  2088. + const struct dblock *blk;
  2089. + u32 blkaddr;
  2090. + u32 blklen;
  2091. + int err = 0;
  2092. +
  2093. + blk = (const struct dblock *) first_block;
  2094. +
  2095. + if ((void *) blk > (end - sizeof(*blk)))
  2096. + return -EIO;
  2097. +
  2098. + blkaddr = dblock_addr(blk);
  2099. + blklen = dblock_len(blk);
  2100. +
  2101. + while ((blkaddr != BLOCK_END) &&
  2102. + (((void *) blk + blklen) <= end)) {
  2103. + pr_debug(PFX "Programming block of length %d "
  2104. + "to address 0x%08x\n", blklen, blkaddr);
  2105. +
  2106. + err = hw->ops->program(hw, blk->data, blkaddr, blklen);
  2107. + if (err)
  2108. + break;
  2109. +
  2110. + blk = (const struct dblock *) &blk->data[blklen];
  2111. +
  2112. + if ((void *) blk > (end - sizeof(*blk)))
  2113. + return -EIO;
  2114. +
  2115. + blkaddr = dblock_addr(blk);
  2116. + blklen = dblock_len(blk);
  2117. + }
  2118. + return err;
  2119. +}
  2120. +
  2121. +/*** Default plugging data for Hermes I ***/
  2122. +/* Values from wl_lkm_718/hcf/dhf.c */
  2123. +
  2124. +#define DEFINE_DEFAULT_PDR(pid, length, data) \
  2125. +static const struct { \
  2126. + __le16 len; \
  2127. + __le16 id; \
  2128. + u8 val[length]; \
  2129. +} __packed default_pdr_data_##pid = { \
  2130. + cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
  2131. + sizeof(__le16)) - 1), \
  2132. + cpu_to_le16(pid), \
  2133. + data \
  2134. +}
  2135. +
  2136. +#define DEFAULT_PDR(pid) default_pdr_data_##pid
  2137. +
  2138. +/* HWIF Compatibility */
  2139. +DEFINE_DEFAULT_PDR(0x0005, 10, "\x00\x00\x06\x00\x01\x00\x01\x00\x01\x00");
  2140. +
  2141. +/* PPPPSign */
  2142. +DEFINE_DEFAULT_PDR(0x0108, 4, "\x00\x00\x00\x00");
  2143. +
  2144. +/* PPPPProf */
  2145. +DEFINE_DEFAULT_PDR(0x0109, 10, "\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00");
  2146. +
  2147. +/* Antenna diversity */
  2148. +DEFINE_DEFAULT_PDR(0x0150, 2, "\x00\x3F");
  2149. +
  2150. +/* Modem VCO band Set-up */
  2151. +DEFINE_DEFAULT_PDR(0x0160, 28,
  2152. + "\x00\x00\x00\x00\x00\x00\x00\x00"
  2153. + "\x00\x00\x00\x00\x00\x00\x00\x00"
  2154. + "\x00\x00\x00\x00\x00\x00\x00\x00"
  2155. + "\x00\x00\x00\x00");
  2156. +
  2157. +/* Modem Rx Gain Table Values */
  2158. +DEFINE_DEFAULT_PDR(0x0161, 256,
  2159. + "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
  2160. + "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
  2161. + "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
  2162. + "\x3F\x01\x3F\01\x3F\x01\x3F\x01"
  2163. + "\x3F\x01\x3E\01\x3E\x01\x3D\x01"
  2164. + "\x3D\x01\x3C\01\x3C\x01\x3B\x01"
  2165. + "\x3B\x01\x3A\01\x3A\x01\x39\x01"
  2166. + "\x39\x01\x38\01\x38\x01\x37\x01"
  2167. + "\x37\x01\x36\01\x36\x01\x35\x01"
  2168. + "\x35\x01\x34\01\x34\x01\x33\x01"
  2169. + "\x33\x01\x32\x01\x32\x01\x31\x01"
  2170. + "\x31\x01\x30\x01\x30\x01\x7B\x01"
  2171. + "\x7B\x01\x7A\x01\x7A\x01\x79\x01"
  2172. + "\x79\x01\x78\x01\x78\x01\x77\x01"
  2173. + "\x77\x01\x76\x01\x76\x01\x75\x01"
  2174. + "\x75\x01\x74\x01\x74\x01\x73\x01"
  2175. + "\x73\x01\x72\x01\x72\x01\x71\x01"
  2176. + "\x71\x01\x70\x01\x70\x01\x68\x01"
  2177. + "\x68\x01\x67\x01\x67\x01\x66\x01"
  2178. + "\x66\x01\x65\x01\x65\x01\x57\x01"
  2179. + "\x57\x01\x56\x01\x56\x01\x55\x01"
  2180. + "\x55\x01\x54\x01\x54\x01\x53\x01"
  2181. + "\x53\x01\x52\x01\x52\x01\x51\x01"
  2182. + "\x51\x01\x50\x01\x50\x01\x48\x01"
  2183. + "\x48\x01\x47\x01\x47\x01\x46\x01"
  2184. + "\x46\x01\x45\x01\x45\x01\x44\x01"
  2185. + "\x44\x01\x43\x01\x43\x01\x42\x01"
  2186. + "\x42\x01\x41\x01\x41\x01\x40\x01"
  2187. + "\x40\x01\x40\x01\x40\x01\x40\x01"
  2188. + "\x40\x01\x40\x01\x40\x01\x40\x01"
  2189. + "\x40\x01\x40\x01\x40\x01\x40\x01"
  2190. + "\x40\x01\x40\x01\x40\x01\x40\x01");
  2191. +
  2192. +/* Write PDA according to certain rules.
  2193. + *
  2194. + * For every production data record, look for a previous setting in
  2195. + * the pda, and use that.
  2196. + *
  2197. + * For certain records, use defaults if they are not found in pda.
  2198. + */
  2199. +int hermes_apply_pda_with_defaults(struct hermes *hw,
  2200. + const char *first_pdr,
  2201. + const void *pdr_end,
  2202. + const __le16 *pda,
  2203. + const void *pda_end)
  2204. +{
  2205. + const struct pdr *pdr = (const struct pdr *) first_pdr;
  2206. + const struct pdi *first_pdi = (const struct pdi *) &pda[2];
  2207. + const struct pdi *pdi;
  2208. + const struct pdi *default_pdi = NULL;
  2209. + const struct pdi *outdoor_pdi;
  2210. + int record_id;
  2211. +
  2212. + pdr_end -= sizeof(struct pdr);
  2213. +
  2214. + while (((void *) pdr <= pdr_end) &&
  2215. + (pdr_id(pdr) != PDI_END)) {
  2216. + /*
  2217. + * For spectrum_cs firmwares,
  2218. + * PDR area is currently not terminated by PDI_END.
  2219. + * It's followed by CRC records, which have the type
  2220. + * field where PDR has length. The type can be 0 or 1.
  2221. + */
  2222. + if (pdr_len(pdr) < 2)
  2223. + break;
  2224. + record_id = pdr_id(pdr);
  2225. +
  2226. + pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
  2227. + if (pdi)
  2228. + pr_debug(PFX "Found record 0x%04x at %p\n",
  2229. + record_id, pdi);
  2230. +
  2231. + switch (record_id) {
  2232. + case 0x110: /* Modem REFDAC values */
  2233. + case 0x120: /* Modem VGDAC values */
  2234. + outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1,
  2235. + pda_end);
  2236. + default_pdi = NULL;
  2237. + if (outdoor_pdi) {
  2238. + pdi = outdoor_pdi;
  2239. + pr_debug(PFX
  2240. + "Using outdoor record 0x%04x at %p\n",
  2241. + record_id + 1, pdi);
  2242. + }
  2243. + break;
  2244. + case 0x5: /* HWIF Compatibility */
  2245. + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0005);
  2246. + break;
  2247. + case 0x108: /* PPPPSign */
  2248. + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0108);
  2249. + break;
  2250. + case 0x109: /* PPPPProf */
  2251. + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0109);
  2252. + break;
  2253. + case 0x150: /* Antenna diversity */
  2254. + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0150);
  2255. + break;
  2256. + case 0x160: /* Modem VCO band Set-up */
  2257. + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0160);
  2258. + break;
  2259. + case 0x161: /* Modem Rx Gain Table Values */
  2260. + default_pdi = (struct pdi *) &DEFAULT_PDR(0x0161);
  2261. + break;
  2262. + default:
  2263. + default_pdi = NULL;
  2264. + break;
  2265. + }
  2266. + if (!pdi && default_pdi) {
  2267. + /* Use default */
  2268. + pdi = default_pdi;
  2269. + pr_debug(PFX "Using default record 0x%04x at %p\n",
  2270. + record_id, pdi);
  2271. + }
  2272. +
  2273. + if (pdi) {
  2274. + /* Lengths of the data in PDI and PDR must match */
  2275. + if ((pdi_len(pdi) == pdr_len(pdr)) &&
  2276. + ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
  2277. + /* do the actual plugging */
  2278. + hw->ops->program(hw, pdi->data, pdr_addr(pdr),
  2279. + pdi_len(pdi));
  2280. + }
  2281. + }
  2282. +
  2283. + pdr++;
  2284. + }
  2285. + return 0;
  2286. +}
  2287. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hermes_dld.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/hermes_dld.h
  2288. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hermes_dld.h 1970-01-01 01:00:00.000000000 +0100
  2289. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/hermes_dld.h 2026-02-16 14:00:36.623256352 +0100
  2290. @@ -0,0 +1,52 @@
  2291. +/*
  2292. + * Copyright (C) 2007, David Kilroy
  2293. + *
  2294. + * The contents of this file are subject to the Mozilla Public License
  2295. + * Version 1.1 (the "License"); you may not use this file except in
  2296. + * compliance with the License. You may obtain a copy of the License
  2297. + * at http://www.mozilla.org/MPL/
  2298. + *
  2299. + * Software distributed under the License is distributed on an "AS IS"
  2300. + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  2301. + * the License for the specific language governing rights and
  2302. + * limitations under the License.
  2303. + *
  2304. + * Alternatively, the contents of this file may be used under the
  2305. + * terms of the GNU General Public License version 2 (the "GPL"), in
  2306. + * which case the provisions of the GPL are applicable instead of the
  2307. + * above. If you wish to allow the use of your version of this file
  2308. + * only under the terms of the GPL and not to allow others to use your
  2309. + * version of this file under the MPL, indicate your decision by
  2310. + * deleting the provisions above and replace them with the notice and
  2311. + * other provisions required by the GPL. If you do not delete the
  2312. + * provisions above, a recipient may use your version of this file
  2313. + * under either the MPL or the GPL.
  2314. + */
  2315. +#ifndef _HERMES_DLD_H
  2316. +#define _HERMES_DLD_H
  2317. +
  2318. +#include "hermes.h"
  2319. +
  2320. +int hermesi_program_init(struct hermes *hw, u32 offset);
  2321. +int hermesi_program_end(struct hermes *hw);
  2322. +int hermes_program(struct hermes *hw, const char *first_block, const void *end);
  2323. +
  2324. +int hermes_read_pda(struct hermes *hw,
  2325. + __le16 *pda,
  2326. + u32 pda_addr,
  2327. + u16 pda_len,
  2328. + int use_eeprom);
  2329. +int hermes_apply_pda(struct hermes *hw,
  2330. + const char *first_pdr,
  2331. + const void *pdr_end,
  2332. + const __le16 *pda,
  2333. + const void *pda_end);
  2334. +int hermes_apply_pda_with_defaults(struct hermes *hw,
  2335. + const char *first_pdr,
  2336. + const void *pdr_end,
  2337. + const __le16 *pda,
  2338. + const void *pda_end);
  2339. +
  2340. +size_t hermes_blocks_length(const char *first_block, const void *end);
  2341. +
  2342. +#endif /* _HERMES_DLD_H */
  2343. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hermes.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/hermes.h
  2344. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hermes.h 1970-01-01 01:00:00.000000000 +0100
  2345. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/hermes.h 2026-02-16 14:00:36.623256352 +0100
  2346. @@ -0,0 +1,534 @@
  2347. +/* SPDX-License-Identifier: GPL-2.0-only */
  2348. +/* hermes.h
  2349. + *
  2350. + * Driver core for the "Hermes" wireless MAC controller, as used in
  2351. + * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
  2352. + * work on the hfa3841 and hfa3842 MAC controller chips used in the
  2353. + * Prism I & II chipsets.
  2354. + *
  2355. + * This is not a complete driver, just low-level access routines for
  2356. + * the MAC controller itself.
  2357. + *
  2358. + * Based on the prism2 driver from Absolute Value Systems' linux-wlan
  2359. + * project, the Linux wvlan_cs driver, Lucent's HCF-Light
  2360. + * (wvlan_hcf.c) library, and the NetBSD wireless driver.
  2361. + *
  2362. + * Copyright (C) 2000, David Gibson, Linuxcare Australia.
  2363. + * (C) Copyright David Gibson, IBM Corp. 2001-2003.
  2364. + *
  2365. + * Portions taken from hfa384x.h.
  2366. + * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
  2367. + */
  2368. +
  2369. +#ifndef _HERMES_H
  2370. +#define _HERMES_H
  2371. +
  2372. +/* Notes on locking:
  2373. + *
  2374. + * As a module of low level hardware access routines, there is no
  2375. + * locking. Users of this module should ensure that they serialize
  2376. + * access to the hermes structure, and to the hardware
  2377. +*/
  2378. +
  2379. +#include <linux/if_ether.h>
  2380. +#include <linux/io.h>
  2381. +
  2382. +/*
  2383. + * Limits and constants
  2384. + */
  2385. +#define HERMES_ALLOC_LEN_MIN (4)
  2386. +#define HERMES_ALLOC_LEN_MAX (2400)
  2387. +#define HERMES_LTV_LEN_MAX (34)
  2388. +#define HERMES_BAP_DATALEN_MAX (4096)
  2389. +#define HERMES_BAP_OFFSET_MAX (4096)
  2390. +#define HERMES_PORTID_MAX (7)
  2391. +#define HERMES_NUMPORTS_MAX (HERMES_PORTID_MAX + 1)
  2392. +#define HERMES_PDR_LEN_MAX (260) /* in bytes, from EK */
  2393. +#define HERMES_PDA_RECS_MAX (200) /* a guess */
  2394. +#define HERMES_PDA_LEN_MAX (1024) /* in bytes, from EK */
  2395. +#define HERMES_SCANRESULT_MAX (35)
  2396. +#define HERMES_CHINFORESULT_MAX (8)
  2397. +#define HERMES_MAX_MULTICAST (16)
  2398. +#define HERMES_MAGIC (0x7d1f)
  2399. +
  2400. +/*
  2401. + * Hermes register offsets
  2402. + */
  2403. +#define HERMES_CMD (0x00)
  2404. +#define HERMES_PARAM0 (0x02)
  2405. +#define HERMES_PARAM1 (0x04)
  2406. +#define HERMES_PARAM2 (0x06)
  2407. +#define HERMES_STATUS (0x08)
  2408. +#define HERMES_RESP0 (0x0A)
  2409. +#define HERMES_RESP1 (0x0C)
  2410. +#define HERMES_RESP2 (0x0E)
  2411. +#define HERMES_INFOFID (0x10)
  2412. +#define HERMES_RXFID (0x20)
  2413. +#define HERMES_ALLOCFID (0x22)
  2414. +#define HERMES_TXCOMPLFID (0x24)
  2415. +#define HERMES_SELECT0 (0x18)
  2416. +#define HERMES_OFFSET0 (0x1C)
  2417. +#define HERMES_DATA0 (0x36)
  2418. +#define HERMES_SELECT1 (0x1A)
  2419. +#define HERMES_OFFSET1 (0x1E)
  2420. +#define HERMES_DATA1 (0x38)
  2421. +#define HERMES_EVSTAT (0x30)
  2422. +#define HERMES_INTEN (0x32)
  2423. +#define HERMES_EVACK (0x34)
  2424. +#define HERMES_CONTROL (0x14)
  2425. +#define HERMES_SWSUPPORT0 (0x28)
  2426. +#define HERMES_SWSUPPORT1 (0x2A)
  2427. +#define HERMES_SWSUPPORT2 (0x2C)
  2428. +#define HERMES_AUXPAGE (0x3A)
  2429. +#define HERMES_AUXOFFSET (0x3C)
  2430. +#define HERMES_AUXDATA (0x3E)
  2431. +
  2432. +/*
  2433. + * CMD register bitmasks
  2434. + */
  2435. +#define HERMES_CMD_BUSY (0x8000)
  2436. +#define HERMES_CMD_AINFO (0x7f00)
  2437. +#define HERMES_CMD_MACPORT (0x0700)
  2438. +#define HERMES_CMD_RECL (0x0100)
  2439. +#define HERMES_CMD_WRITE (0x0100)
  2440. +#define HERMES_CMD_PROGMODE (0x0300)
  2441. +#define HERMES_CMD_CMDCODE (0x003f)
  2442. +
  2443. +/*
  2444. + * STATUS register bitmasks
  2445. + */
  2446. +#define HERMES_STATUS_RESULT (0x7f00)
  2447. +#define HERMES_STATUS_CMDCODE (0x003f)
  2448. +
  2449. +/*
  2450. + * OFFSET register bitmasks
  2451. + */
  2452. +#define HERMES_OFFSET_BUSY (0x8000)
  2453. +#define HERMES_OFFSET_ERR (0x4000)
  2454. +#define HERMES_OFFSET_DATAOFF (0x0ffe)
  2455. +
  2456. +/*
  2457. + * Event register bitmasks (INTEN, EVSTAT, EVACK)
  2458. + */
  2459. +#define HERMES_EV_TICK (0x8000)
  2460. +#define HERMES_EV_WTERR (0x4000)
  2461. +#define HERMES_EV_INFDROP (0x2000)
  2462. +#define HERMES_EV_INFO (0x0080)
  2463. +#define HERMES_EV_DTIM (0x0020)
  2464. +#define HERMES_EV_CMD (0x0010)
  2465. +#define HERMES_EV_ALLOC (0x0008)
  2466. +#define HERMES_EV_TXEXC (0x0004)
  2467. +#define HERMES_EV_TX (0x0002)
  2468. +#define HERMES_EV_RX (0x0001)
  2469. +
  2470. +/*
  2471. + * Command codes
  2472. + */
  2473. +/*--- Controller Commands ----------------------------*/
  2474. +#define HERMES_CMD_INIT (0x0000)
  2475. +#define HERMES_CMD_ENABLE (0x0001)
  2476. +#define HERMES_CMD_DISABLE (0x0002)
  2477. +#define HERMES_CMD_DIAG (0x0003)
  2478. +
  2479. +/*--- Buffer Mgmt Commands ---------------------------*/
  2480. +#define HERMES_CMD_ALLOC (0x000A)
  2481. +#define HERMES_CMD_TX (0x000B)
  2482. +
  2483. +/*--- Regulate Commands ------------------------------*/
  2484. +#define HERMES_CMD_NOTIFY (0x0010)
  2485. +#define HERMES_CMD_INQUIRE (0x0011)
  2486. +
  2487. +/*--- Configure Commands -----------------------------*/
  2488. +#define HERMES_CMD_ACCESS (0x0021)
  2489. +#define HERMES_CMD_DOWNLD (0x0022)
  2490. +
  2491. +/*--- Serial I/O Commands ----------------------------*/
  2492. +#define HERMES_CMD_READMIF (0x0030)
  2493. +#define HERMES_CMD_WRITEMIF (0x0031)
  2494. +
  2495. +/*--- Debugging Commands -----------------------------*/
  2496. +#define HERMES_CMD_TEST (0x0038)
  2497. +
  2498. +
  2499. +/* Test command arguments */
  2500. +#define HERMES_TEST_SET_CHANNEL 0x0800
  2501. +#define HERMES_TEST_MONITOR 0x0b00
  2502. +#define HERMES_TEST_STOP 0x0f00
  2503. +
  2504. +/* Authentication algorithms */
  2505. +#define HERMES_AUTH_OPEN 1
  2506. +#define HERMES_AUTH_SHARED_KEY 2
  2507. +
  2508. +/* WEP settings */
  2509. +#define HERMES_WEP_PRIVACY_INVOKED 0x0001
  2510. +#define HERMES_WEP_EXCL_UNENCRYPTED 0x0002
  2511. +#define HERMES_WEP_HOST_ENCRYPT 0x0010
  2512. +#define HERMES_WEP_HOST_DECRYPT 0x0080
  2513. +
  2514. +/* Symbol hostscan options */
  2515. +#define HERMES_HOSTSCAN_SYMBOL_5SEC 0x0001
  2516. +#define HERMES_HOSTSCAN_SYMBOL_ONCE 0x0002
  2517. +#define HERMES_HOSTSCAN_SYMBOL_PASSIVE 0x0040
  2518. +#define HERMES_HOSTSCAN_SYMBOL_BCAST 0x0080
  2519. +
  2520. +/*
  2521. + * Frame structures and constants
  2522. + */
  2523. +
  2524. +#define HERMES_DESCRIPTOR_OFFSET 0
  2525. +#define HERMES_802_11_OFFSET (14)
  2526. +#define HERMES_802_3_OFFSET (14 + 32)
  2527. +#define HERMES_802_2_OFFSET (14 + 32 + 14)
  2528. +#define HERMES_TXCNTL2_OFFSET (HERMES_802_3_OFFSET - 2)
  2529. +
  2530. +#define HERMES_RXSTAT_ERR (0x0003)
  2531. +#define HERMES_RXSTAT_BADCRC (0x0001)
  2532. +#define HERMES_RXSTAT_UNDECRYPTABLE (0x0002)
  2533. +#define HERMES_RXSTAT_MIC (0x0010) /* Frame contains MIC */
  2534. +#define HERMES_RXSTAT_MACPORT (0x0700)
  2535. +#define HERMES_RXSTAT_PCF (0x1000) /* Frame was received in CF period */
  2536. +#define HERMES_RXSTAT_MIC_KEY_ID (0x1800) /* MIC key used */
  2537. +#define HERMES_RXSTAT_MSGTYPE (0xE000)
  2538. +#define HERMES_RXSTAT_1042 (0x2000) /* RFC-1042 frame */
  2539. +#define HERMES_RXSTAT_TUNNEL (0x4000) /* bridge-tunnel encoded frame */
  2540. +#define HERMES_RXSTAT_WMP (0x6000) /* Wavelan-II Management Protocol frame */
  2541. +
  2542. +/* Shift amount for key ID in RXSTAT and TXCTRL */
  2543. +#define HERMES_MIC_KEY_ID_SHIFT 11
  2544. +
  2545. +struct hermes_tx_descriptor {
  2546. + __le16 status;
  2547. + __le16 reserved1;
  2548. + __le16 reserved2;
  2549. + __le32 sw_support;
  2550. + u8 retry_count;
  2551. + u8 tx_rate;
  2552. + __le16 tx_control;
  2553. +} __packed;
  2554. +
  2555. +#define HERMES_TXSTAT_RETRYERR (0x0001)
  2556. +#define HERMES_TXSTAT_AGEDERR (0x0002)
  2557. +#define HERMES_TXSTAT_DISCON (0x0004)
  2558. +#define HERMES_TXSTAT_FORMERR (0x0008)
  2559. +
  2560. +#define HERMES_TXCTRL_TX_OK (0x0002) /* ?? interrupt on Tx complete */
  2561. +#define HERMES_TXCTRL_TX_EX (0x0004) /* ?? interrupt on Tx exception */
  2562. +#define HERMES_TXCTRL_802_11 (0x0008) /* We supply 802.11 header */
  2563. +#define HERMES_TXCTRL_MIC (0x0010) /* 802.3 + TKIP */
  2564. +#define HERMES_TXCTRL_MIC_KEY_ID (0x1800) /* MIC Key ID mask */
  2565. +#define HERMES_TXCTRL_ALT_RTRY (0x0020)
  2566. +
  2567. +/* Inquiry constants and data types */
  2568. +
  2569. +#define HERMES_INQ_TALLIES (0xF100)
  2570. +#define HERMES_INQ_SCAN (0xF101)
  2571. +#define HERMES_INQ_CHANNELINFO (0xF102)
  2572. +#define HERMES_INQ_HOSTSCAN (0xF103)
  2573. +#define HERMES_INQ_HOSTSCAN_SYMBOL (0xF104)
  2574. +#define HERMES_INQ_LINKSTATUS (0xF200)
  2575. +#define HERMES_INQ_SEC_STAT_AGERE (0xF202)
  2576. +
  2577. +struct hermes_tallies_frame {
  2578. + __le16 TxUnicastFrames;
  2579. + __le16 TxMulticastFrames;
  2580. + __le16 TxFragments;
  2581. + __le16 TxUnicastOctets;
  2582. + __le16 TxMulticastOctets;
  2583. + __le16 TxDeferredTransmissions;
  2584. + __le16 TxSingleRetryFrames;
  2585. + __le16 TxMultipleRetryFrames;
  2586. + __le16 TxRetryLimitExceeded;
  2587. + __le16 TxDiscards;
  2588. + __le16 RxUnicastFrames;
  2589. + __le16 RxMulticastFrames;
  2590. + __le16 RxFragments;
  2591. + __le16 RxUnicastOctets;
  2592. + __le16 RxMulticastOctets;
  2593. + __le16 RxFCSErrors;
  2594. + __le16 RxDiscards_NoBuffer;
  2595. + __le16 TxDiscardsWrongSA;
  2596. + __le16 RxWEPUndecryptable;
  2597. + __le16 RxMsgInMsgFragments;
  2598. + __le16 RxMsgInBadMsgFragments;
  2599. + /* Those last are probably not available in very old firmwares */
  2600. + __le16 RxDiscards_WEPICVError;
  2601. + __le16 RxDiscards_WEPExcluded;
  2602. +} __packed;
  2603. +
  2604. +/* Grabbed from wlan-ng - Thanks Mark... - Jean II
  2605. + * This is the result of a scan inquiry command */
  2606. +/* Structure describing info about an Access Point */
  2607. +struct prism2_scan_apinfo {
  2608. + __le16 channel; /* Channel where the AP sits */
  2609. + __le16 noise; /* Noise level */
  2610. + __le16 level; /* Signal level */
  2611. + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
  2612. + __le16 beacon_interv; /* Beacon interval */
  2613. + __le16 capabilities; /* Capabilities */
  2614. + __le16 essid_len; /* ESSID length */
  2615. + u8 essid[32]; /* ESSID of the network */
  2616. + u8 rates[10]; /* Bit rate supported */
  2617. + __le16 proberesp_rate; /* Data rate of the response frame */
  2618. + __le16 atim; /* ATIM window time, Kus (hostscan only) */
  2619. +} __packed;
  2620. +
  2621. +/* Same stuff for the Lucent/Agere card.
  2622. + * Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */
  2623. +struct agere_scan_apinfo {
  2624. + __le16 channel; /* Channel where the AP sits */
  2625. + __le16 noise; /* Noise level */
  2626. + __le16 level; /* Signal level */
  2627. + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
  2628. + __le16 beacon_interv; /* Beacon interval */
  2629. + __le16 capabilities; /* Capabilities */
  2630. + /* bits: 0-ess, 1-ibss, 4-privacy [wep] */
  2631. + __le16 essid_len; /* ESSID length */
  2632. + u8 essid[32]; /* ESSID of the network */
  2633. +} __packed;
  2634. +
  2635. +/* Moustafa: Scan structure for Symbol cards */
  2636. +struct symbol_scan_apinfo {
  2637. + u8 channel; /* Channel where the AP sits */
  2638. + u8 unknown1; /* 8 in 2.9x and 3.9x f/w, 0 otherwise */
  2639. + __le16 noise; /* Noise level */
  2640. + __le16 level; /* Signal level */
  2641. + u8 bssid[ETH_ALEN]; /* MAC address of the Access Point */
  2642. + __le16 beacon_interv; /* Beacon interval */
  2643. + __le16 capabilities; /* Capabilities */
  2644. + /* bits: 0-ess, 1-ibss, 4-privacy [wep] */
  2645. + __le16 essid_len; /* ESSID length */
  2646. + u8 essid[32]; /* ESSID of the network */
  2647. + __le16 rates[5]; /* Bit rate supported */
  2648. + __le16 basic_rates; /* Basic rates bitmask */
  2649. + u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */
  2650. + u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */
  2651. +} __packed;
  2652. +
  2653. +union hermes_scan_info {
  2654. + struct agere_scan_apinfo a;
  2655. + struct prism2_scan_apinfo p;
  2656. + struct symbol_scan_apinfo s;
  2657. +};
  2658. +
  2659. +/* Extended scan struct for HERMES_INQ_CHANNELINFO.
  2660. + * wl_lkm calls this an ACS scan (Automatic Channel Select).
  2661. + * Keep out of union hermes_scan_info because it is much bigger than
  2662. + * the older scan structures. */
  2663. +struct agere_ext_scan_info {
  2664. + __le16 reserved0;
  2665. +
  2666. + u8 noise;
  2667. + u8 level;
  2668. + u8 rx_flow;
  2669. + u8 rate;
  2670. + __le16 reserved1[2];
  2671. +
  2672. + __le16 frame_control;
  2673. + __le16 dur_id;
  2674. + u8 addr1[ETH_ALEN];
  2675. + u8 addr2[ETH_ALEN];
  2676. + u8 bssid[ETH_ALEN];
  2677. + __le16 sequence;
  2678. + u8 addr4[ETH_ALEN];
  2679. +
  2680. + __le16 data_length;
  2681. +
  2682. + /* Next 3 fields do not get filled in. */
  2683. + u8 daddr[ETH_ALEN];
  2684. + u8 saddr[ETH_ALEN];
  2685. + __le16 len_type;
  2686. +
  2687. + __le64 timestamp;
  2688. + __le16 beacon_interval;
  2689. + __le16 capabilities;
  2690. + u8 data[];
  2691. +} __packed;
  2692. +
  2693. +#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
  2694. +#define HERMES_LINKSTATUS_CONNECTED (0x0001)
  2695. +#define HERMES_LINKSTATUS_DISCONNECTED (0x0002)
  2696. +#define HERMES_LINKSTATUS_AP_CHANGE (0x0003)
  2697. +#define HERMES_LINKSTATUS_AP_OUT_OF_RANGE (0x0004)
  2698. +#define HERMES_LINKSTATUS_AP_IN_RANGE (0x0005)
  2699. +#define HERMES_LINKSTATUS_ASSOC_FAILED (0x0006)
  2700. +
  2701. +struct hermes_linkstatus {
  2702. + __le16 linkstatus; /* Link status */
  2703. +} __packed;
  2704. +
  2705. +struct hermes_response {
  2706. + u16 status, resp0, resp1, resp2;
  2707. +};
  2708. +
  2709. +/* "ID" structure - used for ESSID and station nickname */
  2710. +struct hermes_idstring {
  2711. + __le16 len;
  2712. + __le16 val[16];
  2713. +} __packed;
  2714. +
  2715. +struct hermes_multicast {
  2716. + u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
  2717. +} __packed;
  2718. +
  2719. +/* Timeouts */
  2720. +#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
  2721. +
  2722. +struct hermes;
  2723. +
  2724. +/* Functions to access hardware */
  2725. +struct hermes_ops {
  2726. + int (*init)(struct hermes *hw);
  2727. + int (*cmd_wait)(struct hermes *hw, u16 cmd, u16 parm0,
  2728. + struct hermes_response *resp);
  2729. + int (*init_cmd_wait)(struct hermes *hw, u16 cmd,
  2730. + u16 parm0, u16 parm1, u16 parm2,
  2731. + struct hermes_response *resp);
  2732. + int (*allocate)(struct hermes *hw, u16 size, u16 *fid);
  2733. + int (*read_ltv)(struct hermes *hw, int bap, u16 rid, unsigned buflen,
  2734. + u16 *length, void *buf);
  2735. + int (*read_ltv_pr)(struct hermes *hw, int bap, u16 rid,
  2736. + unsigned buflen, u16 *length, void *buf);
  2737. + int (*write_ltv)(struct hermes *hw, int bap, u16 rid,
  2738. + u16 length, const void *value);
  2739. + int (*bap_pread)(struct hermes *hw, int bap, void *buf, int len,
  2740. + u16 id, u16 offset);
  2741. + int (*bap_pwrite)(struct hermes *hw, int bap, const void *buf,
  2742. + int len, u16 id, u16 offset);
  2743. + int (*read_pda)(struct hermes *hw, __le16 *pda,
  2744. + u32 pda_addr, u16 pda_len);
  2745. + int (*program_init)(struct hermes *hw, u32 entry_point);
  2746. + int (*program_end)(struct hermes *hw);
  2747. + int (*program)(struct hermes *hw, const char *buf,
  2748. + u32 addr, u32 len);
  2749. + void (*lock_irqsave)(spinlock_t *lock, unsigned long *flags);
  2750. + void (*unlock_irqrestore)(spinlock_t *lock, unsigned long *flags);
  2751. + void (*lock_irq)(spinlock_t *lock);
  2752. + void (*unlock_irq)(spinlock_t *lock);
  2753. +};
  2754. +
  2755. +/* Basic control structure */
  2756. +struct hermes {
  2757. + void __iomem *iobase;
  2758. + int reg_spacing;
  2759. +#define HERMES_16BIT_REGSPACING 0
  2760. +#define HERMES_32BIT_REGSPACING 1
  2761. + u16 inten; /* Which interrupts should be enabled? */
  2762. + bool eeprom_pda;
  2763. + const struct hermes_ops *ops;
  2764. + void *priv;
  2765. +};
  2766. +
  2767. +/* Register access convenience macros */
  2768. +#define hermes_read_reg(hw, off) \
  2769. + (ioread16((hw)->iobase + ((off) << (hw)->reg_spacing)))
  2770. +#define hermes_write_reg(hw, off, val) \
  2771. + (iowrite16((val), (hw)->iobase + ((off) << (hw)->reg_spacing)))
  2772. +#define hermes_read_regn(hw, name) hermes_read_reg((hw), HERMES_##name)
  2773. +#define hermes_write_regn(hw, name, val) \
  2774. + hermes_write_reg((hw), HERMES_##name, (val))
  2775. +
  2776. +/* Function prototypes */
  2777. +void hermes_struct_init(struct hermes *hw, void __iomem *address,
  2778. + int reg_spacing);
  2779. +
  2780. +/* Inline functions */
  2781. +
  2782. +static inline int hermes_present(struct hermes *hw)
  2783. +{
  2784. + return hermes_read_regn(hw, SWSUPPORT0) == HERMES_MAGIC;
  2785. +}
  2786. +
  2787. +static inline void hermes_set_irqmask(struct hermes *hw, u16 events)
  2788. +{
  2789. + hw->inten = events;
  2790. + hermes_write_regn(hw, INTEN, events);
  2791. +}
  2792. +
  2793. +static inline int hermes_enable_port(struct hermes *hw, int port)
  2794. +{
  2795. + return hw->ops->cmd_wait(hw, HERMES_CMD_ENABLE | (port << 8),
  2796. + 0, NULL);
  2797. +}
  2798. +
  2799. +static inline int hermes_disable_port(struct hermes *hw, int port)
  2800. +{
  2801. + return hw->ops->cmd_wait(hw, HERMES_CMD_DISABLE | (port << 8),
  2802. + 0, NULL);
  2803. +}
  2804. +
  2805. +/* Initiate an INQUIRE command (tallies or scan). The result will come as an
  2806. + * information frame in __orinoco_ev_info() */
  2807. +static inline int hermes_inquire(struct hermes *hw, u16 rid)
  2808. +{
  2809. + return hw->ops->cmd_wait(hw, HERMES_CMD_INQUIRE, rid, NULL);
  2810. +}
  2811. +
  2812. +#define HERMES_BYTES_TO_RECLEN(n) ((((n) + 1) / 2) + 1)
  2813. +#define HERMES_RECLEN_TO_BYTES(n) (((n) - 1) * 2)
  2814. +
  2815. +/* Note that for the next two, the count is in 16-bit words, not bytes */
  2816. +static inline void hermes_read_words(struct hermes *hw, int off,
  2817. + void *buf, unsigned count)
  2818. +{
  2819. + off = off << hw->reg_spacing;
  2820. + ioread16_rep(hw->iobase + off, buf, count);
  2821. +}
  2822. +
  2823. +static inline void hermes_write_bytes(struct hermes *hw, int off,
  2824. + const char *buf, unsigned count)
  2825. +{
  2826. + off = off << hw->reg_spacing;
  2827. + iowrite16_rep(hw->iobase + off, buf, count >> 1);
  2828. + if (unlikely(count & 1))
  2829. + iowrite8(buf[count - 1], hw->iobase + off);
  2830. +}
  2831. +
  2832. +static inline void hermes_clear_words(struct hermes *hw, int off,
  2833. + unsigned count)
  2834. +{
  2835. + unsigned i;
  2836. +
  2837. + off = off << hw->reg_spacing;
  2838. +
  2839. + for (i = 0; i < count; i++)
  2840. + iowrite16(0, hw->iobase + off);
  2841. +}
  2842. +
  2843. +#define HERMES_READ_RECORD(hw, bap, rid, buf) \
  2844. + (hw->ops->read_ltv((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
  2845. +#define HERMES_READ_RECORD_PR(hw, bap, rid, buf) \
  2846. + (hw->ops->read_ltv_pr((hw), (bap), (rid), sizeof(*buf), NULL, (buf)))
  2847. +#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
  2848. + (hw->ops->write_ltv((hw), (bap), (rid), \
  2849. + HERMES_BYTES_TO_RECLEN(sizeof(*buf)), (buf)))
  2850. +
  2851. +static inline int hermes_read_wordrec(struct hermes *hw, int bap, u16 rid,
  2852. + u16 *word)
  2853. +{
  2854. + __le16 rec;
  2855. + int err;
  2856. +
  2857. + err = HERMES_READ_RECORD(hw, bap, rid, &rec);
  2858. + *word = le16_to_cpu(rec);
  2859. + return err;
  2860. +}
  2861. +
  2862. +static inline int hermes_read_wordrec_pr(struct hermes *hw, int bap, u16 rid,
  2863. + u16 *word)
  2864. +{
  2865. + __le16 rec;
  2866. + int err;
  2867. +
  2868. + err = HERMES_READ_RECORD_PR(hw, bap, rid, &rec);
  2869. + *word = le16_to_cpu(rec);
  2870. + return err;
  2871. +}
  2872. +
  2873. +static inline int hermes_write_wordrec(struct hermes *hw, int bap, u16 rid,
  2874. + u16 word)
  2875. +{
  2876. + __le16 rec = cpu_to_le16(word);
  2877. + return HERMES_WRITE_RECORD(hw, bap, rid, &rec);
  2878. +}
  2879. +
  2880. +#endif /* _HERMES_H */
  2881. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hermes_rid.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/hermes_rid.h
  2882. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hermes_rid.h 1970-01-01 01:00:00.000000000 +0100
  2883. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/hermes_rid.h 2026-02-16 14:00:36.623256352 +0100
  2884. @@ -0,0 +1,165 @@
  2885. +#ifndef _HERMES_RID_H
  2886. +#define _HERMES_RID_H
  2887. +
  2888. +/*
  2889. + * Configuration RIDs
  2890. + */
  2891. +#define HERMES_RID_CNFPORTTYPE 0xFC00
  2892. +#define HERMES_RID_CNFOWNMACADDR 0xFC01
  2893. +#define HERMES_RID_CNFDESIREDSSID 0xFC02
  2894. +#define HERMES_RID_CNFOWNCHANNEL 0xFC03
  2895. +#define HERMES_RID_CNFOWNSSID 0xFC04
  2896. +#define HERMES_RID_CNFOWNATIMWINDOW 0xFC05
  2897. +#define HERMES_RID_CNFSYSTEMSCALE 0xFC06
  2898. +#define HERMES_RID_CNFMAXDATALEN 0xFC07
  2899. +#define HERMES_RID_CNFWDSADDRESS 0xFC08
  2900. +#define HERMES_RID_CNFPMENABLED 0xFC09
  2901. +#define HERMES_RID_CNFPMEPS 0xFC0A
  2902. +#define HERMES_RID_CNFMULTICASTRECEIVE 0xFC0B
  2903. +#define HERMES_RID_CNFMAXSLEEPDURATION 0xFC0C
  2904. +#define HERMES_RID_CNFPMHOLDOVERDURATION 0xFC0D
  2905. +#define HERMES_RID_CNFOWNNAME 0xFC0E
  2906. +#define HERMES_RID_CNFOWNDTIMPERIOD 0xFC10
  2907. +#define HERMES_RID_CNFWDSADDRESS1 0xFC11
  2908. +#define HERMES_RID_CNFWDSADDRESS2 0xFC12
  2909. +#define HERMES_RID_CNFWDSADDRESS3 0xFC13
  2910. +#define HERMES_RID_CNFWDSADDRESS4 0xFC14
  2911. +#define HERMES_RID_CNFWDSADDRESS5 0xFC15
  2912. +#define HERMES_RID_CNFWDSADDRESS6 0xFC16
  2913. +#define HERMES_RID_CNFMULTICASTPMBUFFERING 0xFC17
  2914. +#define HERMES_RID_CNFWEPENABLED_AGERE 0xFC20
  2915. +#define HERMES_RID_CNFAUTHENTICATION_AGERE 0xFC21
  2916. +#define HERMES_RID_CNFMANDATORYBSSID_SYMBOL 0xFC21
  2917. +#define HERMES_RID_CNFDROPUNENCRYPTED 0xFC22
  2918. +#define HERMES_RID_CNFWEPDEFAULTKEYID 0xFC23
  2919. +#define HERMES_RID_CNFDEFAULTKEY0 0xFC24
  2920. +#define HERMES_RID_CNFDEFAULTKEY1 0xFC25
  2921. +#define HERMES_RID_CNFMWOROBUST_AGERE 0xFC25
  2922. +#define HERMES_RID_CNFDEFAULTKEY2 0xFC26
  2923. +#define HERMES_RID_CNFDEFAULTKEY3 0xFC27
  2924. +#define HERMES_RID_CNFWEPFLAGS_INTERSIL 0xFC28
  2925. +#define HERMES_RID_CNFWEPKEYMAPPINGTABLE 0xFC29
  2926. +#define HERMES_RID_CNFAUTHENTICATION 0xFC2A
  2927. +#define HERMES_RID_CNFMAXASSOCSTA 0xFC2B
  2928. +#define HERMES_RID_CNFKEYLENGTH_SYMBOL 0xFC2B
  2929. +#define HERMES_RID_CNFTXCONTROL 0xFC2C
  2930. +#define HERMES_RID_CNFROAMINGMODE 0xFC2D
  2931. +#define HERMES_RID_CNFHOSTAUTHENTICATION 0xFC2E
  2932. +#define HERMES_RID_CNFRCVCRCERROR 0xFC30
  2933. +#define HERMES_RID_CNFMMLIFE 0xFC31
  2934. +#define HERMES_RID_CNFALTRETRYCOUNT 0xFC32
  2935. +#define HERMES_RID_CNFBEACONINT 0xFC33
  2936. +#define HERMES_RID_CNFAPPCFINFO 0xFC34
  2937. +#define HERMES_RID_CNFSTAPCFINFO 0xFC35
  2938. +#define HERMES_RID_CNFPRIORITYQUSAGE 0xFC37
  2939. +#define HERMES_RID_CNFTIMCTRL 0xFC40
  2940. +#define HERMES_RID_CNFTHIRTY2TALLY 0xFC42
  2941. +#define HERMES_RID_CNFENHSECURITY 0xFC43
  2942. +#define HERMES_RID_CNFGROUPADDRESSES 0xFC80
  2943. +#define HERMES_RID_CNFCREATEIBSS 0xFC81
  2944. +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD 0xFC82
  2945. +#define HERMES_RID_CNFRTSTHRESHOLD 0xFC83
  2946. +#define HERMES_RID_CNFTXRATECONTROL 0xFC84
  2947. +#define HERMES_RID_CNFPROMISCUOUSMODE 0xFC85
  2948. +#define HERMES_RID_CNFBASICRATES_SYMBOL 0xFC8A
  2949. +#define HERMES_RID_CNFPREAMBLE_SYMBOL 0xFC8C
  2950. +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD0 0xFC90
  2951. +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD1 0xFC91
  2952. +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD2 0xFC92
  2953. +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD3 0xFC93
  2954. +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD4 0xFC94
  2955. +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD5 0xFC95
  2956. +#define HERMES_RID_CNFFRAGMENTATIONTHRESHOLD6 0xFC96
  2957. +#define HERMES_RID_CNFRTSTHRESHOLD0 0xFC97
  2958. +#define HERMES_RID_CNFRTSTHRESHOLD1 0xFC98
  2959. +#define HERMES_RID_CNFRTSTHRESHOLD2 0xFC99
  2960. +#define HERMES_RID_CNFRTSTHRESHOLD3 0xFC9A
  2961. +#define HERMES_RID_CNFRTSTHRESHOLD4 0xFC9B
  2962. +#define HERMES_RID_CNFRTSTHRESHOLD5 0xFC9C
  2963. +#define HERMES_RID_CNFRTSTHRESHOLD6 0xFC9D
  2964. +#define HERMES_RID_CNFHOSTSCAN_SYMBOL 0xFCAB
  2965. +#define HERMES_RID_CNFSHORTPREAMBLE 0xFCB0
  2966. +#define HERMES_RID_CNFWEPKEYS_AGERE 0xFCB0
  2967. +#define HERMES_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1
  2968. +#define HERMES_RID_CNFTXKEY_AGERE 0xFCB1
  2969. +#define HERMES_RID_CNFAUTHENTICATIONRSPTO 0xFCB2
  2970. +#define HERMES_RID_CNFSCANSSID_AGERE 0xFCB2
  2971. +#define HERMES_RID_CNFBASICRATES 0xFCB3
  2972. +#define HERMES_RID_CNFSUPPORTEDRATES 0xFCB4
  2973. +#define HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE 0xFCB4
  2974. +#define HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE 0xFCB5
  2975. +#define HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE 0xFCB6
  2976. +#define HERMES_RID_CNFADDMAPPEDTKIPKEY_AGERE 0xFCB7
  2977. +#define HERMES_RID_CNFREMMAPPEDTKIPKEY_AGERE 0xFCB8
  2978. +#define HERMES_RID_CNFSETWPACAPABILITIES_AGERE 0xFCB9
  2979. +#define HERMES_RID_CNFCACHEDPMKADDRESS 0xFCBA
  2980. +#define HERMES_RID_CNFREMOVEPMKADDRESS 0xFCBB
  2981. +#define HERMES_RID_CNFSCANCHANNELS2GHZ 0xFCC2
  2982. +#define HERMES_RID_CNFDISASSOCIATE 0xFCC8
  2983. +#define HERMES_RID_CNFTICKTIME 0xFCE0
  2984. +#define HERMES_RID_CNFSCANREQUEST 0xFCE1
  2985. +#define HERMES_RID_CNFJOINREQUEST 0xFCE2
  2986. +#define HERMES_RID_CNFAUTHENTICATESTATION 0xFCE3
  2987. +#define HERMES_RID_CNFCHANNELINFOREQUEST 0xFCE4
  2988. +#define HERMES_RID_CNFHOSTSCAN 0xFCE5
  2989. +
  2990. +/*
  2991. + * Information RIDs
  2992. + */
  2993. +#define HERMES_RID_MAXLOADTIME 0xFD00
  2994. +#define HERMES_RID_DOWNLOADBUFFER 0xFD01
  2995. +#define HERMES_RID_PRIID 0xFD02
  2996. +#define HERMES_RID_PRISUPRANGE 0xFD03
  2997. +#define HERMES_RID_CFIACTRANGES 0xFD04
  2998. +#define HERMES_RID_NICSERNUM 0xFD0A
  2999. +#define HERMES_RID_NICID 0xFD0B
  3000. +#define HERMES_RID_MFISUPRANGE 0xFD0C
  3001. +#define HERMES_RID_CFISUPRANGE 0xFD0D
  3002. +#define HERMES_RID_CHANNELLIST 0xFD10
  3003. +#define HERMES_RID_REGULATORYDOMAINS 0xFD11
  3004. +#define HERMES_RID_TEMPTYPE 0xFD12
  3005. +#define HERMES_RID_CIS 0xFD13
  3006. +#define HERMES_RID_STAID 0xFD20
  3007. +#define HERMES_RID_STASUPRANGE 0xFD21
  3008. +#define HERMES_RID_MFIACTRANGES 0xFD22
  3009. +#define HERMES_RID_CFIACTRANGES2 0xFD23
  3010. +#define HERMES_RID_SECONDARYVERSION_SYMBOL 0xFD24
  3011. +#define HERMES_RID_PORTSTATUS 0xFD40
  3012. +#define HERMES_RID_CURRENTSSID 0xFD41
  3013. +#define HERMES_RID_CURRENTBSSID 0xFD42
  3014. +#define HERMES_RID_COMMSQUALITY 0xFD43
  3015. +#define HERMES_RID_CURRENTTXRATE 0xFD44
  3016. +#define HERMES_RID_CURRENTBEACONINTERVAL 0xFD45
  3017. +#define HERMES_RID_CURRENTSCALETHRESHOLDS 0xFD46
  3018. +#define HERMES_RID_PROTOCOLRSPTIME 0xFD47
  3019. +#define HERMES_RID_SHORTRETRYLIMIT 0xFD48
  3020. +#define HERMES_RID_LONGRETRYLIMIT 0xFD49
  3021. +#define HERMES_RID_MAXTRANSMITLIFETIME 0xFD4A
  3022. +#define HERMES_RID_MAXRECEIVELIFETIME 0xFD4B
  3023. +#define HERMES_RID_CFPOLLABLE 0xFD4C
  3024. +#define HERMES_RID_AUTHENTICATIONALGORITHMS 0xFD4D
  3025. +#define HERMES_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F
  3026. +#define HERMES_RID_DBMCOMMSQUALITY_INTERSIL 0xFD51
  3027. +#define HERMES_RID_CURRENTTXRATE1 0xFD80
  3028. +#define HERMES_RID_CURRENTTXRATE2 0xFD81
  3029. +#define HERMES_RID_CURRENTTXRATE3 0xFD82
  3030. +#define HERMES_RID_CURRENTTXRATE4 0xFD83
  3031. +#define HERMES_RID_CURRENTTXRATE5 0xFD84
  3032. +#define HERMES_RID_CURRENTTXRATE6 0xFD85
  3033. +#define HERMES_RID_OWNMACADDR 0xFD86
  3034. +#define HERMES_RID_SCANRESULTSTABLE 0xFD88
  3035. +#define HERMES_RID_CURRENT_COUNTRY_INFO 0xFD89
  3036. +#define HERMES_RID_CURRENT_WPA_IE 0xFD8A
  3037. +#define HERMES_RID_CURRENT_TKIP_IV 0xFD8B
  3038. +#define HERMES_RID_CURRENT_ASSOC_REQ_INFO 0xFD8C
  3039. +#define HERMES_RID_CURRENT_ASSOC_RESP_INFO 0xFD8D
  3040. +#define HERMES_RID_TXQUEUEEMPTY 0xFD91
  3041. +#define HERMES_RID_PHYTYPE 0xFDC0
  3042. +#define HERMES_RID_CURRENTCHANNEL 0xFDC1
  3043. +#define HERMES_RID_CURRENTPOWERSTATE 0xFDC2
  3044. +#define HERMES_RID_CCAMODE 0xFDC3
  3045. +#define HERMES_RID_SUPPORTEDDATARATES 0xFDC6
  3046. +#define HERMES_RID_BUILDSEQ 0xFFFE
  3047. +#define HERMES_RID_FWID 0xFFFF
  3048. +
  3049. +#endif
  3050. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hw.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/hw.c
  3051. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hw.c 1970-01-01 01:00:00.000000000 +0100
  3052. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/hw.c 2026-02-16 14:00:36.623256352 +0100
  3053. @@ -0,0 +1,1362 @@
  3054. +/* Encapsulate basic setting changes and retrieval on Hermes hardware
  3055. + *
  3056. + * See copyright notice in main.c
  3057. + */
  3058. +#include <linux/kernel.h>
  3059. +#include <linux/device.h>
  3060. +#include <linux/if_arp.h>
  3061. +#include <linux/ieee80211.h>
  3062. +#include <linux/wireless.h>
  3063. +#include <net/cfg80211.h>
  3064. +#include "hermes.h"
  3065. +#include "hermes_rid.h"
  3066. +#include "orinoco.h"
  3067. +
  3068. +#include "hw.h"
  3069. +
  3070. +#define SYMBOL_MAX_VER_LEN (14)
  3071. +
  3072. +/* Symbol firmware has a bug allocating buffers larger than this */
  3073. +#define TX_NICBUF_SIZE_BUG 1585
  3074. +
  3075. +/********************************************************************/
  3076. +/* Data tables */
  3077. +/********************************************************************/
  3078. +
  3079. +/* This tables gives the actual meanings of the bitrate IDs returned
  3080. + * by the firmware. */
  3081. +static const struct {
  3082. + int bitrate; /* in 100s of kilobits */
  3083. + int automatic;
  3084. + u16 agere_txratectrl;
  3085. + u16 intersil_txratectrl;
  3086. +} bitrate_table[] = {
  3087. + {110, 1, 3, 15}, /* Entry 0 is the default */
  3088. + {10, 0, 1, 1},
  3089. + {10, 1, 1, 1},
  3090. + {20, 0, 2, 2},
  3091. + {20, 1, 6, 3},
  3092. + {55, 0, 4, 4},
  3093. + {55, 1, 7, 7},
  3094. + {110, 0, 5, 8},
  3095. +};
  3096. +#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
  3097. +
  3098. +/* Firmware version encoding */
  3099. +struct comp_id {
  3100. + u16 id, variant, major, minor;
  3101. +} __packed;
  3102. +
  3103. +static inline enum fwtype determine_firmware_type(struct comp_id *nic_id)
  3104. +{
  3105. + if (nic_id->id < 0x8000)
  3106. + return FIRMWARE_TYPE_AGERE;
  3107. + else if (nic_id->id == 0x8000 && nic_id->major == 0)
  3108. + return FIRMWARE_TYPE_SYMBOL;
  3109. + else
  3110. + return FIRMWARE_TYPE_INTERSIL;
  3111. +}
  3112. +
  3113. +/* Set priv->firmware type, determine firmware properties
  3114. + * This function can be called before we have registerred with netdev,
  3115. + * so all errors go out with dev_* rather than printk
  3116. + *
  3117. + * If non-NULL stores a firmware description in fw_name.
  3118. + * If non-NULL stores a HW version in hw_ver
  3119. + *
  3120. + * These are output via generic cfg80211 ethtool support.
  3121. + */
  3122. +int determine_fw_capabilities(struct orinoco_private *priv,
  3123. + char *fw_name, size_t fw_name_len,
  3124. + u32 *hw_ver)
  3125. +{
  3126. + struct device *dev = priv->dev;
  3127. + struct hermes *hw = &priv->hw;
  3128. + int err;
  3129. + struct comp_id nic_id, sta_id;
  3130. + unsigned int firmver;
  3131. + char tmp[SYMBOL_MAX_VER_LEN + 1] __attribute__((aligned(2)));
  3132. +
  3133. + /* Get the hardware version */
  3134. + err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
  3135. + if (err) {
  3136. + dev_err(dev, "Cannot read hardware identity: error %d\n",
  3137. + err);
  3138. + return err;
  3139. + }
  3140. +
  3141. + le16_to_cpus(&nic_id.id);
  3142. + le16_to_cpus(&nic_id.variant);
  3143. + le16_to_cpus(&nic_id.major);
  3144. + le16_to_cpus(&nic_id.minor);
  3145. + dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
  3146. + nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
  3147. +
  3148. + if (hw_ver)
  3149. + *hw_ver = (((nic_id.id & 0xff) << 24) |
  3150. + ((nic_id.variant & 0xff) << 16) |
  3151. + ((nic_id.major & 0xff) << 8) |
  3152. + (nic_id.minor & 0xff));
  3153. +
  3154. + priv->firmware_type = determine_firmware_type(&nic_id);
  3155. +
  3156. + /* Get the firmware version */
  3157. + err = HERMES_READ_RECORD_PR(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
  3158. + if (err) {
  3159. + dev_err(dev, "Cannot read station identity: error %d\n",
  3160. + err);
  3161. + return err;
  3162. + }
  3163. +
  3164. + le16_to_cpus(&sta_id.id);
  3165. + le16_to_cpus(&sta_id.variant);
  3166. + le16_to_cpus(&sta_id.major);
  3167. + le16_to_cpus(&sta_id.minor);
  3168. + dev_info(dev, "Station identity %04x:%04x:%04x:%04x\n",
  3169. + sta_id.id, sta_id.variant, sta_id.major, sta_id.minor);
  3170. +
  3171. + switch (sta_id.id) {
  3172. + case 0x15:
  3173. + dev_err(dev, "Primary firmware is active\n");
  3174. + return -ENODEV;
  3175. + case 0x14b:
  3176. + dev_err(dev, "Tertiary firmware is active\n");
  3177. + return -ENODEV;
  3178. + case 0x1f: /* Intersil, Agere, Symbol Spectrum24 */
  3179. + case 0x21: /* Symbol Spectrum24 Trilogy */
  3180. + break;
  3181. + default:
  3182. + dev_notice(dev, "Unknown station ID, please report\n");
  3183. + break;
  3184. + }
  3185. +
  3186. + /* Default capabilities */
  3187. + priv->has_sensitivity = 1;
  3188. + priv->has_mwo = 0;
  3189. + priv->has_preamble = 0;
  3190. + priv->has_port3 = 1;
  3191. + priv->has_ibss = 1;
  3192. + priv->has_wep = 0;
  3193. + priv->has_big_wep = 0;
  3194. + priv->has_alt_txcntl = 0;
  3195. + priv->has_ext_scan = 0;
  3196. + priv->has_wpa = 0;
  3197. + priv->do_fw_download = 0;
  3198. +
  3199. + /* Determine capabilities from the firmware version */
  3200. + switch (priv->firmware_type) {
  3201. + case FIRMWARE_TYPE_AGERE:
  3202. + /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
  3203. + ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
  3204. + if (fw_name)
  3205. + snprintf(fw_name, fw_name_len, "Lucent/Agere %d.%02d",
  3206. + sta_id.major, sta_id.minor);
  3207. +
  3208. + firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
  3209. +
  3210. + priv->has_ibss = (firmver >= 0x60006);
  3211. + priv->has_wep = (firmver >= 0x40020);
  3212. + priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
  3213. + Gold cards from the others? */
  3214. + priv->has_mwo = (firmver >= 0x60000);
  3215. + priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
  3216. + priv->ibss_port = 1;
  3217. + priv->has_hostscan = (firmver >= 0x8000a);
  3218. + priv->do_fw_download = 1;
  3219. + priv->broken_monitor = (firmver >= 0x80000);
  3220. + priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
  3221. + priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
  3222. + priv->has_wpa = (firmver >= 0x9002a);
  3223. + /* Tested with Agere firmware :
  3224. + * 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
  3225. + * Tested CableTron firmware : 4.32 => Anton */
  3226. + break;
  3227. + case FIRMWARE_TYPE_SYMBOL:
  3228. + /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
  3229. + /* Intel MAC : 00:02:B3:* */
  3230. + /* 3Com MAC : 00:50:DA:* */
  3231. + memset(tmp, 0, sizeof(tmp));
  3232. + /* Get the Symbol firmware version */
  3233. + err = hw->ops->read_ltv_pr(hw, USER_BAP,
  3234. + HERMES_RID_SECONDARYVERSION_SYMBOL,
  3235. + SYMBOL_MAX_VER_LEN, NULL, &tmp);
  3236. + if (err) {
  3237. + dev_warn(dev, "Error %d reading Symbol firmware info. "
  3238. + "Wildly guessing capabilities...\n", err);
  3239. + firmver = 0;
  3240. + tmp[0] = '\0';
  3241. + } else {
  3242. + /* The firmware revision is a string, the format is
  3243. + * something like : "V2.20-01".
  3244. + * Quick and dirty parsing... - Jean II
  3245. + */
  3246. + firmver = ((tmp[1] - '0') << 16)
  3247. + | ((tmp[3] - '0') << 12)
  3248. + | ((tmp[4] - '0') << 8)
  3249. + | ((tmp[6] - '0') << 4)
  3250. + | (tmp[7] - '0');
  3251. +
  3252. + tmp[SYMBOL_MAX_VER_LEN] = '\0';
  3253. + }
  3254. +
  3255. + if (fw_name)
  3256. + snprintf(fw_name, fw_name_len, "Symbol %s", tmp);
  3257. +
  3258. + priv->has_ibss = (firmver >= 0x20000);
  3259. + priv->has_wep = (firmver >= 0x15012);
  3260. + priv->has_big_wep = (firmver >= 0x20000);
  3261. + priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
  3262. + (firmver >= 0x29000 && firmver < 0x30000) ||
  3263. + firmver >= 0x31000;
  3264. + priv->has_preamble = (firmver >= 0x20000);
  3265. + priv->ibss_port = 4;
  3266. +
  3267. + /* Symbol firmware is found on various cards, but
  3268. + * there has been no attempt to check firmware
  3269. + * download on non-spectrum_cs based cards.
  3270. + *
  3271. + * Given that the Agere firmware download works
  3272. + * differently, we should avoid doing a firmware
  3273. + * download with the Symbol algorithm on non-spectrum
  3274. + * cards.
  3275. + *
  3276. + * For now we can identify a spectrum_cs based card
  3277. + * because it has a firmware reset function.
  3278. + */
  3279. + priv->do_fw_download = (priv->stop_fw != NULL);
  3280. +
  3281. + priv->broken_disableport = (firmver == 0x25013) ||
  3282. + (firmver >= 0x30000 && firmver <= 0x31000);
  3283. + priv->has_hostscan = (firmver >= 0x31001) ||
  3284. + (firmver >= 0x29057 && firmver < 0x30000);
  3285. + /* Tested with Intel firmware : 0x20015 => Jean II */
  3286. + /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
  3287. + break;
  3288. + case FIRMWARE_TYPE_INTERSIL:
  3289. + /* D-Link, Linksys, Adtron, ZoomAir, and many others...
  3290. + * Samsung, Compaq 100/200 and Proxim are slightly
  3291. + * different and less well tested */
  3292. + /* D-Link MAC : 00:40:05:* */
  3293. + /* Addtron MAC : 00:90:D1:* */
  3294. + if (fw_name)
  3295. + snprintf(fw_name, fw_name_len, "Intersil %d.%d.%d",
  3296. + sta_id.major, sta_id.minor, sta_id.variant);
  3297. +
  3298. + firmver = ((unsigned long)sta_id.major << 16) |
  3299. + ((unsigned long)sta_id.minor << 8) | sta_id.variant;
  3300. +
  3301. + priv->has_ibss = (firmver >= 0x000700); /* FIXME */
  3302. + priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
  3303. + priv->has_pm = (firmver >= 0x000700);
  3304. + priv->has_hostscan = (firmver >= 0x010301);
  3305. +
  3306. + if (firmver >= 0x000800)
  3307. + priv->ibss_port = 0;
  3308. + else {
  3309. + dev_notice(dev, "Intersil firmware earlier than v0.8.x"
  3310. + " - several features not supported\n");
  3311. + priv->ibss_port = 1;
  3312. + }
  3313. + break;
  3314. + }
  3315. + if (fw_name)
  3316. + dev_info(dev, "Firmware determined as %s\n", fw_name);
  3317. +
  3318. +#ifndef CONFIG_HERMES_PRISM
  3319. + if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
  3320. + dev_err(dev, "Support for Prism chipset is not enabled\n");
  3321. + return -ENODEV;
  3322. + }
  3323. +#endif
  3324. +
  3325. + return 0;
  3326. +}
  3327. +
  3328. +/* Read settings from EEPROM into our private structure.
  3329. + * MAC address gets dropped into callers buffer
  3330. + * Can be called before netdev registration.
  3331. + */
  3332. +int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
  3333. +{
  3334. + struct device *dev = priv->dev;
  3335. + struct hermes_idstring nickbuf;
  3336. + struct hermes *hw = &priv->hw;
  3337. + int len;
  3338. + int err;
  3339. + u16 reclen;
  3340. +
  3341. + /* Get the MAC address */
  3342. + err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
  3343. + ETH_ALEN, NULL, dev_addr);
  3344. + if (err) {
  3345. + dev_warn(dev, "Failed to read MAC address!\n");
  3346. + goto out;
  3347. + }
  3348. +
  3349. + dev_dbg(dev, "MAC address %pM\n", dev_addr);
  3350. +
  3351. + /* Get the station name */
  3352. + err = hw->ops->read_ltv_pr(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
  3353. + sizeof(nickbuf), &reclen, &nickbuf);
  3354. + if (err) {
  3355. + dev_err(dev, "failed to read station name\n");
  3356. + goto out;
  3357. + }
  3358. + if (nickbuf.len)
  3359. + len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
  3360. + else
  3361. + len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
  3362. + memcpy(priv->nick, &nickbuf.val, len);
  3363. + priv->nick[len] = '\0';
  3364. +
  3365. + dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
  3366. +
  3367. + /* Get allowed channels */
  3368. + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CHANNELLIST,
  3369. + &priv->channel_mask);
  3370. + if (err) {
  3371. + dev_err(dev, "Failed to read channel list!\n");
  3372. + goto out;
  3373. + }
  3374. +
  3375. + /* Get initial AP density */
  3376. + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
  3377. + &priv->ap_density);
  3378. + if (err || priv->ap_density < 1 || priv->ap_density > 3)
  3379. + priv->has_sensitivity = 0;
  3380. +
  3381. + /* Get initial RTS threshold */
  3382. + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
  3383. + &priv->rts_thresh);
  3384. + if (err) {
  3385. + dev_err(dev, "Failed to read RTS threshold!\n");
  3386. + goto out;
  3387. + }
  3388. +
  3389. + /* Get initial fragmentation settings */
  3390. + if (priv->has_mwo)
  3391. + err = hermes_read_wordrec_pr(hw, USER_BAP,
  3392. + HERMES_RID_CNFMWOROBUST_AGERE,
  3393. + &priv->mwo_robust);
  3394. + else
  3395. + err = hermes_read_wordrec_pr(hw, USER_BAP,
  3396. + HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
  3397. + &priv->frag_thresh);
  3398. + if (err) {
  3399. + dev_err(dev, "Failed to read fragmentation settings!\n");
  3400. + goto out;
  3401. + }
  3402. +
  3403. + /* Power management setup */
  3404. + if (priv->has_pm) {
  3405. + priv->pm_on = 0;
  3406. + priv->pm_mcast = 1;
  3407. + err = hermes_read_wordrec_pr(hw, USER_BAP,
  3408. + HERMES_RID_CNFMAXSLEEPDURATION,
  3409. + &priv->pm_period);
  3410. + if (err) {
  3411. + dev_err(dev, "Failed to read power management "
  3412. + "period!\n");
  3413. + goto out;
  3414. + }
  3415. + err = hermes_read_wordrec_pr(hw, USER_BAP,
  3416. + HERMES_RID_CNFPMHOLDOVERDURATION,
  3417. + &priv->pm_timeout);
  3418. + if (err) {
  3419. + dev_err(dev, "Failed to read power management "
  3420. + "timeout!\n");
  3421. + goto out;
  3422. + }
  3423. + }
  3424. +
  3425. + /* Preamble setup */
  3426. + if (priv->has_preamble) {
  3427. + err = hermes_read_wordrec_pr(hw, USER_BAP,
  3428. + HERMES_RID_CNFPREAMBLE_SYMBOL,
  3429. + &priv->preamble);
  3430. + if (err) {
  3431. + dev_err(dev, "Failed to read preamble setup\n");
  3432. + goto out;
  3433. + }
  3434. + }
  3435. +
  3436. + /* Retry settings */
  3437. + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_SHORTRETRYLIMIT,
  3438. + &priv->short_retry_limit);
  3439. + if (err) {
  3440. + dev_err(dev, "Failed to read short retry limit\n");
  3441. + goto out;
  3442. + }
  3443. +
  3444. + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_LONGRETRYLIMIT,
  3445. + &priv->long_retry_limit);
  3446. + if (err) {
  3447. + dev_err(dev, "Failed to read long retry limit\n");
  3448. + goto out;
  3449. + }
  3450. +
  3451. + err = hermes_read_wordrec_pr(hw, USER_BAP, HERMES_RID_MAXTRANSMITLIFETIME,
  3452. + &priv->retry_lifetime);
  3453. + if (err) {
  3454. + dev_err(dev, "Failed to read max retry lifetime\n");
  3455. + goto out;
  3456. + }
  3457. +
  3458. +out:
  3459. + return err;
  3460. +}
  3461. +
  3462. +/* Can be called before netdev registration */
  3463. +int orinoco_hw_allocate_fid(struct orinoco_private *priv)
  3464. +{
  3465. + struct device *dev = priv->dev;
  3466. + struct hermes *hw = &priv->hw;
  3467. + int err;
  3468. +
  3469. + err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
  3470. + if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
  3471. + /* Try workaround for old Symbol firmware bug */
  3472. + priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
  3473. + err = hw->ops->allocate(hw, priv->nicbuf_size, &priv->txfid);
  3474. +
  3475. + dev_warn(dev, "Firmware ALLOC bug detected "
  3476. + "(old Symbol firmware?). Work around %s\n",
  3477. + err ? "failed!" : "ok.");
  3478. + }
  3479. +
  3480. + return err;
  3481. +}
  3482. +
  3483. +int orinoco_get_bitratemode(int bitrate, int automatic)
  3484. +{
  3485. + int ratemode = -1;
  3486. + int i;
  3487. +
  3488. + if ((bitrate != 10) && (bitrate != 20) &&
  3489. + (bitrate != 55) && (bitrate != 110))
  3490. + return ratemode;
  3491. +
  3492. + for (i = 0; i < BITRATE_TABLE_SIZE; i++) {
  3493. + if ((bitrate_table[i].bitrate == bitrate) &&
  3494. + (bitrate_table[i].automatic == automatic)) {
  3495. + ratemode = i;
  3496. + break;
  3497. + }
  3498. + }
  3499. + return ratemode;
  3500. +}
  3501. +
  3502. +void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
  3503. +{
  3504. + BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE));
  3505. +
  3506. + *bitrate = bitrate_table[ratemode].bitrate * 100000;
  3507. + *automatic = bitrate_table[ratemode].automatic;
  3508. +}
  3509. +
  3510. +int orinoco_hw_program_rids(struct orinoco_private *priv)
  3511. +{
  3512. + struct net_device *dev = priv->ndev;
  3513. + struct wireless_dev *wdev = netdev_priv(dev);
  3514. + struct hermes *hw = &priv->hw;
  3515. + int err;
  3516. + struct hermes_idstring idbuf;
  3517. +
  3518. + /* Set the MAC address */
  3519. + err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
  3520. + HERMES_BYTES_TO_RECLEN(ETH_ALEN),
  3521. + dev->dev_addr);
  3522. + if (err) {
  3523. + printk(KERN_ERR "%s: Error %d setting MAC address\n",
  3524. + dev->name, err);
  3525. + return err;
  3526. + }
  3527. +
  3528. + /* Set up the link mode */
  3529. + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
  3530. + priv->port_type);
  3531. + if (err) {
  3532. + printk(KERN_ERR "%s: Error %d setting port type\n",
  3533. + dev->name, err);
  3534. + return err;
  3535. + }
  3536. + /* Set the channel/frequency */
  3537. + if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) {
  3538. + err = hermes_write_wordrec(hw, USER_BAP,
  3539. + HERMES_RID_CNFOWNCHANNEL,
  3540. + priv->channel);
  3541. + if (err) {
  3542. + printk(KERN_ERR "%s: Error %d setting channel %d\n",
  3543. + dev->name, err, priv->channel);
  3544. + return err;
  3545. + }
  3546. + }
  3547. +
  3548. + if (priv->has_ibss) {
  3549. + u16 createibss;
  3550. +
  3551. + if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
  3552. + printk(KERN_WARNING "%s: This firmware requires an "
  3553. + "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
  3554. + /* With wvlan_cs, in this case, we would crash.
  3555. + * hopefully, this driver will behave better...
  3556. + * Jean II */
  3557. + createibss = 0;
  3558. + } else {
  3559. + createibss = priv->createibss;
  3560. + }
  3561. +
  3562. + err = hermes_write_wordrec(hw, USER_BAP,
  3563. + HERMES_RID_CNFCREATEIBSS,
  3564. + createibss);
  3565. + if (err) {
  3566. + printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
  3567. + dev->name, err);
  3568. + return err;
  3569. + }
  3570. + }
  3571. +
  3572. + /* Set the desired BSSID */
  3573. + err = __orinoco_hw_set_wap(priv);
  3574. + if (err) {
  3575. + printk(KERN_ERR "%s: Error %d setting AP address\n",
  3576. + dev->name, err);
  3577. + return err;
  3578. + }
  3579. +
  3580. + /* Set the desired ESSID */
  3581. + idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
  3582. + memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
  3583. + /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
  3584. + err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
  3585. + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2),
  3586. + &idbuf);
  3587. + if (err) {
  3588. + printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
  3589. + dev->name, err);
  3590. + return err;
  3591. + }
  3592. + err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
  3593. + HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid) + 2),
  3594. + &idbuf);
  3595. + if (err) {
  3596. + printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
  3597. + dev->name, err);
  3598. + return err;
  3599. + }
  3600. +
  3601. + /* Set the station name */
  3602. + idbuf.len = cpu_to_le16(strlen(priv->nick));
  3603. + memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
  3604. + err = hw->ops->write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
  3605. + HERMES_BYTES_TO_RECLEN(strlen(priv->nick) + 2),
  3606. + &idbuf);
  3607. + if (err) {
  3608. + printk(KERN_ERR "%s: Error %d setting nickname\n",
  3609. + dev->name, err);
  3610. + return err;
  3611. + }
  3612. +
  3613. + /* Set AP density */
  3614. + if (priv->has_sensitivity) {
  3615. + err = hermes_write_wordrec(hw, USER_BAP,
  3616. + HERMES_RID_CNFSYSTEMSCALE,
  3617. + priv->ap_density);
  3618. + if (err) {
  3619. + printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
  3620. + "Disabling sensitivity control\n",
  3621. + dev->name, err);
  3622. +
  3623. + priv->has_sensitivity = 0;
  3624. + }
  3625. + }
  3626. +
  3627. + /* Set RTS threshold */
  3628. + err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
  3629. + priv->rts_thresh);
  3630. + if (err) {
  3631. + printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
  3632. + dev->name, err);
  3633. + return err;
  3634. + }
  3635. +
  3636. + /* Set fragmentation threshold or MWO robustness */
  3637. + if (priv->has_mwo)
  3638. + err = hermes_write_wordrec(hw, USER_BAP,
  3639. + HERMES_RID_CNFMWOROBUST_AGERE,
  3640. + priv->mwo_robust);
  3641. + else
  3642. + err = hermes_write_wordrec(hw, USER_BAP,
  3643. + HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
  3644. + priv->frag_thresh);
  3645. + if (err) {
  3646. + printk(KERN_ERR "%s: Error %d setting fragmentation\n",
  3647. + dev->name, err);
  3648. + return err;
  3649. + }
  3650. +
  3651. + /* Set bitrate */
  3652. + err = __orinoco_hw_set_bitrate(priv);
  3653. + if (err) {
  3654. + printk(KERN_ERR "%s: Error %d setting bitrate\n",
  3655. + dev->name, err);
  3656. + return err;
  3657. + }
  3658. +
  3659. + /* Set power management */
  3660. + if (priv->has_pm) {
  3661. + err = hermes_write_wordrec(hw, USER_BAP,
  3662. + HERMES_RID_CNFPMENABLED,
  3663. + priv->pm_on);
  3664. + if (err) {
  3665. + printk(KERN_ERR "%s: Error %d setting up PM\n",
  3666. + dev->name, err);
  3667. + return err;
  3668. + }
  3669. +
  3670. + err = hermes_write_wordrec(hw, USER_BAP,
  3671. + HERMES_RID_CNFMULTICASTRECEIVE,
  3672. + priv->pm_mcast);
  3673. + if (err) {
  3674. + printk(KERN_ERR "%s: Error %d setting up PM\n",
  3675. + dev->name, err);
  3676. + return err;
  3677. + }
  3678. + err = hermes_write_wordrec(hw, USER_BAP,
  3679. + HERMES_RID_CNFMAXSLEEPDURATION,
  3680. + priv->pm_period);
  3681. + if (err) {
  3682. + printk(KERN_ERR "%s: Error %d setting up PM\n",
  3683. + dev->name, err);
  3684. + return err;
  3685. + }
  3686. + err = hermes_write_wordrec(hw, USER_BAP,
  3687. + HERMES_RID_CNFPMHOLDOVERDURATION,
  3688. + priv->pm_timeout);
  3689. + if (err) {
  3690. + printk(KERN_ERR "%s: Error %d setting up PM\n",
  3691. + dev->name, err);
  3692. + return err;
  3693. + }
  3694. + }
  3695. +
  3696. + /* Set preamble - only for Symbol so far... */
  3697. + if (priv->has_preamble) {
  3698. + err = hermes_write_wordrec(hw, USER_BAP,
  3699. + HERMES_RID_CNFPREAMBLE_SYMBOL,
  3700. + priv->preamble);
  3701. + if (err) {
  3702. + printk(KERN_ERR "%s: Error %d setting preamble\n",
  3703. + dev->name, err);
  3704. + return err;
  3705. + }
  3706. + }
  3707. +
  3708. + /* Set up encryption */
  3709. + if (priv->has_wep || priv->has_wpa) {
  3710. + err = __orinoco_hw_setup_enc(priv);
  3711. + if (err) {
  3712. + printk(KERN_ERR "%s: Error %d activating encryption\n",
  3713. + dev->name, err);
  3714. + return err;
  3715. + }
  3716. + }
  3717. +
  3718. + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
  3719. + /* Enable monitor mode */
  3720. + dev->type = ARPHRD_IEEE80211;
  3721. + err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
  3722. + HERMES_TEST_MONITOR, 0, NULL);
  3723. + } else {
  3724. + /* Disable monitor mode */
  3725. + dev->type = ARPHRD_ETHER;
  3726. + err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
  3727. + HERMES_TEST_STOP, 0, NULL);
  3728. + }
  3729. + if (err)
  3730. + return err;
  3731. +
  3732. + /* Reset promiscuity / multicast*/
  3733. + priv->promiscuous = 0;
  3734. + priv->mc_count = 0;
  3735. +
  3736. + /* Record mode change */
  3737. + wdev->iftype = priv->iw_mode;
  3738. +
  3739. + return 0;
  3740. +}
  3741. +
  3742. +/* Get tsc from the firmware */
  3743. +int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
  3744. +{
  3745. + struct hermes *hw = &priv->hw;
  3746. + int err = 0;
  3747. + u8 tsc_arr[4][ORINOCO_SEQ_LEN];
  3748. +
  3749. + if ((key < 0) || (key >= 4))
  3750. + return -EINVAL;
  3751. +
  3752. + err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
  3753. + sizeof(tsc_arr), NULL, &tsc_arr);
  3754. + if (!err)
  3755. + memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
  3756. +
  3757. + return err;
  3758. +}
  3759. +
  3760. +int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
  3761. +{
  3762. + struct hermes *hw = &priv->hw;
  3763. + int ratemode = priv->bitratemode;
  3764. + int err = 0;
  3765. +
  3766. + if (ratemode >= BITRATE_TABLE_SIZE) {
  3767. + printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
  3768. + priv->ndev->name, ratemode);
  3769. + return -EINVAL;
  3770. + }
  3771. +
  3772. + switch (priv->firmware_type) {
  3773. + case FIRMWARE_TYPE_AGERE:
  3774. + err = hermes_write_wordrec(hw, USER_BAP,
  3775. + HERMES_RID_CNFTXRATECONTROL,
  3776. + bitrate_table[ratemode].agere_txratectrl);
  3777. + break;
  3778. + case FIRMWARE_TYPE_INTERSIL:
  3779. + case FIRMWARE_TYPE_SYMBOL:
  3780. + err = hermes_write_wordrec(hw, USER_BAP,
  3781. + HERMES_RID_CNFTXRATECONTROL,
  3782. + bitrate_table[ratemode].intersil_txratectrl);
  3783. + break;
  3784. + default:
  3785. + BUG();
  3786. + }
  3787. +
  3788. + return err;
  3789. +}
  3790. +
  3791. +int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate)
  3792. +{
  3793. + struct hermes *hw = &priv->hw;
  3794. + int i;
  3795. + int err = 0;
  3796. + u16 val;
  3797. +
  3798. + err = hermes_read_wordrec(hw, USER_BAP,
  3799. + HERMES_RID_CURRENTTXRATE, &val);
  3800. + if (err)
  3801. + return err;
  3802. +
  3803. + switch (priv->firmware_type) {
  3804. + case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
  3805. + /* Note : in Lucent firmware, the return value of
  3806. + * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
  3807. + * and therefore is totally different from the
  3808. + * encoding of HERMES_RID_CNFTXRATECONTROL.
  3809. + * Don't forget that 6Mb/s is really 5.5Mb/s */
  3810. + if (val == 6)
  3811. + *bitrate = 5500000;
  3812. + else
  3813. + *bitrate = val * 1000000;
  3814. + break;
  3815. + case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
  3816. + case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
  3817. + for (i = 0; i < BITRATE_TABLE_SIZE; i++)
  3818. + if (bitrate_table[i].intersil_txratectrl == val) {
  3819. + *bitrate = bitrate_table[i].bitrate * 100000;
  3820. + break;
  3821. + }
  3822. +
  3823. + if (i >= BITRATE_TABLE_SIZE) {
  3824. + printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
  3825. + priv->ndev->name, val);
  3826. + err = -EIO;
  3827. + }
  3828. +
  3829. + break;
  3830. + default:
  3831. + BUG();
  3832. + }
  3833. +
  3834. + return err;
  3835. +}
  3836. +
  3837. +/* Set fixed AP address */
  3838. +int __orinoco_hw_set_wap(struct orinoco_private *priv)
  3839. +{
  3840. + int roaming_flag;
  3841. + int err = 0;
  3842. + struct hermes *hw = &priv->hw;
  3843. +
  3844. + switch (priv->firmware_type) {
  3845. + case FIRMWARE_TYPE_AGERE:
  3846. + /* not supported */
  3847. + break;
  3848. + case FIRMWARE_TYPE_INTERSIL:
  3849. + if (priv->bssid_fixed)
  3850. + roaming_flag = 2;
  3851. + else
  3852. + roaming_flag = 1;
  3853. +
  3854. + err = hermes_write_wordrec(hw, USER_BAP,
  3855. + HERMES_RID_CNFROAMINGMODE,
  3856. + roaming_flag);
  3857. + break;
  3858. + case FIRMWARE_TYPE_SYMBOL:
  3859. + err = HERMES_WRITE_RECORD(hw, USER_BAP,
  3860. + HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
  3861. + &priv->desired_bssid);
  3862. + break;
  3863. + }
  3864. + return err;
  3865. +}
  3866. +
  3867. +/* Change the WEP keys and/or the current keys. Can be called
  3868. + * either from __orinoco_hw_setup_enc() or directly from
  3869. + * orinoco_ioctl_setiwencode(). In the later case the association
  3870. + * with the AP is not broken (if the firmware can handle it),
  3871. + * which is needed for 802.1x implementations. */
  3872. +int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
  3873. +{
  3874. + struct hermes *hw = &priv->hw;
  3875. + int err = 0;
  3876. + int i;
  3877. +
  3878. + switch (priv->firmware_type) {
  3879. + case FIRMWARE_TYPE_AGERE:
  3880. + {
  3881. + struct orinoco_key keys[ORINOCO_MAX_KEYS];
  3882. +
  3883. + memset(&keys, 0, sizeof(keys));
  3884. + for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
  3885. + int len = min(priv->keys[i].key_len,
  3886. + ORINOCO_MAX_KEY_SIZE);
  3887. + memcpy(&keys[i].data, priv->keys[i].key, len);
  3888. + if (len > SMALL_KEY_SIZE)
  3889. + keys[i].len = cpu_to_le16(LARGE_KEY_SIZE);
  3890. + else if (len > 0)
  3891. + keys[i].len = cpu_to_le16(SMALL_KEY_SIZE);
  3892. + else
  3893. + keys[i].len = cpu_to_le16(0);
  3894. + }
  3895. +
  3896. + err = HERMES_WRITE_RECORD(hw, USER_BAP,
  3897. + HERMES_RID_CNFWEPKEYS_AGERE,
  3898. + &keys);
  3899. + if (err)
  3900. + return err;
  3901. + err = hermes_write_wordrec(hw, USER_BAP,
  3902. + HERMES_RID_CNFTXKEY_AGERE,
  3903. + priv->tx_key);
  3904. + if (err)
  3905. + return err;
  3906. + break;
  3907. + }
  3908. + case FIRMWARE_TYPE_INTERSIL:
  3909. + case FIRMWARE_TYPE_SYMBOL:
  3910. + {
  3911. + int keylen;
  3912. +
  3913. + /* Force uniform key length to work around
  3914. + * firmware bugs */
  3915. + keylen = priv->keys[priv->tx_key].key_len;
  3916. +
  3917. + if (keylen > LARGE_KEY_SIZE) {
  3918. + printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
  3919. + priv->ndev->name, priv->tx_key, keylen);
  3920. + return -E2BIG;
  3921. + } else if (keylen > SMALL_KEY_SIZE)
  3922. + keylen = LARGE_KEY_SIZE;
  3923. + else if (keylen > 0)
  3924. + keylen = SMALL_KEY_SIZE;
  3925. + else
  3926. + keylen = 0;
  3927. +
  3928. + /* Write all 4 keys */
  3929. + for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
  3930. + u8 key[LARGE_KEY_SIZE] = { 0 };
  3931. +
  3932. + memcpy(key, priv->keys[i].key,
  3933. + priv->keys[i].key_len);
  3934. +
  3935. + err = hw->ops->write_ltv(hw, USER_BAP,
  3936. + HERMES_RID_CNFDEFAULTKEY0 + i,
  3937. + HERMES_BYTES_TO_RECLEN(keylen),
  3938. + key);
  3939. + if (err)
  3940. + return err;
  3941. + }
  3942. +
  3943. + /* Write the index of the key used in transmission */
  3944. + err = hermes_write_wordrec(hw, USER_BAP,
  3945. + HERMES_RID_CNFWEPDEFAULTKEYID,
  3946. + priv->tx_key);
  3947. + if (err)
  3948. + return err;
  3949. + }
  3950. + break;
  3951. + }
  3952. +
  3953. + return 0;
  3954. +}
  3955. +
  3956. +int __orinoco_hw_setup_enc(struct orinoco_private *priv)
  3957. +{
  3958. + struct hermes *hw = &priv->hw;
  3959. + int err = 0;
  3960. + int master_wep_flag;
  3961. + int auth_flag;
  3962. + int enc_flag;
  3963. +
  3964. + /* Setup WEP keys */
  3965. + if (priv->encode_alg == ORINOCO_ALG_WEP)
  3966. + __orinoco_hw_setup_wepkeys(priv);
  3967. +
  3968. + if (priv->wep_restrict)
  3969. + auth_flag = HERMES_AUTH_SHARED_KEY;
  3970. + else
  3971. + auth_flag = HERMES_AUTH_OPEN;
  3972. +
  3973. + if (priv->wpa_enabled)
  3974. + enc_flag = 2;
  3975. + else if (priv->encode_alg == ORINOCO_ALG_WEP)
  3976. + enc_flag = 1;
  3977. + else
  3978. + enc_flag = 0;
  3979. +
  3980. + switch (priv->firmware_type) {
  3981. + case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
  3982. + if (priv->encode_alg == ORINOCO_ALG_WEP) {
  3983. + /* Enable the shared-key authentication. */
  3984. + err = hermes_write_wordrec(hw, USER_BAP,
  3985. + HERMES_RID_CNFAUTHENTICATION_AGERE,
  3986. + auth_flag);
  3987. + if (err)
  3988. + return err;
  3989. + }
  3990. + err = hermes_write_wordrec(hw, USER_BAP,
  3991. + HERMES_RID_CNFWEPENABLED_AGERE,
  3992. + enc_flag);
  3993. + if (err)
  3994. + return err;
  3995. +
  3996. + if (priv->has_wpa) {
  3997. + /* Set WPA key management */
  3998. + err = hermes_write_wordrec(hw, USER_BAP,
  3999. + HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
  4000. + priv->key_mgmt);
  4001. + if (err)
  4002. + return err;
  4003. + }
  4004. +
  4005. + break;
  4006. +
  4007. + case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
  4008. + case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
  4009. + if (priv->encode_alg == ORINOCO_ALG_WEP) {
  4010. + if (priv->wep_restrict ||
  4011. + (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
  4012. + master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
  4013. + HERMES_WEP_EXCL_UNENCRYPTED;
  4014. + else
  4015. + master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
  4016. +
  4017. + err = hermes_write_wordrec(hw, USER_BAP,
  4018. + HERMES_RID_CNFAUTHENTICATION,
  4019. + auth_flag);
  4020. + if (err)
  4021. + return err;
  4022. + } else
  4023. + master_wep_flag = 0;
  4024. +
  4025. + if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
  4026. + master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
  4027. +
  4028. + /* Master WEP setting : on/off */
  4029. + err = hermes_write_wordrec(hw, USER_BAP,
  4030. + HERMES_RID_CNFWEPFLAGS_INTERSIL,
  4031. + master_wep_flag);
  4032. + if (err)
  4033. + return err;
  4034. +
  4035. + break;
  4036. + }
  4037. +
  4038. + return 0;
  4039. +}
  4040. +
  4041. +/* key must be 32 bytes, including the tx and rx MIC keys.
  4042. + * rsc must be NULL or up to 8 bytes
  4043. + * tsc must be NULL or up to 8 bytes
  4044. + */
  4045. +int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
  4046. + int set_tx, const u8 *key, size_t key_len,
  4047. + const u8 *rsc, size_t rsc_len,
  4048. + const u8 *tsc, size_t tsc_len)
  4049. +{
  4050. + struct {
  4051. + __le16 idx;
  4052. + u8 rsc[ORINOCO_SEQ_LEN];
  4053. + struct {
  4054. + u8 key[TKIP_KEYLEN];
  4055. + u8 tx_mic[MIC_KEYLEN];
  4056. + u8 rx_mic[MIC_KEYLEN];
  4057. + } tkip;
  4058. + u8 tsc[ORINOCO_SEQ_LEN];
  4059. + } __packed buf;
  4060. + struct hermes *hw = &priv->hw;
  4061. + int ret;
  4062. + int err;
  4063. + int k;
  4064. + u16 xmitting;
  4065. +
  4066. + key_idx &= 0x3;
  4067. +
  4068. + if (set_tx)
  4069. + key_idx |= 0x8000;
  4070. +
  4071. + buf.idx = cpu_to_le16(key_idx);
  4072. + if (key_len != sizeof(buf.tkip))
  4073. + return -EINVAL;
  4074. + memcpy(&buf.tkip, key, sizeof(buf.tkip));
  4075. +
  4076. + if (rsc_len > sizeof(buf.rsc))
  4077. + rsc_len = sizeof(buf.rsc);
  4078. +
  4079. + if (tsc_len > sizeof(buf.tsc))
  4080. + tsc_len = sizeof(buf.tsc);
  4081. +
  4082. + memset(buf.rsc, 0, sizeof(buf.rsc));
  4083. + memset(buf.tsc, 0, sizeof(buf.tsc));
  4084. +
  4085. + if (rsc != NULL)
  4086. + memcpy(buf.rsc, rsc, rsc_len);
  4087. +
  4088. + if (tsc != NULL)
  4089. + memcpy(buf.tsc, tsc, tsc_len);
  4090. + else
  4091. + buf.tsc[4] = 0x10;
  4092. +
  4093. + /* Wait up to 100ms for tx queue to empty */
  4094. + for (k = 100; k > 0; k--) {
  4095. + udelay(1000);
  4096. + ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
  4097. + &xmitting);
  4098. + if (ret || !xmitting)
  4099. + break;
  4100. + }
  4101. +
  4102. + if (k == 0)
  4103. + ret = -ETIMEDOUT;
  4104. +
  4105. + err = HERMES_WRITE_RECORD(hw, USER_BAP,
  4106. + HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
  4107. + &buf);
  4108. +
  4109. + return ret ? ret : err;
  4110. +}
  4111. +
  4112. +int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
  4113. +{
  4114. + struct hermes *hw = &priv->hw;
  4115. + int err;
  4116. +
  4117. + err = hermes_write_wordrec(hw, USER_BAP,
  4118. + HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
  4119. + key_idx);
  4120. + if (err)
  4121. + printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
  4122. + priv->ndev->name, err, key_idx);
  4123. + return err;
  4124. +}
  4125. +
  4126. +int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
  4127. + struct net_device *dev,
  4128. + int mc_count, int promisc)
  4129. +{
  4130. + struct hermes *hw = &priv->hw;
  4131. + int err = 0;
  4132. +
  4133. + if (promisc != priv->promiscuous) {
  4134. + err = hermes_write_wordrec(hw, USER_BAP,
  4135. + HERMES_RID_CNFPROMISCUOUSMODE,
  4136. + promisc);
  4137. + if (err) {
  4138. + printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
  4139. + priv->ndev->name, err);
  4140. + } else
  4141. + priv->promiscuous = promisc;
  4142. + }
  4143. +
  4144. + /* If we're not in promiscuous mode, then we need to set the
  4145. + * group address if either we want to multicast, or if we were
  4146. + * multicasting and want to stop */
  4147. + if (!promisc && (mc_count || priv->mc_count)) {
  4148. + struct netdev_hw_addr *ha;
  4149. + struct hermes_multicast mclist;
  4150. + int i = 0;
  4151. +
  4152. + netdev_for_each_mc_addr(ha, dev) {
  4153. + if (i == mc_count)
  4154. + break;
  4155. + memcpy(mclist.addr[i++], ha->addr, ETH_ALEN);
  4156. + }
  4157. +
  4158. + err = hw->ops->write_ltv(hw, USER_BAP,
  4159. + HERMES_RID_CNFGROUPADDRESSES,
  4160. + HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
  4161. + &mclist);
  4162. + if (err)
  4163. + printk(KERN_ERR "%s: Error %d setting multicast list.\n",
  4164. + priv->ndev->name, err);
  4165. + else
  4166. + priv->mc_count = mc_count;
  4167. + }
  4168. + return err;
  4169. +}
  4170. +
  4171. +/* Return : < 0 -> error code ; >= 0 -> length */
  4172. +int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
  4173. + char buf[IW_ESSID_MAX_SIZE + 1])
  4174. +{
  4175. + struct hermes *hw = &priv->hw;
  4176. + int err = 0;
  4177. + struct hermes_idstring essidbuf;
  4178. + char *p = (char *)(&essidbuf.val);
  4179. + int len;
  4180. + unsigned long flags;
  4181. +
  4182. + if (orinoco_lock(priv, &flags) != 0)
  4183. + return -EBUSY;
  4184. +
  4185. + if (strlen(priv->desired_essid) > 0) {
  4186. + /* We read the desired SSID from the hardware rather
  4187. + than from priv->desired_essid, just in case the
  4188. + firmware is allowed to change it on us. I'm not
  4189. + sure about this */
  4190. + /* My guess is that the OWNSSID should always be whatever
  4191. + * we set to the card, whereas CURRENT_SSID is the one that
  4192. + * may change... - Jean II */
  4193. + u16 rid;
  4194. +
  4195. + *active = 1;
  4196. +
  4197. + rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
  4198. + HERMES_RID_CNFDESIREDSSID;
  4199. +
  4200. + err = hw->ops->read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
  4201. + NULL, &essidbuf);
  4202. + if (err)
  4203. + goto fail_unlock;
  4204. + } else {
  4205. + *active = 0;
  4206. +
  4207. + err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
  4208. + sizeof(essidbuf), NULL, &essidbuf);
  4209. + if (err)
  4210. + goto fail_unlock;
  4211. + }
  4212. +
  4213. + len = le16_to_cpu(essidbuf.len);
  4214. + BUG_ON(len > IW_ESSID_MAX_SIZE);
  4215. +
  4216. + memset(buf, 0, IW_ESSID_MAX_SIZE);
  4217. + memcpy(buf, p, len);
  4218. + err = len;
  4219. +
  4220. + fail_unlock:
  4221. + orinoco_unlock(priv, &flags);
  4222. +
  4223. + return err;
  4224. +}
  4225. +
  4226. +int orinoco_hw_get_freq(struct orinoco_private *priv)
  4227. +{
  4228. + struct hermes *hw = &priv->hw;
  4229. + int err = 0;
  4230. + u16 channel;
  4231. + int freq = 0;
  4232. + unsigned long flags;
  4233. +
  4234. + if (orinoco_lock(priv, &flags) != 0)
  4235. + return -EBUSY;
  4236. +
  4237. + err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL,
  4238. + &channel);
  4239. + if (err)
  4240. + goto out;
  4241. +
  4242. + /* Intersil firmware 1.3.5 returns 0 when the interface is down */
  4243. + if (channel == 0) {
  4244. + err = -EBUSY;
  4245. + goto out;
  4246. + }
  4247. +
  4248. + if ((channel < 1) || (channel > NUM_CHANNELS)) {
  4249. + printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
  4250. + priv->ndev->name, channel);
  4251. + err = -EBUSY;
  4252. + goto out;
  4253. +
  4254. + }
  4255. + freq = ieee80211_channel_to_frequency(channel, NL80211_BAND_2GHZ);
  4256. +
  4257. + out:
  4258. + orinoco_unlock(priv, &flags);
  4259. +
  4260. + if (err > 0)
  4261. + err = -EBUSY;
  4262. + return err ? err : freq;
  4263. +}
  4264. +
  4265. +int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
  4266. + int *numrates, s32 *rates, int max)
  4267. +{
  4268. + struct hermes *hw = &priv->hw;
  4269. + struct hermes_idstring list;
  4270. + unsigned char *p = (unsigned char *)&list.val;
  4271. + int err = 0;
  4272. + int num;
  4273. + int i;
  4274. + unsigned long flags;
  4275. +
  4276. + if (orinoco_lock(priv, &flags) != 0)
  4277. + return -EBUSY;
  4278. +
  4279. + err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
  4280. + sizeof(list), NULL, &list);
  4281. + orinoco_unlock(priv, &flags);
  4282. +
  4283. + if (err)
  4284. + return err;
  4285. +
  4286. + num = le16_to_cpu(list.len);
  4287. + *numrates = num;
  4288. + num = min(num, max);
  4289. +
  4290. + for (i = 0; i < num; i++)
  4291. + rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
  4292. +
  4293. + return 0;
  4294. +}
  4295. +
  4296. +int orinoco_hw_trigger_scan(struct orinoco_private *priv,
  4297. + const struct cfg80211_ssid *ssid)
  4298. +{
  4299. + struct net_device *dev = priv->ndev;
  4300. + struct hermes *hw = &priv->hw;
  4301. + unsigned long flags;
  4302. + int err = 0;
  4303. +
  4304. + if (orinoco_lock(priv, &flags) != 0)
  4305. + return -EBUSY;
  4306. +
  4307. + /* Scanning with port 0 disabled would fail */
  4308. + if (!netif_running(dev)) {
  4309. + err = -ENETDOWN;
  4310. + goto out;
  4311. + }
  4312. +
  4313. + /* In monitor mode, the scan results are always empty.
  4314. + * Probe responses are passed to the driver as received
  4315. + * frames and could be processed in software. */
  4316. + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
  4317. + err = -EOPNOTSUPP;
  4318. + goto out;
  4319. + }
  4320. +
  4321. + if (priv->has_hostscan) {
  4322. + switch (priv->firmware_type) {
  4323. + case FIRMWARE_TYPE_SYMBOL:
  4324. + err = hermes_write_wordrec(hw, USER_BAP,
  4325. + HERMES_RID_CNFHOSTSCAN_SYMBOL,
  4326. + HERMES_HOSTSCAN_SYMBOL_ONCE |
  4327. + HERMES_HOSTSCAN_SYMBOL_BCAST);
  4328. + break;
  4329. + case FIRMWARE_TYPE_INTERSIL: {
  4330. + __le16 req[3];
  4331. +
  4332. + req[0] = cpu_to_le16(0x3fff); /* All channels */
  4333. + req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
  4334. + req[2] = 0; /* Any ESSID */
  4335. + err = HERMES_WRITE_RECORD(hw, USER_BAP,
  4336. + HERMES_RID_CNFHOSTSCAN, &req);
  4337. + break;
  4338. + }
  4339. + case FIRMWARE_TYPE_AGERE:
  4340. + if (ssid->ssid_len > 0) {
  4341. + struct hermes_idstring idbuf;
  4342. + size_t len = ssid->ssid_len;
  4343. +
  4344. + idbuf.len = cpu_to_le16(len);
  4345. + memcpy(idbuf.val, ssid->ssid, len);
  4346. +
  4347. + err = hw->ops->write_ltv(hw, USER_BAP,
  4348. + HERMES_RID_CNFSCANSSID_AGERE,
  4349. + HERMES_BYTES_TO_RECLEN(len + 2),
  4350. + &idbuf);
  4351. + } else
  4352. + err = hermes_write_wordrec(hw, USER_BAP,
  4353. + HERMES_RID_CNFSCANSSID_AGERE,
  4354. + 0); /* Any ESSID */
  4355. + if (err)
  4356. + break;
  4357. +
  4358. + if (priv->has_ext_scan) {
  4359. + err = hermes_write_wordrec(hw, USER_BAP,
  4360. + HERMES_RID_CNFSCANCHANNELS2GHZ,
  4361. + 0x7FFF);
  4362. + if (err)
  4363. + goto out;
  4364. +
  4365. + err = hermes_inquire(hw,
  4366. + HERMES_INQ_CHANNELINFO);
  4367. + } else
  4368. + err = hermes_inquire(hw, HERMES_INQ_SCAN);
  4369. +
  4370. + break;
  4371. + }
  4372. + } else
  4373. + err = hermes_inquire(hw, HERMES_INQ_SCAN);
  4374. +
  4375. + out:
  4376. + orinoco_unlock(priv, &flags);
  4377. +
  4378. + return err;
  4379. +}
  4380. +
  4381. +/* Disassociate from node with BSSID addr */
  4382. +int orinoco_hw_disassociate(struct orinoco_private *priv,
  4383. + u8 *addr, u16 reason_code)
  4384. +{
  4385. + struct hermes *hw = &priv->hw;
  4386. + int err;
  4387. +
  4388. + struct {
  4389. + u8 addr[ETH_ALEN];
  4390. + __le16 reason_code;
  4391. + } __packed buf;
  4392. +
  4393. + /* Currently only supported by WPA enabled Agere fw */
  4394. + if (!priv->has_wpa)
  4395. + return -EOPNOTSUPP;
  4396. +
  4397. + memcpy(buf.addr, addr, ETH_ALEN);
  4398. + buf.reason_code = cpu_to_le16(reason_code);
  4399. + err = HERMES_WRITE_RECORD(hw, USER_BAP,
  4400. + HERMES_RID_CNFDISASSOCIATE,
  4401. + &buf);
  4402. + return err;
  4403. +}
  4404. +
  4405. +int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
  4406. + u8 *addr)
  4407. +{
  4408. + struct hermes *hw = &priv->hw;
  4409. + int err;
  4410. +
  4411. + err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
  4412. + ETH_ALEN, NULL, addr);
  4413. +
  4414. + return err;
  4415. +}
  4416. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hw.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/hw.h
  4417. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/hw.h 1970-01-01 01:00:00.000000000 +0100
  4418. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/hw.h 2026-02-16 14:00:36.623256352 +0100
  4419. @@ -0,0 +1,60 @@
  4420. +/* Encapsulate basic setting changes on Hermes hardware
  4421. + *
  4422. + * See copyright notice in main.c
  4423. + */
  4424. +#ifndef _ORINOCO_HW_H_
  4425. +#define _ORINOCO_HW_H_
  4426. +
  4427. +#include <linux/types.h>
  4428. +#include <linux/wireless.h>
  4429. +#include <net/cfg80211.h>
  4430. +
  4431. +/* Hardware BAPs */
  4432. +#define USER_BAP 0
  4433. +#define IRQ_BAP 1
  4434. +
  4435. +/* WEP key sizes */
  4436. +#define SMALL_KEY_SIZE 5
  4437. +#define LARGE_KEY_SIZE 13
  4438. +
  4439. +/* Number of supported channels */
  4440. +#define NUM_CHANNELS 14
  4441. +
  4442. +/* Forward declarations */
  4443. +struct orinoco_private;
  4444. +
  4445. +int determine_fw_capabilities(struct orinoco_private *priv, char *fw_name,
  4446. + size_t fw_name_len, u32 *hw_ver);
  4447. +int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr);
  4448. +int orinoco_hw_allocate_fid(struct orinoco_private *priv);
  4449. +int orinoco_get_bitratemode(int bitrate, int automatic);
  4450. +void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic);
  4451. +
  4452. +int orinoco_hw_program_rids(struct orinoco_private *priv);
  4453. +int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc);
  4454. +int __orinoco_hw_set_bitrate(struct orinoco_private *priv);
  4455. +int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate);
  4456. +int __orinoco_hw_set_wap(struct orinoco_private *priv);
  4457. +int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv);
  4458. +int __orinoco_hw_setup_enc(struct orinoco_private *priv);
  4459. +int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
  4460. + int set_tx, const u8 *key, size_t key_len,
  4461. + const u8 *rsc, size_t rsc_len,
  4462. + const u8 *tsc, size_t tsc_len);
  4463. +int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx);
  4464. +int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
  4465. + struct net_device *dev,
  4466. + int mc_count, int promisc);
  4467. +int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
  4468. + char buf[IW_ESSID_MAX_SIZE + 1]);
  4469. +int orinoco_hw_get_freq(struct orinoco_private *priv);
  4470. +int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
  4471. + int *numrates, s32 *rates, int max);
  4472. +int orinoco_hw_trigger_scan(struct orinoco_private *priv,
  4473. + const struct cfg80211_ssid *ssid);
  4474. +int orinoco_hw_disassociate(struct orinoco_private *priv,
  4475. + u8 *addr, u16 reason_code);
  4476. +int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
  4477. + u8 *addr);
  4478. +
  4479. +#endif /* _ORINOCO_HW_H_ */
  4480. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/Kconfig linux-6.18.9/drivers/net/wireless/intersil/orinoco/Kconfig
  4481. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/Kconfig 1970-01-01 01:00:00.000000000 +0100
  4482. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/Kconfig 2026-02-16 14:00:36.623256352 +0100
  4483. @@ -0,0 +1,143 @@
  4484. +# SPDX-License-Identifier: GPL-2.0-only
  4485. +config HERMES
  4486. + tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
  4487. + depends on (PPC_PMAC || PCI || PCMCIA)
  4488. + depends on CFG80211
  4489. + select CFG80211_WEXT_EXPORT
  4490. + select WIRELESS_EXT
  4491. + select WEXT_SPY
  4492. + select WEXT_PRIV
  4493. + select FW_LOADER
  4494. + select CRYPTO
  4495. + select CRYPTO_MICHAEL_MIC
  4496. + help
  4497. + A driver for 802.11b wireless cards based on the "Hermes" or
  4498. + Intersil HFA384x (Prism 2) MAC controller. This includes the vast
  4499. + majority of the PCMCIA 802.11b cards (which are nearly all rebadges)
  4500. + - except for the Cisco/Aironet cards. Cards supported include the
  4501. + Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco,
  4502. + Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya,
  4503. + IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear
  4504. + MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel
  4505. + IPW2011, and Symbol Spectrum24 High Rate amongst others.
  4506. +
  4507. + This option includes the guts of the driver, but in order to
  4508. + actually use a card you will also need to enable support for PCMCIA
  4509. + Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below.
  4510. +
  4511. + You will also very likely also need the Wireless Tools in order to
  4512. + configure your card and that /etc/pcmcia/wireless.opts works :
  4513. + <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>
  4514. +
  4515. +config HERMES_PRISM
  4516. + bool "Support Prism 2/2.5 chipset"
  4517. + depends on HERMES
  4518. + help
  4519. +
  4520. + Say Y to enable support for Prism 2 and 2.5 chipsets. These
  4521. + chipsets are better handled by the hostap driver. This driver
  4522. + would not support WPA or firmware download for Prism chipset.
  4523. +
  4524. + If you are not sure, say N.
  4525. +
  4526. +config HERMES_CACHE_FW_ON_INIT
  4527. + bool "Cache Hermes firmware on driver initialisation"
  4528. + depends on HERMES
  4529. + default y
  4530. + help
  4531. + Say Y to cache any firmware required by the Hermes drivers
  4532. + on startup. The firmware will remain cached until the
  4533. + driver is unloaded. The cache uses 64K of RAM.
  4534. +
  4535. + Otherwise load the firmware from userspace as required. In
  4536. + this case the driver should be unloaded and restarted
  4537. + whenever the firmware is changed.
  4538. +
  4539. + If you are not sure, say Y.
  4540. +
  4541. +config APPLE_AIRPORT
  4542. + tristate "Apple Airport support (built-in)"
  4543. + depends on PPC_PMAC && HERMES
  4544. + help
  4545. + Say Y here to support the Airport 802.11b wireless Ethernet hardware
  4546. + built into the Macintosh iBook and other recent PowerPC-based
  4547. + Macintosh machines. This is essentially a Lucent Orinoco card with
  4548. + a non-standard interface.
  4549. +
  4550. + This driver does not support the Airport Extreme (802.11b/g). Use
  4551. + the BCM43xx driver for Airport Extreme cards.
  4552. +
  4553. +config PLX_HERMES
  4554. + tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)"
  4555. + depends on PCI && HERMES
  4556. + help
  4557. + Enable support for PCMCIA cards supported by the "Hermes" (aka
  4558. + orinoco) driver when used in PLX9052 based PCI adaptors. These
  4559. + adaptors are not a full PCMCIA controller but act as a more limited
  4560. + PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
  4561. + 802.11b PCMCIA cards can be used in desktop machines. The Netgear
  4562. + MA301 is such an adaptor.
  4563. +
  4564. +config TMD_HERMES
  4565. + tristate "Hermes in TMD7160 based PCI adaptor support"
  4566. + depends on PCI && HERMES
  4567. + help
  4568. + Enable support for PCMCIA cards supported by the "Hermes" (aka
  4569. + orinoco) driver when used in TMD7160 based PCI adaptors. These
  4570. + adaptors are not a full PCMCIA controller but act as a more limited
  4571. + PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
  4572. + 802.11b PCMCIA cards can be used in desktop machines.
  4573. +
  4574. +config NORTEL_HERMES
  4575. + tristate "Nortel emobility PCI adaptor support"
  4576. + depends on PCI && HERMES
  4577. + help
  4578. + Enable support for PCMCIA cards supported by the "Hermes" (aka
  4579. + orinoco) driver when used in Nortel emobility PCI adaptors. These
  4580. + adaptors are not full PCMCIA controllers, but act as a more limited
  4581. + PCI <-> PCMCIA bridge.
  4582. +
  4583. +config PCI_HERMES
  4584. + tristate "Prism 2.5 PCI 802.11b adaptor support"
  4585. + depends on PCI && HERMES && HERMES_PRISM
  4586. + help
  4587. + Enable support for PCI and mini-PCI 802.11b wireless NICs based on
  4588. + the Prism 2.5 chipset. These are true PCI cards, not the 802.11b
  4589. + PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also
  4590. + common. Some of the built-in wireless adaptors in laptops are of
  4591. + this variety.
  4592. +
  4593. +config PCMCIA_HERMES
  4594. + tristate "Hermes PCMCIA card support"
  4595. + depends on PCMCIA && HERMES && HAS_IOPORT_MAP
  4596. + help
  4597. + A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
  4598. + as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
  4599. + EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and
  4600. + others). It should also be usable on various Prism II based cards
  4601. + such as the Linksys, D-Link and Farallon Skyline. It should also
  4602. + work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN.
  4603. +
  4604. + You will very likely need the Wireless Tools in order to
  4605. + configure your card and that /etc/pcmcia/wireless.opts works:
  4606. + <https://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
  4607. +
  4608. +config PCMCIA_SPECTRUM
  4609. + tristate "Symbol Spectrum24 Trilogy PCMCIA card support"
  4610. + depends on PCMCIA && HERMES && HAS_IOPORT_MAP
  4611. + help
  4612. +
  4613. + This is a driver for 802.11b cards using RAM-loadable Symbol
  4614. + firmware, such as Symbol Wireless Networker LA4100, CompactFlash
  4615. + cards by Socket Communications and Intel PRO/Wireless 2011B.
  4616. +
  4617. + This driver requires firmware download on startup. Utilities
  4618. + for downloading Symbol firmware are available at
  4619. + <http://sourceforge.net/projects/orinoco/>
  4620. +
  4621. +config ORINOCO_USB
  4622. + tristate "Agere Orinoco USB support"
  4623. + depends on USB && HERMES
  4624. + select FW_LOADER
  4625. + help
  4626. + This driver is for USB versions of the Agere Orinoco card.
  4627. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/main.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/main.c
  4628. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/main.c 1970-01-01 01:00:00.000000000 +0100
  4629. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/main.c 2026-02-16 14:00:36.623256352 +0100
  4630. @@ -0,0 +1,2414 @@
  4631. +/* main.c - (formerly known as dldwd_cs.c, orinoco_cs.c and orinoco.c)
  4632. + *
  4633. + * A driver for Hermes or Prism 2 chipset based PCMCIA wireless
  4634. + * adaptors, with Lucent/Agere, Intersil or Symbol firmware.
  4635. + *
  4636. + * Current maintainers (as of 29 September 2003) are:
  4637. + * Pavel Roskin <proski AT gnu.org>
  4638. + * and David Gibson <hermes AT gibson.dropbear.id.au>
  4639. + *
  4640. + * (C) Copyright David Gibson, IBM Corporation 2001-2003.
  4641. + * Copyright (C) 2000 David Gibson, Linuxcare Australia.
  4642. + * With some help from :
  4643. + * Copyright (C) 2001 Jean Tourrilhes, HP Labs
  4644. + * Copyright (C) 2001 Benjamin Herrenschmidt
  4645. + *
  4646. + * Based on dummy_cs.c 1.27 2000/06/12 21:27:25
  4647. + *
  4648. + * Portions based on wvlan_cs.c 1.0.6, Copyright Andreas Neuhaus <andy
  4649. + * AT fasta.fh-dortmund.de>
  4650. + * http://www.stud.fh-dortmund.de/~andy/wvlan/
  4651. + *
  4652. + * The contents of this file are subject to the Mozilla Public License
  4653. + * Version 1.1 (the "License"); you may not use this file except in
  4654. + * compliance with the License. You may obtain a copy of the License
  4655. + * at http://www.mozilla.org/MPL/
  4656. + *
  4657. + * Software distributed under the License is distributed on an "AS IS"
  4658. + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  4659. + * the License for the specific language governing rights and
  4660. + * limitations under the License.
  4661. + *
  4662. + * The initial developer of the original code is David A. Hinds
  4663. + * <dahinds AT users.sourceforge.net>. Portions created by David
  4664. + * A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights
  4665. + * Reserved.
  4666. + *
  4667. + * Alternatively, the contents of this file may be used under the
  4668. + * terms of the GNU General Public License version 2 (the "GPL"), in
  4669. + * which case the provisions of the GPL are applicable instead of the
  4670. + * above. If you wish to allow the use of your version of this file
  4671. + * only under the terms of the GPL and not to allow others to use your
  4672. + * version of this file under the MPL, indicate your decision by
  4673. + * deleting the provisions above and replace them with the notice and
  4674. + * other provisions required by the GPL. If you do not delete the
  4675. + * provisions above, a recipient may use your version of this file
  4676. + * under either the MPL or the GPL. */
  4677. +
  4678. +/*
  4679. + * TODO
  4680. + * o Handle de-encapsulation within network layer, provide 802.11
  4681. + * headers (patch from Thomas 'Dent' Mirlacher)
  4682. + * o Fix possible races in SPY handling.
  4683. + * o Disconnect wireless extensions from fundamental configuration.
  4684. + * o (maybe) Software WEP support (patch from Stano Meduna).
  4685. + * o (maybe) Use multiple Tx buffers - driver handling queue
  4686. + * rather than firmware.
  4687. + */
  4688. +
  4689. +/* Locking and synchronization:
  4690. + *
  4691. + * The basic principle is that everything is serialized through a
  4692. + * single spinlock, priv->lock. The lock is used in user, bh and irq
  4693. + * context, so when taken outside hardirq context it should always be
  4694. + * taken with interrupts disabled. The lock protects both the
  4695. + * hardware and the struct orinoco_private.
  4696. + *
  4697. + * Another flag, priv->hw_unavailable indicates that the hardware is
  4698. + * unavailable for an extended period of time (e.g. suspended, or in
  4699. + * the middle of a hard reset). This flag is protected by the
  4700. + * spinlock. All code which touches the hardware should check the
  4701. + * flag after taking the lock, and if it is set, give up on whatever
  4702. + * they are doing and drop the lock again. The orinoco_lock()
  4703. + * function handles this (it unlocks and returns -EBUSY if
  4704. + * hw_unavailable is non-zero).
  4705. + */
  4706. +
  4707. +#define DRIVER_NAME "orinoco"
  4708. +
  4709. +#include <linux/module.h>
  4710. +#include <linux/kernel.h>
  4711. +#include <linux/slab.h>
  4712. +#include <linux/init.h>
  4713. +#include <linux/delay.h>
  4714. +#include <linux/device.h>
  4715. +#include <linux/netdevice.h>
  4716. +#include <linux/etherdevice.h>
  4717. +#include <linux/suspend.h>
  4718. +#include <linux/if_arp.h>
  4719. +#include <linux/wireless.h>
  4720. +#include <linux/ieee80211.h>
  4721. +#include <net/iw_handler.h>
  4722. +#include <net/cfg80211.h>
  4723. +
  4724. +#include "hermes_rid.h"
  4725. +#include "hermes_dld.h"
  4726. +#include "hw.h"
  4727. +#include "scan.h"
  4728. +#include "mic.h"
  4729. +#include "fw.h"
  4730. +#include "wext.h"
  4731. +#include "cfg.h"
  4732. +#include "main.h"
  4733. +
  4734. +#include "orinoco.h"
  4735. +
  4736. +/********************************************************************/
  4737. +/* Module information */
  4738. +/********************************************************************/
  4739. +
  4740. +MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> & "
  4741. + "David Gibson <hermes@gibson.dropbear.id.au>");
  4742. +MODULE_DESCRIPTION("Driver for Lucent Orinoco, Prism II based "
  4743. + "and similar wireless cards");
  4744. +MODULE_LICENSE("Dual MPL/GPL");
  4745. +
  4746. +/* Level of debugging. Used in the macros in orinoco.h */
  4747. +#ifdef ORINOCO_DEBUG
  4748. +int orinoco_debug = ORINOCO_DEBUG;
  4749. +EXPORT_SYMBOL(orinoco_debug);
  4750. +module_param(orinoco_debug, int, 0644);
  4751. +MODULE_PARM_DESC(orinoco_debug, "Debug level");
  4752. +#endif
  4753. +
  4754. +static bool suppress_linkstatus; /* = 0 */
  4755. +module_param(suppress_linkstatus, bool, 0644);
  4756. +MODULE_PARM_DESC(suppress_linkstatus, "Don't log link status changes");
  4757. +
  4758. +static int ignore_disconnect; /* = 0 */
  4759. +module_param(ignore_disconnect, int, 0644);
  4760. +MODULE_PARM_DESC(ignore_disconnect,
  4761. + "Don't report lost link to the network layer");
  4762. +
  4763. +int force_monitor; /* = 0 */
  4764. +module_param(force_monitor, int, 0644);
  4765. +MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
  4766. +
  4767. +/********************************************************************/
  4768. +/* Internal constants */
  4769. +/********************************************************************/
  4770. +
  4771. +/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
  4772. +static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
  4773. +#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
  4774. +
  4775. +#define ORINOCO_MIN_MTU 256
  4776. +#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD)
  4777. +
  4778. +#define MAX_IRQLOOPS_PER_IRQ 10
  4779. +#define MAX_IRQLOOPS_PER_JIFFY (20000 / HZ) /* Based on a guestimate of
  4780. + * how many events the
  4781. + * device could
  4782. + * legitimately generate */
  4783. +
  4784. +#define DUMMY_FID 0xFFFF
  4785. +
  4786. +/*#define MAX_MULTICAST(priv) (priv->firmware_type == FIRMWARE_TYPE_AGERE ? \
  4787. + HERMES_MAX_MULTICAST : 0)*/
  4788. +#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST)
  4789. +
  4790. +#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \
  4791. + | HERMES_EV_TX | HERMES_EV_TXEXC \
  4792. + | HERMES_EV_WTERR | HERMES_EV_INFO \
  4793. + | HERMES_EV_INFDROP)
  4794. +
  4795. +/********************************************************************/
  4796. +/* Data types */
  4797. +/********************************************************************/
  4798. +
  4799. +/* Beginning of the Tx descriptor, used in TxExc handling */
  4800. +struct hermes_txexc_data {
  4801. + struct hermes_tx_descriptor desc;
  4802. + __le16 frame_ctl;
  4803. + __le16 duration_id;
  4804. + u8 addr1[ETH_ALEN];
  4805. +} __packed;
  4806. +
  4807. +/* Rx frame header except compatibility 802.3 header */
  4808. +struct hermes_rx_descriptor {
  4809. + /* Control */
  4810. + __le16 status;
  4811. + __le32 time;
  4812. + u8 silence;
  4813. + u8 signal;
  4814. + u8 rate;
  4815. + u8 rxflow;
  4816. + __le32 reserved;
  4817. +
  4818. + /* 802.11 header */
  4819. + __le16 frame_ctl;
  4820. + __le16 duration_id;
  4821. + u8 addr1[ETH_ALEN];
  4822. + u8 addr2[ETH_ALEN];
  4823. + u8 addr3[ETH_ALEN];
  4824. + __le16 seq_ctl;
  4825. + u8 addr4[ETH_ALEN];
  4826. +
  4827. + /* Data length */
  4828. + __le16 data_len;
  4829. +} __packed;
  4830. +
  4831. +struct orinoco_rx_data {
  4832. + struct hermes_rx_descriptor *desc;
  4833. + struct sk_buff *skb;
  4834. + struct list_head list;
  4835. +};
  4836. +
  4837. +struct orinoco_scan_data {
  4838. + void *buf;
  4839. + size_t len;
  4840. + int type;
  4841. + struct list_head list;
  4842. +};
  4843. +
  4844. +/********************************************************************/
  4845. +/* Function prototypes */
  4846. +/********************************************************************/
  4847. +
  4848. +static int __orinoco_set_multicast_list(struct net_device *dev);
  4849. +static int __orinoco_up(struct orinoco_private *priv);
  4850. +static int __orinoco_down(struct orinoco_private *priv);
  4851. +static int __orinoco_commit(struct orinoco_private *priv);
  4852. +
  4853. +/********************************************************************/
  4854. +/* Internal helper functions */
  4855. +/********************************************************************/
  4856. +
  4857. +void set_port_type(struct orinoco_private *priv)
  4858. +{
  4859. + switch (priv->iw_mode) {
  4860. + case NL80211_IFTYPE_STATION:
  4861. + priv->port_type = 1;
  4862. + priv->createibss = 0;
  4863. + break;
  4864. + case NL80211_IFTYPE_ADHOC:
  4865. + if (priv->prefer_port3) {
  4866. + priv->port_type = 3;
  4867. + priv->createibss = 0;
  4868. + } else {
  4869. + priv->port_type = priv->ibss_port;
  4870. + priv->createibss = 1;
  4871. + }
  4872. + break;
  4873. + case NL80211_IFTYPE_MONITOR:
  4874. + priv->port_type = 3;
  4875. + priv->createibss = 0;
  4876. + break;
  4877. + default:
  4878. + printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
  4879. + priv->ndev->name);
  4880. + }
  4881. +}
  4882. +
  4883. +/********************************************************************/
  4884. +/* Device methods */
  4885. +/********************************************************************/
  4886. +
  4887. +int orinoco_open(struct net_device *dev)
  4888. +{
  4889. + struct orinoco_private *priv = ndev_priv(dev);
  4890. + unsigned long flags;
  4891. + int err;
  4892. +
  4893. + if (orinoco_lock(priv, &flags) != 0)
  4894. + return -EBUSY;
  4895. +
  4896. + err = __orinoco_up(priv);
  4897. +
  4898. + if (!err)
  4899. + priv->open = 1;
  4900. +
  4901. + orinoco_unlock(priv, &flags);
  4902. +
  4903. + return err;
  4904. +}
  4905. +EXPORT_SYMBOL(orinoco_open);
  4906. +
  4907. +int orinoco_stop(struct net_device *dev)
  4908. +{
  4909. + struct orinoco_private *priv = ndev_priv(dev);
  4910. + int err = 0;
  4911. +
  4912. + /* We mustn't use orinoco_lock() here, because we need to be
  4913. + able to close the interface even if hw_unavailable is set
  4914. + (e.g. as we're released after a PC Card removal) */
  4915. + orinoco_lock_irq(priv);
  4916. +
  4917. + priv->open = 0;
  4918. +
  4919. + err = __orinoco_down(priv);
  4920. +
  4921. + orinoco_unlock_irq(priv);
  4922. +
  4923. + return err;
  4924. +}
  4925. +EXPORT_SYMBOL(orinoco_stop);
  4926. +
  4927. +void orinoco_set_multicast_list(struct net_device *dev)
  4928. +{
  4929. + struct orinoco_private *priv = ndev_priv(dev);
  4930. + unsigned long flags;
  4931. +
  4932. + if (orinoco_lock(priv, &flags) != 0) {
  4933. + printk(KERN_DEBUG "%s: orinoco_set_multicast_list() "
  4934. + "called when hw_unavailable\n", dev->name);
  4935. + return;
  4936. + }
  4937. +
  4938. + __orinoco_set_multicast_list(dev);
  4939. + orinoco_unlock(priv, &flags);
  4940. +}
  4941. +EXPORT_SYMBOL(orinoco_set_multicast_list);
  4942. +
  4943. +int orinoco_change_mtu(struct net_device *dev, int new_mtu)
  4944. +{
  4945. + struct orinoco_private *priv = ndev_priv(dev);
  4946. +
  4947. + /* MTU + encapsulation + header length */
  4948. + if ((new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) >
  4949. + (priv->nicbuf_size - ETH_HLEN))
  4950. + return -EINVAL;
  4951. +
  4952. + dev->mtu = new_mtu;
  4953. +
  4954. + return 0;
  4955. +}
  4956. +EXPORT_SYMBOL(orinoco_change_mtu);
  4957. +
  4958. +/********************************************************************/
  4959. +/* Tx path */
  4960. +/********************************************************************/
  4961. +
  4962. +/* Add encapsulation and MIC to the existing SKB.
  4963. + * The main xmit routine will then send the whole lot to the card.
  4964. + * Need 8 bytes headroom
  4965. + * Need 8 bytes tailroom
  4966. + *
  4967. + * With encapsulated ethernet II frame
  4968. + * --------
  4969. + * 803.3 header (14 bytes)
  4970. + * dst[6]
  4971. + * -------- src[6]
  4972. + * 803.3 header (14 bytes) len[2]
  4973. + * dst[6] 803.2 header (8 bytes)
  4974. + * src[6] encaps[6]
  4975. + * len[2] <- leave alone -> len[2]
  4976. + * -------- -------- <-- 0
  4977. + * Payload Payload
  4978. + * ... ...
  4979. + *
  4980. + * -------- --------
  4981. + * MIC (8 bytes)
  4982. + * --------
  4983. + *
  4984. + * returns 0 on success, -ENOMEM on error.
  4985. + */
  4986. +int orinoco_process_xmit_skb(struct sk_buff *skb,
  4987. + struct net_device *dev,
  4988. + struct orinoco_private *priv,
  4989. + int *tx_control,
  4990. + u8 *mic_buf)
  4991. +{
  4992. + struct orinoco_tkip_key *key;
  4993. + struct ethhdr *eh;
  4994. + int do_mic;
  4995. +
  4996. + key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
  4997. +
  4998. + do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
  4999. + (key != NULL));
  5000. +
  5001. + if (do_mic)
  5002. + *tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
  5003. + HERMES_TXCTRL_MIC;
  5004. +
  5005. + eh = (struct ethhdr *)skb->data;
  5006. +
  5007. + /* Encapsulate Ethernet-II frames */
  5008. + if (ntohs(eh->h_proto) > ETH_DATA_LEN) { /* Ethernet-II frame */
  5009. + struct header_struct {
  5010. + struct ethhdr eth; /* 802.3 header */
  5011. + u8 encap[6]; /* 802.2 header */
  5012. + } __packed hdr;
  5013. + int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
  5014. +
  5015. + if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
  5016. + if (net_ratelimit())
  5017. + printk(KERN_ERR
  5018. + "%s: Not enough headroom for 802.2 headers %d\n",
  5019. + dev->name, skb_headroom(skb));
  5020. + return -ENOMEM;
  5021. + }
  5022. +
  5023. + /* Fill in new header */
  5024. + memcpy(&hdr.eth, eh, 2 * ETH_ALEN);
  5025. + hdr.eth.h_proto = htons(len);
  5026. + memcpy(hdr.encap, encaps_hdr, sizeof(encaps_hdr));
  5027. +
  5028. + /* Make room for the new header, and copy it in */
  5029. + eh = skb_push(skb, ENCAPS_OVERHEAD);
  5030. + memcpy(eh, &hdr, sizeof(hdr));
  5031. + }
  5032. +
  5033. + /* Calculate Michael MIC */
  5034. + if (do_mic) {
  5035. + size_t len = skb->len - ETH_HLEN;
  5036. + u8 *mic = &mic_buf[0];
  5037. +
  5038. + /* Have to write to an even address, so copy the spare
  5039. + * byte across */
  5040. + if (skb->len % 2) {
  5041. + *mic = skb->data[skb->len - 1];
  5042. + mic++;
  5043. + }
  5044. +
  5045. + orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
  5046. + eh->h_dest, eh->h_source, 0 /* priority */,
  5047. + skb->data + ETH_HLEN,
  5048. + len, mic);
  5049. + }
  5050. +
  5051. + return 0;
  5052. +}
  5053. +EXPORT_SYMBOL(orinoco_process_xmit_skb);
  5054. +
  5055. +static netdev_tx_t orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
  5056. +{
  5057. + struct orinoco_private *priv = ndev_priv(dev);
  5058. + struct net_device_stats *stats = &dev->stats;
  5059. + struct hermes *hw = &priv->hw;
  5060. + int err = 0;
  5061. + u16 txfid = priv->txfid;
  5062. + int tx_control;
  5063. + unsigned long flags;
  5064. + u8 mic_buf[MICHAEL_MIC_LEN + 1];
  5065. +
  5066. + if (!netif_running(dev)) {
  5067. + printk(KERN_ERR "%s: Tx on stopped device!\n",
  5068. + dev->name);
  5069. + return NETDEV_TX_BUSY;
  5070. + }
  5071. +
  5072. + if (netif_queue_stopped(dev)) {
  5073. + printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
  5074. + dev->name);
  5075. + return NETDEV_TX_BUSY;
  5076. + }
  5077. +
  5078. + if (orinoco_lock(priv, &flags) != 0) {
  5079. + printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n",
  5080. + dev->name);
  5081. + return NETDEV_TX_BUSY;
  5082. + }
  5083. +
  5084. + if (!netif_carrier_ok(dev) ||
  5085. + (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
  5086. + /* Oops, the firmware hasn't established a connection,
  5087. + silently drop the packet (this seems to be the
  5088. + safest approach). */
  5089. + goto drop;
  5090. + }
  5091. +
  5092. + /* Check packet length */
  5093. + if (skb->len < ETH_HLEN)
  5094. + goto drop;
  5095. +
  5096. + tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
  5097. +
  5098. + err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
  5099. + &mic_buf[0]);
  5100. + if (err)
  5101. + goto drop;
  5102. +
  5103. + if (priv->has_alt_txcntl) {
  5104. + /* WPA enabled firmwares have tx_cntl at the end of
  5105. + * the 802.11 header. So write zeroed descriptor and
  5106. + * 802.11 header at the same time
  5107. + */
  5108. + char desc[HERMES_802_3_OFFSET];
  5109. + __le16 *txcntl = (__le16 *) &desc[HERMES_TXCNTL2_OFFSET];
  5110. +
  5111. + memset(&desc, 0, sizeof(desc));
  5112. +
  5113. + *txcntl = cpu_to_le16(tx_control);
  5114. + err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
  5115. + txfid, 0);
  5116. + if (err) {
  5117. + if (net_ratelimit())
  5118. + printk(KERN_ERR "%s: Error %d writing Tx "
  5119. + "descriptor to BAP\n", dev->name, err);
  5120. + goto busy;
  5121. + }
  5122. + } else {
  5123. + struct hermes_tx_descriptor desc;
  5124. +
  5125. + memset(&desc, 0, sizeof(desc));
  5126. +
  5127. + desc.tx_control = cpu_to_le16(tx_control);
  5128. + err = hw->ops->bap_pwrite(hw, USER_BAP, &desc, sizeof(desc),
  5129. + txfid, 0);
  5130. + if (err) {
  5131. + if (net_ratelimit())
  5132. + printk(KERN_ERR "%s: Error %d writing Tx "
  5133. + "descriptor to BAP\n", dev->name, err);
  5134. + goto busy;
  5135. + }
  5136. +
  5137. + /* Clear the 802.11 header and data length fields - some
  5138. + * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused
  5139. + * if this isn't done. */
  5140. + hermes_clear_words(hw, HERMES_DATA0,
  5141. + HERMES_802_3_OFFSET - HERMES_802_11_OFFSET);
  5142. + }
  5143. +
  5144. + err = hw->ops->bap_pwrite(hw, USER_BAP, skb->data, skb->len,
  5145. + txfid, HERMES_802_3_OFFSET);
  5146. + if (err) {
  5147. + printk(KERN_ERR "%s: Error %d writing packet to BAP\n",
  5148. + dev->name, err);
  5149. + goto busy;
  5150. + }
  5151. +
  5152. + if (tx_control & HERMES_TXCTRL_MIC) {
  5153. + size_t offset = HERMES_802_3_OFFSET + skb->len;
  5154. + size_t len = MICHAEL_MIC_LEN;
  5155. +
  5156. + if (offset % 2) {
  5157. + offset--;
  5158. + len++;
  5159. + }
  5160. + err = hw->ops->bap_pwrite(hw, USER_BAP, &mic_buf[0], len,
  5161. + txfid, offset);
  5162. + if (err) {
  5163. + printk(KERN_ERR "%s: Error %d writing MIC to BAP\n",
  5164. + dev->name, err);
  5165. + goto busy;
  5166. + }
  5167. + }
  5168. +
  5169. + /* Finally, we actually initiate the send */
  5170. + netif_stop_queue(dev);
  5171. +
  5172. + err = hw->ops->cmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL,
  5173. + txfid, NULL);
  5174. + if (err) {
  5175. + netif_start_queue(dev);
  5176. + if (net_ratelimit())
  5177. + printk(KERN_ERR "%s: Error %d transmitting packet\n",
  5178. + dev->name, err);
  5179. + goto busy;
  5180. + }
  5181. +
  5182. + stats->tx_bytes += HERMES_802_3_OFFSET + skb->len;
  5183. + goto ok;
  5184. +
  5185. + drop:
  5186. + stats->tx_errors++;
  5187. + stats->tx_dropped++;
  5188. +
  5189. + ok:
  5190. + orinoco_unlock(priv, &flags);
  5191. + dev_kfree_skb(skb);
  5192. + return NETDEV_TX_OK;
  5193. +
  5194. + busy:
  5195. + if (err == -EIO)
  5196. + schedule_work(&priv->reset_work);
  5197. + orinoco_unlock(priv, &flags);
  5198. + return NETDEV_TX_BUSY;
  5199. +}
  5200. +
  5201. +static void __orinoco_ev_alloc(struct net_device *dev, struct hermes *hw)
  5202. +{
  5203. + struct orinoco_private *priv = ndev_priv(dev);
  5204. + u16 fid = hermes_read_regn(hw, ALLOCFID);
  5205. +
  5206. + if (fid != priv->txfid) {
  5207. + if (fid != DUMMY_FID)
  5208. + printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n",
  5209. + dev->name, fid);
  5210. + return;
  5211. + }
  5212. +
  5213. + hermes_write_regn(hw, ALLOCFID, DUMMY_FID);
  5214. +}
  5215. +
  5216. +static void __orinoco_ev_tx(struct net_device *dev, struct hermes *hw)
  5217. +{
  5218. + dev->stats.tx_packets++;
  5219. +
  5220. + netif_wake_queue(dev);
  5221. +
  5222. + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
  5223. +}
  5224. +
  5225. +static void __orinoco_ev_txexc(struct net_device *dev, struct hermes *hw)
  5226. +{
  5227. + struct net_device_stats *stats = &dev->stats;
  5228. + u16 fid = hermes_read_regn(hw, TXCOMPLFID);
  5229. + u16 status;
  5230. + struct hermes_txexc_data hdr;
  5231. + int err = 0;
  5232. +
  5233. + if (fid == DUMMY_FID)
  5234. + return; /* Nothing's really happened */
  5235. +
  5236. + /* Read part of the frame header - we need status and addr1 */
  5237. + err = hw->ops->bap_pread(hw, IRQ_BAP, &hdr,
  5238. + sizeof(struct hermes_txexc_data),
  5239. + fid, 0);
  5240. +
  5241. + hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
  5242. + stats->tx_errors++;
  5243. +
  5244. + if (err) {
  5245. + printk(KERN_WARNING "%s: Unable to read descriptor on Tx error "
  5246. + "(FID=%04X error %d)\n",
  5247. + dev->name, fid, err);
  5248. + return;
  5249. + }
  5250. +
  5251. + DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
  5252. + err, fid);
  5253. +
  5254. + /* We produce a TXDROP event only for retry or lifetime
  5255. + * exceeded, because that's the only status that really mean
  5256. + * that this particular node went away.
  5257. + * Other errors means that *we* screwed up. - Jean II */
  5258. + status = le16_to_cpu(hdr.desc.status);
  5259. + if (status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
  5260. + union iwreq_data wrqu;
  5261. +
  5262. + /* Copy 802.11 dest address.
  5263. + * We use the 802.11 header because the frame may
  5264. + * not be 802.3 or may be mangled...
  5265. + * In Ad-Hoc mode, it will be the node address.
  5266. + * In managed mode, it will be most likely the AP addr
  5267. + * User space will figure out how to convert it to
  5268. + * whatever it needs (IP address or else).
  5269. + * - Jean II */
  5270. + memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
  5271. + wrqu.addr.sa_family = ARPHRD_ETHER;
  5272. +
  5273. + /* Send event to user space */
  5274. + wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
  5275. + }
  5276. +
  5277. + netif_wake_queue(dev);
  5278. +}
  5279. +
  5280. +void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue)
  5281. +{
  5282. + struct orinoco_private *priv = ndev_priv(dev);
  5283. + struct net_device_stats *stats = &dev->stats;
  5284. + struct hermes *hw = &priv->hw;
  5285. +
  5286. + printk(KERN_WARNING "%s: Tx timeout! "
  5287. + "ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n",
  5288. + dev->name, hermes_read_regn(hw, ALLOCFID),
  5289. + hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT));
  5290. +
  5291. + stats->tx_errors++;
  5292. +
  5293. + schedule_work(&priv->reset_work);
  5294. +}
  5295. +EXPORT_SYMBOL(orinoco_tx_timeout);
  5296. +
  5297. +/********************************************************************/
  5298. +/* Rx path (data frames) */
  5299. +/********************************************************************/
  5300. +
  5301. +/* Does the frame have a SNAP header indicating it should be
  5302. + * de-encapsulated to Ethernet-II? */
  5303. +static inline int is_ethersnap(void *_hdr)
  5304. +{
  5305. + u8 *hdr = _hdr;
  5306. +
  5307. + /* We de-encapsulate all packets which, a) have SNAP headers
  5308. + * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header
  5309. + * and where b) the OUI of the SNAP header is 00:00:00 or
  5310. + * 00:00:f8 - we need both because different APs appear to use
  5311. + * different OUIs for some reason */
  5312. + return (memcmp(hdr, &encaps_hdr, 5) == 0)
  5313. + && ((hdr[5] == 0x00) || (hdr[5] == 0xf8));
  5314. +}
  5315. +
  5316. +static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac,
  5317. + int level, int noise)
  5318. +{
  5319. + struct iw_quality wstats;
  5320. + wstats.level = level - 0x95;
  5321. + wstats.noise = noise - 0x95;
  5322. + wstats.qual = (level > noise) ? (level - noise) : 0;
  5323. + wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
  5324. + /* Update spy records */
  5325. + //wireless_spy_update(dev, mac, &wstats);
  5326. +}
  5327. +
  5328. +static void orinoco_stat_gather(struct net_device *dev,
  5329. + struct sk_buff *skb,
  5330. + struct hermes_rx_descriptor *desc)
  5331. +{
  5332. + struct orinoco_private *priv = ndev_priv(dev);
  5333. +
  5334. + /* Using spy support with lots of Rx packets, like in an
  5335. + * infrastructure (AP), will really slow down everything, because
  5336. + * the MAC address must be compared to each entry of the spy list.
  5337. + * If the user really asks for it (set some address in the
  5338. + * spy list), we do it, but he will pay the price.
  5339. + * Note that to get here, you need both WIRELESS_SPY
  5340. + * compiled in AND some addresses in the list !!!
  5341. + */
  5342. + /* Note : gcc will optimise the whole section away if
  5343. + * WIRELESS_SPY is not defined... - Jean II */
  5344. + if (SPY_NUMBER(priv)) {
  5345. + orinoco_spy_gather(dev, skb_mac_header(skb) + ETH_ALEN,
  5346. + desc->signal, desc->silence);
  5347. + }
  5348. +}
  5349. +
  5350. +/*
  5351. + * orinoco_rx_monitor - handle received monitor frames.
  5352. + *
  5353. + * Arguments:
  5354. + * dev network device
  5355. + * rxfid received FID
  5356. + * desc rx descriptor of the frame
  5357. + *
  5358. + * Call context: interrupt
  5359. + */
  5360. +static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
  5361. + struct hermes_rx_descriptor *desc)
  5362. +{
  5363. + u32 hdrlen = 30; /* return full header by default */
  5364. + u32 datalen = 0;
  5365. + u16 fc;
  5366. + int err;
  5367. + int len;
  5368. + struct sk_buff *skb;
  5369. + struct orinoco_private *priv = ndev_priv(dev);
  5370. + struct net_device_stats *stats = &dev->stats;
  5371. + struct hermes *hw = &priv->hw;
  5372. +
  5373. + len = le16_to_cpu(desc->data_len);
  5374. +
  5375. + /* Determine the size of the header and the data */
  5376. + fc = le16_to_cpu(desc->frame_ctl);
  5377. + switch (fc & IEEE80211_FCTL_FTYPE) {
  5378. + case IEEE80211_FTYPE_DATA:
  5379. + if ((fc & IEEE80211_FCTL_TODS)
  5380. + && (fc & IEEE80211_FCTL_FROMDS))
  5381. + hdrlen = 30;
  5382. + else
  5383. + hdrlen = 24;
  5384. + datalen = len;
  5385. + break;
  5386. + case IEEE80211_FTYPE_MGMT:
  5387. + hdrlen = 24;
  5388. + datalen = len;
  5389. + break;
  5390. + case IEEE80211_FTYPE_CTL:
  5391. + switch (fc & IEEE80211_FCTL_STYPE) {
  5392. + case IEEE80211_STYPE_PSPOLL:
  5393. + case IEEE80211_STYPE_RTS:
  5394. + case IEEE80211_STYPE_CFEND:
  5395. + case IEEE80211_STYPE_CFENDACK:
  5396. + hdrlen = 16;
  5397. + break;
  5398. + case IEEE80211_STYPE_CTS:
  5399. + case IEEE80211_STYPE_ACK:
  5400. + hdrlen = 10;
  5401. + break;
  5402. + }
  5403. + break;
  5404. + default:
  5405. + /* Unknown frame type */
  5406. + break;
  5407. + }
  5408. +
  5409. + /* sanity check the length */
  5410. + if (datalen > IEEE80211_MAX_DATA_LEN + 12) {
  5411. + printk(KERN_DEBUG "%s: oversized monitor frame, "
  5412. + "data length = %d\n", dev->name, datalen);
  5413. + stats->rx_length_errors++;
  5414. + goto update_stats;
  5415. + }
  5416. +
  5417. + skb = dev_alloc_skb(hdrlen + datalen);
  5418. + if (!skb) {
  5419. + printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
  5420. + dev->name);
  5421. + goto update_stats;
  5422. + }
  5423. +
  5424. + /* Copy the 802.11 header to the skb */
  5425. + skb_put_data(skb, &(desc->frame_ctl), hdrlen);
  5426. + skb_reset_mac_header(skb);
  5427. +
  5428. + /* If any, copy the data from the card to the skb */
  5429. + if (datalen > 0) {
  5430. + err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
  5431. + ALIGN(datalen, 2), rxfid,
  5432. + HERMES_802_2_OFFSET);
  5433. + if (err) {
  5434. + printk(KERN_ERR "%s: error %d reading monitor frame\n",
  5435. + dev->name, err);
  5436. + goto drop;
  5437. + }
  5438. + }
  5439. +
  5440. + skb->dev = dev;
  5441. + skb->ip_summed = CHECKSUM_NONE;
  5442. + skb->pkt_type = PACKET_OTHERHOST;
  5443. + skb->protocol = cpu_to_be16(ETH_P_802_2);
  5444. +
  5445. + stats->rx_packets++;
  5446. + stats->rx_bytes += skb->len;
  5447. +
  5448. + netif_rx(skb);
  5449. + return;
  5450. +
  5451. + drop:
  5452. + dev_kfree_skb_irq(skb);
  5453. + update_stats:
  5454. + stats->rx_errors++;
  5455. + stats->rx_dropped++;
  5456. +}
  5457. +
  5458. +void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw)
  5459. +{
  5460. + struct orinoco_private *priv = ndev_priv(dev);
  5461. + struct net_device_stats *stats = &dev->stats;
  5462. + struct iw_statistics *wstats = &priv->wstats;
  5463. + struct sk_buff *skb = NULL;
  5464. + u16 rxfid, status;
  5465. + int length;
  5466. + struct hermes_rx_descriptor *desc;
  5467. + struct orinoco_rx_data *rx_data;
  5468. + int err;
  5469. +
  5470. + desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
  5471. + if (!desc)
  5472. + goto update_stats;
  5473. +
  5474. + rxfid = hermes_read_regn(hw, RXFID);
  5475. +
  5476. + err = hw->ops->bap_pread(hw, IRQ_BAP, desc, sizeof(*desc),
  5477. + rxfid, 0);
  5478. + if (err) {
  5479. + printk(KERN_ERR "%s: error %d reading Rx descriptor. "
  5480. + "Frame dropped.\n", dev->name, err);
  5481. + goto update_stats;
  5482. + }
  5483. +
  5484. + status = le16_to_cpu(desc->status);
  5485. +
  5486. + if (status & HERMES_RXSTAT_BADCRC) {
  5487. + DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
  5488. + dev->name);
  5489. + stats->rx_crc_errors++;
  5490. + goto update_stats;
  5491. + }
  5492. +
  5493. + /* Handle frames in monitor mode */
  5494. + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
  5495. + orinoco_rx_monitor(dev, rxfid, desc);
  5496. + goto out;
  5497. + }
  5498. +
  5499. + if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
  5500. + DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
  5501. + dev->name);
  5502. + wstats->discard.code++;
  5503. + goto update_stats;
  5504. + }
  5505. +
  5506. + length = le16_to_cpu(desc->data_len);
  5507. +
  5508. + /* Sanity checks */
  5509. + if (length < 3) { /* No for even an 802.2 LLC header */
  5510. + /* At least on Symbol firmware with PCF we get quite a
  5511. + lot of these legitimately - Poll frames with no
  5512. + data. */
  5513. + goto out;
  5514. + }
  5515. + if (length > IEEE80211_MAX_DATA_LEN) {
  5516. + printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n",
  5517. + dev->name, length);
  5518. + stats->rx_length_errors++;
  5519. + goto update_stats;
  5520. + }
  5521. +
  5522. + /* Payload size does not include Michael MIC. Increase payload
  5523. + * size to read it together with the data. */
  5524. + if (status & HERMES_RXSTAT_MIC)
  5525. + length += MICHAEL_MIC_LEN;
  5526. +
  5527. + /* We need space for the packet data itself, plus an ethernet
  5528. + header, plus 2 bytes so we can align the IP header on a
  5529. + 32bit boundary, plus 1 byte so we can read in odd length
  5530. + packets from the card, which has an IO granularity of 16
  5531. + bits */
  5532. + skb = dev_alloc_skb(length + ETH_HLEN + 2 + 1);
  5533. + if (!skb) {
  5534. + printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
  5535. + dev->name);
  5536. + goto update_stats;
  5537. + }
  5538. +
  5539. + /* We'll prepend the header, so reserve space for it. The worst
  5540. + case is no decapsulation, when 802.3 header is prepended and
  5541. + nothing is removed. 2 is for aligning the IP header. */
  5542. + skb_reserve(skb, ETH_HLEN + 2);
  5543. +
  5544. + err = hw->ops->bap_pread(hw, IRQ_BAP, skb_put(skb, length),
  5545. + ALIGN(length, 2), rxfid,
  5546. + HERMES_802_2_OFFSET);
  5547. + if (err) {
  5548. + printk(KERN_ERR "%s: error %d reading frame. "
  5549. + "Frame dropped.\n", dev->name, err);
  5550. + goto drop;
  5551. + }
  5552. +
  5553. + /* Add desc and skb to rx queue */
  5554. + rx_data = kzalloc(sizeof(*rx_data), GFP_ATOMIC);
  5555. + if (!rx_data)
  5556. + goto drop;
  5557. +
  5558. + rx_data->desc = desc;
  5559. + rx_data->skb = skb;
  5560. + list_add_tail(&rx_data->list, &priv->rx_list);
  5561. + tasklet_schedule(&priv->rx_tasklet);
  5562. +
  5563. + return;
  5564. +
  5565. +drop:
  5566. + dev_kfree_skb_irq(skb);
  5567. +update_stats:
  5568. + stats->rx_errors++;
  5569. + stats->rx_dropped++;
  5570. +out:
  5571. + kfree(desc);
  5572. +}
  5573. +EXPORT_SYMBOL(__orinoco_ev_rx);
  5574. +
  5575. +static void orinoco_rx(struct net_device *dev,
  5576. + struct hermes_rx_descriptor *desc,
  5577. + struct sk_buff *skb)
  5578. +{
  5579. + struct orinoco_private *priv = ndev_priv(dev);
  5580. + struct net_device_stats *stats = &dev->stats;
  5581. + u16 status, fc;
  5582. + int length;
  5583. + struct ethhdr *hdr;
  5584. +
  5585. + status = le16_to_cpu(desc->status);
  5586. + length = le16_to_cpu(desc->data_len);
  5587. + fc = le16_to_cpu(desc->frame_ctl);
  5588. +
  5589. + /* Calculate and check MIC */
  5590. + if (status & HERMES_RXSTAT_MIC) {
  5591. + struct orinoco_tkip_key *key;
  5592. + int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
  5593. + HERMES_MIC_KEY_ID_SHIFT);
  5594. + u8 mic[MICHAEL_MIC_LEN];
  5595. + u8 *rxmic;
  5596. + u8 *src = (fc & IEEE80211_FCTL_FROMDS) ?
  5597. + desc->addr3 : desc->addr2;
  5598. +
  5599. + /* Extract Michael MIC from payload */
  5600. + rxmic = skb->data + skb->len - MICHAEL_MIC_LEN;
  5601. +
  5602. + skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
  5603. + length -= MICHAEL_MIC_LEN;
  5604. +
  5605. + key = (struct orinoco_tkip_key *) priv->keys[key_id].key;
  5606. +
  5607. + if (!key) {
  5608. + printk(KERN_WARNING "%s: Received encrypted frame from "
  5609. + "%pM using key %i, but key is not installed\n",
  5610. + dev->name, src, key_id);
  5611. + goto drop;
  5612. + }
  5613. +
  5614. + orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src,
  5615. + 0, /* priority or QoS? */
  5616. + skb->data, skb->len, &mic[0]);
  5617. +
  5618. + if (memcmp(mic, rxmic,
  5619. + MICHAEL_MIC_LEN)) {
  5620. + union iwreq_data wrqu;
  5621. + struct iw_michaelmicfailure wxmic;
  5622. +
  5623. + printk(KERN_WARNING "%s: "
  5624. + "Invalid Michael MIC in data frame from %pM, "
  5625. + "using key %i\n",
  5626. + dev->name, src, key_id);
  5627. +
  5628. + /* TODO: update stats */
  5629. +
  5630. + /* Notify userspace */
  5631. + memset(&wxmic, 0, sizeof(wxmic));
  5632. + wxmic.flags = key_id & IW_MICFAILURE_KEY_ID;
  5633. + wxmic.flags |= (desc->addr1[0] & 1) ?
  5634. + IW_MICFAILURE_GROUP : IW_MICFAILURE_PAIRWISE;
  5635. + wxmic.src_addr.sa_family = ARPHRD_ETHER;
  5636. + memcpy(wxmic.src_addr.sa_data, src, ETH_ALEN);
  5637. +
  5638. + (void) orinoco_hw_get_tkip_iv(priv, key_id,
  5639. + &wxmic.tsc[0]);
  5640. +
  5641. + memset(&wrqu, 0, sizeof(wrqu));
  5642. + wrqu.data.length = sizeof(wxmic);
  5643. + wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu,
  5644. + (char *) &wxmic);
  5645. +
  5646. + goto drop;
  5647. + }
  5648. + }
  5649. +
  5650. + /* Handle decapsulation
  5651. + * In most cases, the firmware tell us about SNAP frames.
  5652. + * For some reason, the SNAP frames sent by LinkSys APs
  5653. + * are not properly recognised by most firmwares.
  5654. + * So, check ourselves */
  5655. + if (length >= ENCAPS_OVERHEAD &&
  5656. + (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
  5657. + ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
  5658. + is_ethersnap(skb->data))) {
  5659. + /* These indicate a SNAP within 802.2 LLC within
  5660. + 802.11 frame which we'll need to de-encapsulate to
  5661. + the original EthernetII frame. */
  5662. + hdr = skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
  5663. + } else {
  5664. + /* 802.3 frame - prepend 802.3 header as is */
  5665. + hdr = skb_push(skb, ETH_HLEN);
  5666. + hdr->h_proto = htons(length);
  5667. + }
  5668. + memcpy(hdr->h_dest, desc->addr1, ETH_ALEN);
  5669. + if (fc & IEEE80211_FCTL_FROMDS)
  5670. + memcpy(hdr->h_source, desc->addr3, ETH_ALEN);
  5671. + else
  5672. + memcpy(hdr->h_source, desc->addr2, ETH_ALEN);
  5673. +
  5674. + skb->protocol = eth_type_trans(skb, dev);
  5675. + skb->ip_summed = CHECKSUM_NONE;
  5676. + if (fc & IEEE80211_FCTL_TODS)
  5677. + skb->pkt_type = PACKET_OTHERHOST;
  5678. +
  5679. + /* Process the wireless stats if needed */
  5680. + orinoco_stat_gather(dev, skb, desc);
  5681. +
  5682. + /* Pass the packet to the networking stack */
  5683. + netif_rx(skb);
  5684. + stats->rx_packets++;
  5685. + stats->rx_bytes += length;
  5686. +
  5687. + return;
  5688. +
  5689. + drop:
  5690. + dev_kfree_skb(skb);
  5691. + stats->rx_errors++;
  5692. + stats->rx_dropped++;
  5693. +}
  5694. +
  5695. +static void orinoco_rx_isr_tasklet(struct tasklet_struct *t)
  5696. +{
  5697. + struct orinoco_private *priv = from_tasklet(priv, t, rx_tasklet);
  5698. + struct net_device *dev = priv->ndev;
  5699. + struct orinoco_rx_data *rx_data, *temp;
  5700. + struct hermes_rx_descriptor *desc;
  5701. + struct sk_buff *skb;
  5702. + unsigned long flags;
  5703. +
  5704. + /* orinoco_rx requires the driver lock, and we also need to
  5705. + * protect priv->rx_list, so just hold the lock over the
  5706. + * lot.
  5707. + *
  5708. + * If orinoco_lock fails, we've unplugged the card. In this
  5709. + * case just abort. */
  5710. + if (orinoco_lock(priv, &flags) != 0)
  5711. + return;
  5712. +
  5713. + /* extract desc and skb from queue */
  5714. + list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
  5715. + desc = rx_data->desc;
  5716. + skb = rx_data->skb;
  5717. + list_del(&rx_data->list);
  5718. + kfree(rx_data);
  5719. +
  5720. + orinoco_rx(dev, desc, skb);
  5721. +
  5722. + kfree(desc);
  5723. + }
  5724. +
  5725. + orinoco_unlock(priv, &flags);
  5726. +}
  5727. +
  5728. +/********************************************************************/
  5729. +/* Rx path (info frames) */
  5730. +/********************************************************************/
  5731. +
  5732. +static void print_linkstatus(struct net_device *dev, u16 status)
  5733. +{
  5734. + char *s;
  5735. +
  5736. + if (suppress_linkstatus)
  5737. + return;
  5738. +
  5739. + switch (status) {
  5740. + case HERMES_LINKSTATUS_NOT_CONNECTED:
  5741. + s = "Not Connected";
  5742. + break;
  5743. + case HERMES_LINKSTATUS_CONNECTED:
  5744. + s = "Connected";
  5745. + break;
  5746. + case HERMES_LINKSTATUS_DISCONNECTED:
  5747. + s = "Disconnected";
  5748. + break;
  5749. + case HERMES_LINKSTATUS_AP_CHANGE:
  5750. + s = "AP Changed";
  5751. + break;
  5752. + case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:
  5753. + s = "AP Out of Range";
  5754. + break;
  5755. + case HERMES_LINKSTATUS_AP_IN_RANGE:
  5756. + s = "AP In Range";
  5757. + break;
  5758. + case HERMES_LINKSTATUS_ASSOC_FAILED:
  5759. + s = "Association Failed";
  5760. + break;
  5761. + default:
  5762. + s = "UNKNOWN";
  5763. + }
  5764. +
  5765. + printk(KERN_DEBUG "%s: New link status: %s (%04x)\n",
  5766. + dev->name, s, status);
  5767. +}
  5768. +
  5769. +/* Search scan results for requested BSSID, join it if found */
  5770. +static void orinoco_join_ap(struct work_struct *work)
  5771. +{
  5772. + struct orinoco_private *priv =
  5773. + container_of(work, struct orinoco_private, join_work);
  5774. + struct net_device *dev = priv->ndev;
  5775. + struct hermes *hw = &priv->hw;
  5776. + int err;
  5777. + unsigned long flags;
  5778. + struct join_req {
  5779. + u8 bssid[ETH_ALEN];
  5780. + __le16 channel;
  5781. + } __packed req;
  5782. + const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
  5783. + struct prism2_scan_apinfo *atom = NULL;
  5784. + int offset = 4;
  5785. + int found = 0;
  5786. + u8 *buf;
  5787. + u16 len;
  5788. +
  5789. + /* Allocate buffer for scan results */
  5790. + buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
  5791. + if (!buf)
  5792. + return;
  5793. +
  5794. + if (orinoco_lock(priv, &flags) != 0)
  5795. + goto fail_lock;
  5796. +
  5797. + /* Sanity checks in case user changed something in the meantime */
  5798. + if (!priv->bssid_fixed)
  5799. + goto out;
  5800. +
  5801. + if (strlen(priv->desired_essid) == 0)
  5802. + goto out;
  5803. +
  5804. + /* Read scan results from the firmware */
  5805. + err = hw->ops->read_ltv(hw, USER_BAP,
  5806. + HERMES_RID_SCANRESULTSTABLE,
  5807. + MAX_SCAN_LEN, &len, buf);
  5808. + if (err) {
  5809. + printk(KERN_ERR "%s: Cannot read scan results\n",
  5810. + dev->name);
  5811. + goto out;
  5812. + }
  5813. +
  5814. + len = HERMES_RECLEN_TO_BYTES(len);
  5815. +
  5816. + /* Go through the scan results looking for the channel of the AP
  5817. + * we were requested to join */
  5818. + for (; offset + atom_len <= len; offset += atom_len) {
  5819. + atom = (struct prism2_scan_apinfo *) (buf + offset);
  5820. + if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {
  5821. + found = 1;
  5822. + break;
  5823. + }
  5824. + }
  5825. +
  5826. + if (!found) {
  5827. + DEBUG(1, "%s: Requested AP not found in scan results\n",
  5828. + dev->name);
  5829. + goto out;
  5830. + }
  5831. +
  5832. + memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
  5833. + req.channel = atom->channel; /* both are little-endian */
  5834. + err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
  5835. + &req);
  5836. + if (err)
  5837. + printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
  5838. +
  5839. + out:
  5840. + orinoco_unlock(priv, &flags);
  5841. +
  5842. + fail_lock:
  5843. + kfree(buf);
  5844. +}
  5845. +
  5846. +/* Send new BSSID to userspace */
  5847. +static void orinoco_send_bssid_wevent(struct orinoco_private *priv)
  5848. +{
  5849. + struct net_device *dev = priv->ndev;
  5850. + struct hermes *hw = &priv->hw;
  5851. + union iwreq_data wrqu;
  5852. + int err;
  5853. +
  5854. + err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
  5855. + ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
  5856. + if (err != 0)
  5857. + return;
  5858. +
  5859. + wrqu.ap_addr.sa_family = ARPHRD_ETHER;
  5860. +
  5861. + /* Send event to user space */
  5862. + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
  5863. +}
  5864. +
  5865. +static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv)
  5866. +{
  5867. + struct net_device *dev = priv->ndev;
  5868. + struct hermes *hw = &priv->hw;
  5869. + union iwreq_data wrqu;
  5870. + int err;
  5871. + u8 buf[88];
  5872. + u8 *ie;
  5873. +
  5874. + if (!priv->has_wpa)
  5875. + return;
  5876. +
  5877. + err = hw->ops->read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO,
  5878. + sizeof(buf), NULL, &buf);
  5879. + if (err != 0)
  5880. + return;
  5881. +
  5882. + ie = orinoco_get_wpa_ie(buf, sizeof(buf));
  5883. + if (ie) {
  5884. + int rem = sizeof(buf) - (ie - &buf[0]);
  5885. + wrqu.data.length = ie[1] + 2;
  5886. + if (wrqu.data.length > rem)
  5887. + wrqu.data.length = rem;
  5888. +
  5889. + if (wrqu.data.length)
  5890. + /* Send event to user space */
  5891. + wireless_send_event(dev, IWEVASSOCREQIE, &wrqu, ie);
  5892. + }
  5893. +}
  5894. +
  5895. +static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv)
  5896. +{
  5897. + struct net_device *dev = priv->ndev;
  5898. + struct hermes *hw = &priv->hw;
  5899. + union iwreq_data wrqu;
  5900. + int err;
  5901. + u8 buf[88]; /* TODO: verify max size or IW_GENERIC_IE_MAX */
  5902. + u8 *ie;
  5903. +
  5904. + if (!priv->has_wpa)
  5905. + return;
  5906. +
  5907. + err = hw->ops->read_ltv(hw, USER_BAP,
  5908. + HERMES_RID_CURRENT_ASSOC_RESP_INFO,
  5909. + sizeof(buf), NULL, &buf);
  5910. + if (err != 0)
  5911. + return;
  5912. +
  5913. + ie = orinoco_get_wpa_ie(buf, sizeof(buf));
  5914. + if (ie) {
  5915. + int rem = sizeof(buf) - (ie - &buf[0]);
  5916. + wrqu.data.length = ie[1] + 2;
  5917. + if (wrqu.data.length > rem)
  5918. + wrqu.data.length = rem;
  5919. +
  5920. + if (wrqu.data.length)
  5921. + /* Send event to user space */
  5922. + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, ie);
  5923. + }
  5924. +}
  5925. +
  5926. +static void orinoco_send_wevents(struct work_struct *work)
  5927. +{
  5928. + struct orinoco_private *priv =
  5929. + container_of(work, struct orinoco_private, wevent_work);
  5930. + unsigned long flags;
  5931. +
  5932. + if (orinoco_lock(priv, &flags) != 0)
  5933. + return;
  5934. +
  5935. + orinoco_send_assocreqie_wevent(priv);
  5936. + orinoco_send_assocrespie_wevent(priv);
  5937. + orinoco_send_bssid_wevent(priv);
  5938. +
  5939. + orinoco_unlock(priv, &flags);
  5940. +}
  5941. +
  5942. +static void qbuf_scan(struct orinoco_private *priv, void *buf,
  5943. + int len, int type)
  5944. +{
  5945. + struct orinoco_scan_data *sd;
  5946. + unsigned long flags;
  5947. +
  5948. + sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
  5949. + if (!sd)
  5950. + return;
  5951. +
  5952. + sd->buf = buf;
  5953. + sd->len = len;
  5954. + sd->type = type;
  5955. +
  5956. + spin_lock_irqsave(&priv->scan_lock, flags);
  5957. + list_add_tail(&sd->list, &priv->scan_list);
  5958. + spin_unlock_irqrestore(&priv->scan_lock, flags);
  5959. +
  5960. + schedule_work(&priv->process_scan);
  5961. +}
  5962. +
  5963. +static void qabort_scan(struct orinoco_private *priv)
  5964. +{
  5965. + struct orinoco_scan_data *sd;
  5966. + unsigned long flags;
  5967. +
  5968. + sd = kmalloc(sizeof(*sd), GFP_ATOMIC);
  5969. + if (!sd)
  5970. + return;
  5971. +
  5972. + sd->len = -1; /* Abort */
  5973. +
  5974. + spin_lock_irqsave(&priv->scan_lock, flags);
  5975. + list_add_tail(&sd->list, &priv->scan_list);
  5976. + spin_unlock_irqrestore(&priv->scan_lock, flags);
  5977. +
  5978. + schedule_work(&priv->process_scan);
  5979. +}
  5980. +
  5981. +static void orinoco_process_scan_results(struct work_struct *work)
  5982. +{
  5983. + struct orinoco_private *priv =
  5984. + container_of(work, struct orinoco_private, process_scan);
  5985. + struct orinoco_scan_data *sd, *temp;
  5986. + unsigned long flags;
  5987. + void *buf;
  5988. + int len;
  5989. + int type;
  5990. +
  5991. + spin_lock_irqsave(&priv->scan_lock, flags);
  5992. + list_for_each_entry_safe(sd, temp, &priv->scan_list, list) {
  5993. +
  5994. + buf = sd->buf;
  5995. + len = sd->len;
  5996. + type = sd->type;
  5997. +
  5998. + list_del(&sd->list);
  5999. + spin_unlock_irqrestore(&priv->scan_lock, flags);
  6000. + kfree(sd);
  6001. +
  6002. + if (len > 0) {
  6003. + if (type == HERMES_INQ_CHANNELINFO)
  6004. + orinoco_add_extscan_result(priv, buf, len);
  6005. + else
  6006. + orinoco_add_hostscan_results(priv, buf, len);
  6007. +
  6008. + kfree(buf);
  6009. + } else {
  6010. + /* Either abort or complete the scan */
  6011. + orinoco_scan_done(priv, (len < 0));
  6012. + }
  6013. +
  6014. + spin_lock_irqsave(&priv->scan_lock, flags);
  6015. + }
  6016. + spin_unlock_irqrestore(&priv->scan_lock, flags);
  6017. +}
  6018. +
  6019. +void __orinoco_ev_info(struct net_device *dev, struct hermes *hw)
  6020. +{
  6021. + struct orinoco_private *priv = ndev_priv(dev);
  6022. + u16 infofid;
  6023. + struct {
  6024. + __le16 len;
  6025. + __le16 type;
  6026. + } __packed info;
  6027. + int len, type;
  6028. + int err;
  6029. +
  6030. + /* This is an answer to an INQUIRE command that we did earlier,
  6031. + * or an information "event" generated by the card
  6032. + * The controller return to us a pseudo frame containing
  6033. + * the information in question - Jean II */
  6034. + infofid = hermes_read_regn(hw, INFOFID);
  6035. +
  6036. + /* Read the info frame header - don't try too hard */
  6037. + err = hw->ops->bap_pread(hw, IRQ_BAP, &info, sizeof(info),
  6038. + infofid, 0);
  6039. + if (err) {
  6040. + printk(KERN_ERR "%s: error %d reading info frame. "
  6041. + "Frame dropped.\n", dev->name, err);
  6042. + return;
  6043. + }
  6044. +
  6045. + len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));
  6046. + type = le16_to_cpu(info.type);
  6047. +
  6048. + switch (type) {
  6049. + case HERMES_INQ_TALLIES: {
  6050. + struct hermes_tallies_frame tallies;
  6051. + struct iw_statistics *wstats = &priv->wstats;
  6052. +
  6053. + if (len > sizeof(tallies)) {
  6054. + printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",
  6055. + dev->name, len);
  6056. + len = sizeof(tallies);
  6057. + }
  6058. +
  6059. + err = hw->ops->bap_pread(hw, IRQ_BAP, &tallies, len,
  6060. + infofid, sizeof(info));
  6061. + if (err)
  6062. + break;
  6063. +
  6064. + /* Increment our various counters */
  6065. + /* wstats->discard.nwid - no wrong BSSID stuff */
  6066. + wstats->discard.code +=
  6067. + le16_to_cpu(tallies.RxWEPUndecryptable);
  6068. + if (len == sizeof(tallies))
  6069. + wstats->discard.code +=
  6070. + le16_to_cpu(tallies.RxDiscards_WEPICVError) +
  6071. + le16_to_cpu(tallies.RxDiscards_WEPExcluded);
  6072. + wstats->discard.misc +=
  6073. + le16_to_cpu(tallies.TxDiscardsWrongSA);
  6074. + wstats->discard.fragment +=
  6075. + le16_to_cpu(tallies.RxMsgInBadMsgFragments);
  6076. + wstats->discard.retries +=
  6077. + le16_to_cpu(tallies.TxRetryLimitExceeded);
  6078. + /* wstats->miss.beacon - no match */
  6079. + }
  6080. + break;
  6081. + case HERMES_INQ_LINKSTATUS: {
  6082. + struct hermes_linkstatus linkstatus;
  6083. + u16 newstatus;
  6084. + int connected;
  6085. +
  6086. + if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
  6087. + break;
  6088. +
  6089. + if (len != sizeof(linkstatus)) {
  6090. + printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
  6091. + dev->name, len);
  6092. + break;
  6093. + }
  6094. +
  6095. + err = hw->ops->bap_pread(hw, IRQ_BAP, &linkstatus, len,
  6096. + infofid, sizeof(info));
  6097. + if (err)
  6098. + break;
  6099. + newstatus = le16_to_cpu(linkstatus.linkstatus);
  6100. +
  6101. + /* Symbol firmware uses "out of range" to signal that
  6102. + * the hostscan frame can be requested. */
  6103. + if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
  6104. + priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
  6105. + priv->has_hostscan && priv->scan_request) {
  6106. + hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
  6107. + break;
  6108. + }
  6109. +
  6110. + connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
  6111. + || (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
  6112. + || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
  6113. +
  6114. + if (connected)
  6115. + netif_carrier_on(dev);
  6116. + else if (!ignore_disconnect)
  6117. + netif_carrier_off(dev);
  6118. +
  6119. + if (newstatus != priv->last_linkstatus) {
  6120. + priv->last_linkstatus = newstatus;
  6121. + print_linkstatus(dev, newstatus);
  6122. + /* The info frame contains only one word which is the
  6123. + * status (see hermes.h). The status is pretty boring
  6124. + * in itself, that's why we export the new BSSID...
  6125. + * Jean II */
  6126. + schedule_work(&priv->wevent_work);
  6127. + }
  6128. + }
  6129. + break;
  6130. + case HERMES_INQ_SCAN:
  6131. + if (!priv->scan_request && priv->bssid_fixed &&
  6132. + priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
  6133. + schedule_work(&priv->join_work);
  6134. + break;
  6135. + }
  6136. + fallthrough;
  6137. + case HERMES_INQ_HOSTSCAN:
  6138. + case HERMES_INQ_HOSTSCAN_SYMBOL: {
  6139. + /* Result of a scanning. Contains information about
  6140. + * cells in the vicinity - Jean II */
  6141. + unsigned char *buf;
  6142. +
  6143. + /* Sanity check */
  6144. + if (len > 4096) {
  6145. + printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
  6146. + dev->name, len);
  6147. + qabort_scan(priv);
  6148. + break;
  6149. + }
  6150. +
  6151. + /* Allocate buffer for results */
  6152. + buf = kmalloc(len, GFP_ATOMIC);
  6153. + if (buf == NULL) {
  6154. + /* No memory, so can't printk()... */
  6155. + qabort_scan(priv);
  6156. + break;
  6157. + }
  6158. +
  6159. + /* Read scan data */
  6160. + err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) buf, len,
  6161. + infofid, sizeof(info));
  6162. + if (err) {
  6163. + kfree(buf);
  6164. + qabort_scan(priv);
  6165. + break;
  6166. + }
  6167. +
  6168. +#ifdef ORINOCO_DEBUG
  6169. + {
  6170. + int i;
  6171. + printk(KERN_DEBUG "Scan result [%02X", buf[0]);
  6172. + for (i = 1; i < (len * 2); i++)
  6173. + printk(":%02X", buf[i]);
  6174. + printk("]\n");
  6175. + }
  6176. +#endif /* ORINOCO_DEBUG */
  6177. +
  6178. + qbuf_scan(priv, buf, len, type);
  6179. + }
  6180. + break;
  6181. + case HERMES_INQ_CHANNELINFO:
  6182. + {
  6183. + struct agere_ext_scan_info *bss;
  6184. +
  6185. + if (!priv->scan_request) {
  6186. + printk(KERN_DEBUG "%s: Got chaninfo without scan, "
  6187. + "len=%d\n", dev->name, len);
  6188. + break;
  6189. + }
  6190. +
  6191. + /* An empty result indicates that the scan is complete */
  6192. + if (len == 0) {
  6193. + qbuf_scan(priv, NULL, len, type);
  6194. + break;
  6195. + }
  6196. +
  6197. + /* Sanity check */
  6198. + else if (len < (offsetof(struct agere_ext_scan_info,
  6199. + data) + 2)) {
  6200. + /* Drop this result now so we don't have to
  6201. + * keep checking later */
  6202. + printk(KERN_WARNING
  6203. + "%s: Ext scan results too short (%d bytes)\n",
  6204. + dev->name, len);
  6205. + break;
  6206. + }
  6207. +
  6208. + bss = kmalloc(len, GFP_ATOMIC);
  6209. + if (bss == NULL)
  6210. + break;
  6211. +
  6212. + /* Read scan data */
  6213. + err = hw->ops->bap_pread(hw, IRQ_BAP, (void *) bss, len,
  6214. + infofid, sizeof(info));
  6215. + if (err)
  6216. + kfree(bss);
  6217. + else
  6218. + qbuf_scan(priv, bss, len, type);
  6219. +
  6220. + break;
  6221. + }
  6222. + case HERMES_INQ_SEC_STAT_AGERE:
  6223. + /* Security status (Agere specific) */
  6224. + /* Ignore this frame for now */
  6225. + if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
  6226. + break;
  6227. + fallthrough;
  6228. + default:
  6229. + printk(KERN_DEBUG "%s: Unknown information frame received: "
  6230. + "type 0x%04x, length %d\n", dev->name, type, len);
  6231. + /* We don't actually do anything about it */
  6232. + break;
  6233. + }
  6234. +}
  6235. +EXPORT_SYMBOL(__orinoco_ev_info);
  6236. +
  6237. +static void __orinoco_ev_infdrop(struct net_device *dev, struct hermes *hw)
  6238. +{
  6239. + if (net_ratelimit())
  6240. + printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);
  6241. +}
  6242. +
  6243. +/********************************************************************/
  6244. +/* Internal hardware control routines */
  6245. +/********************************************************************/
  6246. +
  6247. +static int __orinoco_up(struct orinoco_private *priv)
  6248. +{
  6249. + struct net_device *dev = priv->ndev;
  6250. + struct hermes *hw = &priv->hw;
  6251. + int err;
  6252. +
  6253. + netif_carrier_off(dev); /* just to make sure */
  6254. +
  6255. + err = __orinoco_commit(priv);
  6256. + if (err) {
  6257. + printk(KERN_ERR "%s: Error %d configuring card\n",
  6258. + dev->name, err);
  6259. + return err;
  6260. + }
  6261. +
  6262. + /* Fire things up again */
  6263. + hermes_set_irqmask(hw, ORINOCO_INTEN);
  6264. + err = hermes_enable_port(hw, 0);
  6265. + if (err) {
  6266. + printk(KERN_ERR "%s: Error %d enabling MAC port\n",
  6267. + dev->name, err);
  6268. + return err;
  6269. + }
  6270. +
  6271. + netif_start_queue(dev);
  6272. +
  6273. + return 0;
  6274. +}
  6275. +
  6276. +static int __orinoco_down(struct orinoco_private *priv)
  6277. +{
  6278. + struct net_device *dev = priv->ndev;
  6279. + struct hermes *hw = &priv->hw;
  6280. + int err;
  6281. +
  6282. + netif_stop_queue(dev);
  6283. +
  6284. + if (!priv->hw_unavailable) {
  6285. + if (!priv->broken_disableport) {
  6286. + err = hermes_disable_port(hw, 0);
  6287. + if (err) {
  6288. + /* Some firmwares (e.g. Intersil 1.3.x) seem
  6289. + * to have problems disabling the port, oh
  6290. + * well, too bad. */
  6291. + printk(KERN_WARNING "%s: Error %d disabling MAC port\n",
  6292. + dev->name, err);
  6293. + priv->broken_disableport = 1;
  6294. + }
  6295. + }
  6296. + hermes_set_irqmask(hw, 0);
  6297. + hermes_write_regn(hw, EVACK, 0xffff);
  6298. + }
  6299. +
  6300. + orinoco_scan_done(priv, true);
  6301. +
  6302. + /* firmware will have to reassociate */
  6303. + netif_carrier_off(dev);
  6304. + priv->last_linkstatus = 0xffff;
  6305. +
  6306. + return 0;
  6307. +}
  6308. +
  6309. +static int orinoco_reinit_firmware(struct orinoco_private *priv)
  6310. +{
  6311. + struct hermes *hw = &priv->hw;
  6312. + int err;
  6313. +
  6314. + err = hw->ops->init(hw);
  6315. + if (priv->do_fw_download && !err) {
  6316. + err = orinoco_download(priv);
  6317. + if (err)
  6318. + priv->do_fw_download = 0;
  6319. + }
  6320. + if (!err)
  6321. + err = orinoco_hw_allocate_fid(priv);
  6322. +
  6323. + return err;
  6324. +}
  6325. +
  6326. +static int
  6327. +__orinoco_set_multicast_list(struct net_device *dev)
  6328. +{
  6329. + struct orinoco_private *priv = ndev_priv(dev);
  6330. + int err = 0;
  6331. + int promisc, mc_count;
  6332. +
  6333. + /* The Hermes doesn't seem to have an allmulti mode, so we go
  6334. + * into promiscuous mode and let the upper levels deal. */
  6335. + if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
  6336. + (netdev_mc_count(dev) > MAX_MULTICAST(priv))) {
  6337. + promisc = 1;
  6338. + mc_count = 0;
  6339. + } else {
  6340. + promisc = 0;
  6341. + mc_count = netdev_mc_count(dev);
  6342. + }
  6343. +
  6344. + err = __orinoco_hw_set_multicast_list(priv, dev, mc_count, promisc);
  6345. +
  6346. + return err;
  6347. +}
  6348. +
  6349. +/* This must be called from user context, without locks held - use
  6350. + * schedule_work() */
  6351. +void orinoco_reset(struct work_struct *work)
  6352. +{
  6353. + struct orinoco_private *priv =
  6354. + container_of(work, struct orinoco_private, reset_work);
  6355. + struct net_device *dev = priv->ndev;
  6356. + struct hermes *hw = &priv->hw;
  6357. + int err;
  6358. + unsigned long flags;
  6359. +
  6360. + if (orinoco_lock(priv, &flags) != 0)
  6361. + /* When the hardware becomes available again, whatever
  6362. + * detects that is responsible for re-initializing
  6363. + * it. So no need for anything further */
  6364. + return;
  6365. +
  6366. + netif_stop_queue(dev);
  6367. +
  6368. + /* Shut off interrupts. Depending on what state the hardware
  6369. + * is in, this might not work, but we'll try anyway */
  6370. + hermes_set_irqmask(hw, 0);
  6371. + hermes_write_regn(hw, EVACK, 0xffff);
  6372. +
  6373. + priv->hw_unavailable++;
  6374. + priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */
  6375. + netif_carrier_off(dev);
  6376. +
  6377. + orinoco_unlock(priv, &flags);
  6378. +
  6379. + /* Scanning support: Notify scan cancellation */
  6380. + orinoco_scan_done(priv, true);
  6381. +
  6382. + if (priv->hard_reset) {
  6383. + err = (*priv->hard_reset)(priv);
  6384. + if (err) {
  6385. + printk(KERN_ERR "%s: orinoco_reset: Error %d "
  6386. + "performing hard reset\n", dev->name, err);
  6387. + goto disable;
  6388. + }
  6389. + }
  6390. +
  6391. + err = orinoco_reinit_firmware(priv);
  6392. + if (err) {
  6393. + printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n",
  6394. + dev->name, err);
  6395. + goto disable;
  6396. + }
  6397. +
  6398. + /* This has to be called from user context */
  6399. + orinoco_lock_irq(priv);
  6400. +
  6401. + priv->hw_unavailable--;
  6402. +
  6403. + /* priv->open or priv->hw_unavailable might have changed while
  6404. + * we dropped the lock */
  6405. + if (priv->open && (!priv->hw_unavailable)) {
  6406. + err = __orinoco_up(priv);
  6407. + if (err) {
  6408. + printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n",
  6409. + dev->name, err);
  6410. + } else
  6411. + netif_trans_update(dev);
  6412. + }
  6413. +
  6414. + orinoco_unlock_irq(priv);
  6415. +
  6416. + return;
  6417. + disable:
  6418. + hermes_set_irqmask(hw, 0);
  6419. + netif_device_detach(dev);
  6420. + printk(KERN_ERR "%s: Device has been disabled!\n", dev->name);
  6421. +}
  6422. +
  6423. +static int __orinoco_commit(struct orinoco_private *priv)
  6424. +{
  6425. + struct net_device *dev = priv->ndev;
  6426. + int err = 0;
  6427. +
  6428. + /* If we've called commit, we are reconfiguring or bringing the
  6429. + * interface up. Maintaining countermeasures across this would
  6430. + * be confusing, so note that we've disabled them. The port will
  6431. + * be enabled later in orinoco_commit or __orinoco_up. */
  6432. + priv->tkip_cm_active = 0;
  6433. +
  6434. + err = orinoco_hw_program_rids(priv);
  6435. +
  6436. + /* FIXME: what about netif_tx_lock */
  6437. + (void) __orinoco_set_multicast_list(dev);
  6438. +
  6439. + return err;
  6440. +}
  6441. +
  6442. +/* Ensures configuration changes are applied. May result in a reset.
  6443. + * The caller should hold priv->lock
  6444. + */
  6445. +int orinoco_commit(struct orinoco_private *priv)
  6446. +{
  6447. + struct net_device *dev = priv->ndev;
  6448. + struct hermes *hw = &priv->hw;
  6449. + int err;
  6450. +
  6451. + if (priv->broken_disableport) {
  6452. + schedule_work(&priv->reset_work);
  6453. + return 0;
  6454. + }
  6455. +
  6456. + err = hermes_disable_port(hw, 0);
  6457. + if (err) {
  6458. + printk(KERN_WARNING "%s: Unable to disable port "
  6459. + "while reconfiguring card\n", dev->name);
  6460. + priv->broken_disableport = 1;
  6461. + goto out;
  6462. + }
  6463. +
  6464. + err = __orinoco_commit(priv);
  6465. + if (err) {
  6466. + printk(KERN_WARNING "%s: Unable to reconfigure card\n",
  6467. + dev->name);
  6468. + goto out;
  6469. + }
  6470. +
  6471. + err = hermes_enable_port(hw, 0);
  6472. + if (err) {
  6473. + printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
  6474. + dev->name);
  6475. + goto out;
  6476. + }
  6477. +
  6478. + out:
  6479. + if (err) {
  6480. + printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
  6481. + schedule_work(&priv->reset_work);
  6482. + err = 0;
  6483. + }
  6484. + return err;
  6485. +}
  6486. +
  6487. +/********************************************************************/
  6488. +/* Interrupt handler */
  6489. +/********************************************************************/
  6490. +
  6491. +static void __orinoco_ev_tick(struct net_device *dev, struct hermes *hw)
  6492. +{
  6493. + printk(KERN_DEBUG "%s: TICK\n", dev->name);
  6494. +}
  6495. +
  6496. +static void __orinoco_ev_wterr(struct net_device *dev, struct hermes *hw)
  6497. +{
  6498. + /* This seems to happen a fair bit under load, but ignoring it
  6499. + seems to work fine...*/
  6500. + printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n",
  6501. + dev->name);
  6502. +}
  6503. +
  6504. +irqreturn_t orinoco_interrupt(int irq, void *dev_id)
  6505. +{
  6506. + struct orinoco_private *priv = dev_id;
  6507. + struct net_device *dev = priv->ndev;
  6508. + struct hermes *hw = &priv->hw;
  6509. + int count = MAX_IRQLOOPS_PER_IRQ;
  6510. + u16 evstat, events;
  6511. + /* These are used to detect a runaway interrupt situation.
  6512. + *
  6513. + * If we get more than MAX_IRQLOOPS_PER_JIFFY iterations in a jiffy,
  6514. + * we panic and shut down the hardware
  6515. + */
  6516. + /* jiffies value the last time we were called */
  6517. + static int last_irq_jiffy; /* = 0 */
  6518. + static int loops_this_jiffy; /* = 0 */
  6519. + unsigned long flags;
  6520. +
  6521. + if (orinoco_lock(priv, &flags) != 0) {
  6522. + /* If hw is unavailable - we don't know if the irq was
  6523. + * for us or not */
  6524. + return IRQ_HANDLED;
  6525. + }
  6526. +
  6527. + evstat = hermes_read_regn(hw, EVSTAT);
  6528. + events = evstat & hw->inten;
  6529. + if (!events) {
  6530. + orinoco_unlock(priv, &flags);
  6531. + return IRQ_NONE;
  6532. + }
  6533. +
  6534. + if (jiffies != last_irq_jiffy)
  6535. + loops_this_jiffy = 0;
  6536. + last_irq_jiffy = jiffies;
  6537. +
  6538. + while (events && count--) {
  6539. + if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) {
  6540. + printk(KERN_WARNING "%s: IRQ handler is looping too "
  6541. + "much! Resetting.\n", dev->name);
  6542. + /* Disable interrupts for now */
  6543. + hermes_set_irqmask(hw, 0);
  6544. + schedule_work(&priv->reset_work);
  6545. + break;
  6546. + }
  6547. +
  6548. + /* Check the card hasn't been removed */
  6549. + if (!hermes_present(hw)) {
  6550. + DEBUG(0, "orinoco_interrupt(): card removed\n");
  6551. + break;
  6552. + }
  6553. +
  6554. + if (events & HERMES_EV_TICK)
  6555. + __orinoco_ev_tick(dev, hw);
  6556. + if (events & HERMES_EV_WTERR)
  6557. + __orinoco_ev_wterr(dev, hw);
  6558. + if (events & HERMES_EV_INFDROP)
  6559. + __orinoco_ev_infdrop(dev, hw);
  6560. + if (events & HERMES_EV_INFO)
  6561. + __orinoco_ev_info(dev, hw);
  6562. + if (events & HERMES_EV_RX)
  6563. + __orinoco_ev_rx(dev, hw);
  6564. + if (events & HERMES_EV_TXEXC)
  6565. + __orinoco_ev_txexc(dev, hw);
  6566. + if (events & HERMES_EV_TX)
  6567. + __orinoco_ev_tx(dev, hw);
  6568. + if (events & HERMES_EV_ALLOC)
  6569. + __orinoco_ev_alloc(dev, hw);
  6570. +
  6571. + hermes_write_regn(hw, EVACK, evstat);
  6572. +
  6573. + evstat = hermes_read_regn(hw, EVSTAT);
  6574. + events = evstat & hw->inten;
  6575. + }
  6576. +
  6577. + orinoco_unlock(priv, &flags);
  6578. + return IRQ_HANDLED;
  6579. +}
  6580. +EXPORT_SYMBOL(orinoco_interrupt);
  6581. +
  6582. +/********************************************************************/
  6583. +/* Power management */
  6584. +/********************************************************************/
  6585. +#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT)
  6586. +static int orinoco_pm_notifier(struct notifier_block *notifier,
  6587. + unsigned long pm_event,
  6588. + void *unused)
  6589. +{
  6590. + struct orinoco_private *priv = container_of(notifier,
  6591. + struct orinoco_private,
  6592. + pm_notifier);
  6593. +
  6594. + /* All we need to do is cache the firmware before suspend, and
  6595. + * release it when we come out.
  6596. + *
  6597. + * Only need to do this if we're downloading firmware. */
  6598. + if (!priv->do_fw_download)
  6599. + return NOTIFY_DONE;
  6600. +
  6601. + switch (pm_event) {
  6602. + case PM_HIBERNATION_PREPARE:
  6603. + case PM_SUSPEND_PREPARE:
  6604. + orinoco_cache_fw(priv, 0);
  6605. + break;
  6606. +
  6607. + case PM_POST_RESTORE:
  6608. + /* Restore from hibernation failed. We need to clean
  6609. + * up in exactly the same way, so fall through. */
  6610. + case PM_POST_HIBERNATION:
  6611. + case PM_POST_SUSPEND:
  6612. + orinoco_uncache_fw(priv);
  6613. + break;
  6614. +
  6615. + case PM_RESTORE_PREPARE:
  6616. + default:
  6617. + break;
  6618. + }
  6619. +
  6620. + return NOTIFY_DONE;
  6621. +}
  6622. +
  6623. +static void orinoco_register_pm_notifier(struct orinoco_private *priv)
  6624. +{
  6625. + priv->pm_notifier.notifier_call = orinoco_pm_notifier;
  6626. + register_pm_notifier(&priv->pm_notifier);
  6627. +}
  6628. +
  6629. +static void orinoco_unregister_pm_notifier(struct orinoco_private *priv)
  6630. +{
  6631. + unregister_pm_notifier(&priv->pm_notifier);
  6632. +}
  6633. +#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
  6634. +#define orinoco_register_pm_notifier(priv) do { } while (0)
  6635. +#define orinoco_unregister_pm_notifier(priv) do { } while (0)
  6636. +#endif
  6637. +
  6638. +/********************************************************************/
  6639. +/* Initialization */
  6640. +/********************************************************************/
  6641. +
  6642. +int orinoco_init(struct orinoco_private *priv)
  6643. +{
  6644. + struct device *dev = priv->dev;
  6645. + struct wiphy *wiphy = priv_to_wiphy(priv);
  6646. + struct hermes *hw = &priv->hw;
  6647. + int err = 0;
  6648. +
  6649. + /* No need to lock, the hw_unavailable flag is already set in
  6650. + * alloc_orinocodev() */
  6651. + priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN;
  6652. +
  6653. + /* Initialize the firmware */
  6654. + err = hw->ops->init(hw);
  6655. + if (err != 0) {
  6656. + dev_err(dev, "Failed to initialize firmware (err = %d)\n",
  6657. + err);
  6658. + goto out;
  6659. + }
  6660. +
  6661. + err = determine_fw_capabilities(priv, wiphy->fw_version,
  6662. + sizeof(wiphy->fw_version),
  6663. + &wiphy->hw_version);
  6664. + if (err != 0) {
  6665. + dev_err(dev, "Incompatible firmware, aborting\n");
  6666. + goto out;
  6667. + }
  6668. +
  6669. + if (priv->do_fw_download) {
  6670. +#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT
  6671. + orinoco_cache_fw(priv, 0);
  6672. +#endif
  6673. +
  6674. + err = orinoco_download(priv);
  6675. + if (err)
  6676. + priv->do_fw_download = 0;
  6677. +
  6678. + /* Check firmware version again */
  6679. + err = determine_fw_capabilities(priv, wiphy->fw_version,
  6680. + sizeof(wiphy->fw_version),
  6681. + &wiphy->hw_version);
  6682. + if (err != 0) {
  6683. + dev_err(dev, "Incompatible firmware, aborting\n");
  6684. + goto out;
  6685. + }
  6686. + }
  6687. +
  6688. + if (priv->has_port3)
  6689. + dev_info(dev, "Ad-hoc demo mode supported\n");
  6690. + if (priv->has_ibss)
  6691. + dev_info(dev, "IEEE standard IBSS ad-hoc mode supported\n");
  6692. + if (priv->has_wep)
  6693. + dev_info(dev, "WEP supported, %s-bit key\n",
  6694. + priv->has_big_wep ? "104" : "40");
  6695. + if (priv->has_wpa) {
  6696. + dev_info(dev, "WPA-PSK supported\n");
  6697. + if (orinoco_mic_init(priv)) {
  6698. + dev_err(dev, "Failed to setup MIC crypto algorithm. "
  6699. + "Disabling WPA support\n");
  6700. + priv->has_wpa = 0;
  6701. + }
  6702. + }
  6703. +
  6704. + err = orinoco_hw_read_card_settings(priv, wiphy->perm_addr);
  6705. + if (err)
  6706. + goto out;
  6707. +
  6708. + err = orinoco_hw_allocate_fid(priv);
  6709. + if (err) {
  6710. + dev_err(dev, "Failed to allocate NIC buffer!\n");
  6711. + goto out;
  6712. + }
  6713. +
  6714. + /* Set up the default configuration */
  6715. + priv->iw_mode = NL80211_IFTYPE_STATION;
  6716. + /* By default use IEEE/IBSS ad-hoc mode if we have it */
  6717. + priv->prefer_port3 = priv->has_port3 && (!priv->has_ibss);
  6718. + set_port_type(priv);
  6719. + priv->channel = 0; /* use firmware default */
  6720. +
  6721. + priv->promiscuous = 0;
  6722. + priv->encode_alg = ORINOCO_ALG_NONE;
  6723. + priv->tx_key = 0;
  6724. + priv->wpa_enabled = 0;
  6725. + priv->tkip_cm_active = 0;
  6726. + priv->key_mgmt = 0;
  6727. + priv->wpa_ie_len = 0;
  6728. + priv->wpa_ie = NULL;
  6729. +
  6730. + if (orinoco_wiphy_register(wiphy)) {
  6731. + err = -ENODEV;
  6732. + goto out;
  6733. + }
  6734. +
  6735. + /* Make the hardware available, as long as it hasn't been
  6736. + * removed elsewhere (e.g. by PCMCIA hot unplug) */
  6737. + orinoco_lock_irq(priv);
  6738. + priv->hw_unavailable--;
  6739. + orinoco_unlock_irq(priv);
  6740. +
  6741. + dev_dbg(dev, "Ready\n");
  6742. +
  6743. + out:
  6744. + return err;
  6745. +}
  6746. +EXPORT_SYMBOL(orinoco_init);
  6747. +
  6748. +static const struct net_device_ops orinoco_netdev_ops = {
  6749. + .ndo_open = orinoco_open,
  6750. + .ndo_stop = orinoco_stop,
  6751. + .ndo_start_xmit = orinoco_xmit,
  6752. + .ndo_set_rx_mode = orinoco_set_multicast_list,
  6753. + .ndo_change_mtu = orinoco_change_mtu,
  6754. + .ndo_set_mac_address = eth_mac_addr,
  6755. + .ndo_validate_addr = eth_validate_addr,
  6756. + .ndo_tx_timeout = orinoco_tx_timeout,
  6757. +};
  6758. +
  6759. +/* Allocate private data.
  6760. + *
  6761. + * This driver has a number of structures associated with it
  6762. + * netdev - Net device structure for each network interface
  6763. + * wiphy - structure associated with wireless phy
  6764. + * wireless_dev (wdev) - structure for each wireless interface
  6765. + * hw - structure for hermes chip info
  6766. + * card - card specific structure for use by the card driver
  6767. + * (airport, orinoco_cs)
  6768. + * priv - orinoco private data
  6769. + * device - generic linux device structure
  6770. + *
  6771. + * +---------+ +---------+
  6772. + * | wiphy | | netdev |
  6773. + * | +-------+ | +-------+
  6774. + * | | priv | | | wdev |
  6775. + * | | +-----+ +-+-------+
  6776. + * | | | hw |
  6777. + * | +-+-----+
  6778. + * | | card |
  6779. + * +-+-------+
  6780. + *
  6781. + * priv has a link to netdev and device
  6782. + * wdev has a link to wiphy
  6783. + */
  6784. +struct orinoco_private
  6785. +*alloc_orinocodev(int sizeof_card,
  6786. + struct device *device,
  6787. + int (*hard_reset)(struct orinoco_private *),
  6788. + int (*stop_fw)(struct orinoco_private *, int))
  6789. +{
  6790. + struct orinoco_private *priv;
  6791. + struct wiphy *wiphy;
  6792. +
  6793. + /* allocate wiphy
  6794. + * NOTE: We only support a single virtual interface
  6795. + * but this may change when monitor mode is added
  6796. + */
  6797. + wiphy = wiphy_new(&orinoco_cfg_ops,
  6798. + sizeof(struct orinoco_private) + sizeof_card);
  6799. + if (!wiphy)
  6800. + return NULL;
  6801. +
  6802. + priv = wiphy_priv(wiphy);
  6803. + priv->dev = device;
  6804. +
  6805. + if (sizeof_card)
  6806. + priv->card = (void *)((unsigned long)priv
  6807. + + sizeof(struct orinoco_private));
  6808. + else
  6809. + priv->card = NULL;
  6810. +
  6811. + orinoco_wiphy_init(wiphy);
  6812. +
  6813. +#ifdef WIRELESS_SPY
  6814. + priv->wireless_data.spy_data = &priv->spy_data;
  6815. +#endif
  6816. +
  6817. + /* Set up default callbacks */
  6818. + priv->hard_reset = hard_reset;
  6819. + priv->stop_fw = stop_fw;
  6820. +
  6821. + spin_lock_init(&priv->lock);
  6822. + priv->open = 0;
  6823. + priv->hw_unavailable = 1; /* orinoco_init() must clear this
  6824. + * before anything else touches the
  6825. + * hardware */
  6826. + INIT_WORK(&priv->reset_work, orinoco_reset);
  6827. + INIT_WORK(&priv->join_work, orinoco_join_ap);
  6828. + INIT_WORK(&priv->wevent_work, orinoco_send_wevents);
  6829. +
  6830. + INIT_LIST_HEAD(&priv->rx_list);
  6831. + tasklet_setup(&priv->rx_tasklet, orinoco_rx_isr_tasklet);
  6832. +
  6833. + spin_lock_init(&priv->scan_lock);
  6834. + INIT_LIST_HEAD(&priv->scan_list);
  6835. + INIT_WORK(&priv->process_scan, orinoco_process_scan_results);
  6836. +
  6837. + priv->last_linkstatus = 0xffff;
  6838. +
  6839. +#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
  6840. + priv->cached_pri_fw = NULL;
  6841. + priv->cached_fw = NULL;
  6842. +#endif
  6843. +
  6844. + /* Register PM notifiers */
  6845. + orinoco_register_pm_notifier(priv);
  6846. +
  6847. + return priv;
  6848. +}
  6849. +EXPORT_SYMBOL(alloc_orinocodev);
  6850. +
  6851. +/* We can only support a single interface. We provide a separate
  6852. + * function to set it up to distinguish between hardware
  6853. + * initialisation and interface setup.
  6854. + *
  6855. + * The base_addr and irq parameters are passed on to netdev for use
  6856. + * with SIOCGIFMAP.
  6857. + */
  6858. +int orinoco_if_add(struct orinoco_private *priv,
  6859. + unsigned long base_addr,
  6860. + unsigned int irq,
  6861. + const struct net_device_ops *ops)
  6862. +{
  6863. + struct wiphy *wiphy = priv_to_wiphy(priv);
  6864. + struct wireless_dev *wdev;
  6865. + struct net_device *dev;
  6866. + int ret;
  6867. +
  6868. + dev = alloc_etherdev(sizeof(struct wireless_dev));
  6869. +
  6870. + if (!dev)
  6871. + return -ENOMEM;
  6872. +
  6873. + /* Initialise wireless_dev */
  6874. + wdev = netdev_priv(dev);
  6875. + wdev->wiphy = wiphy;
  6876. + wdev->iftype = NL80211_IFTYPE_STATION;
  6877. +
  6878. + /* Setup / override net_device fields */
  6879. + dev->ieee80211_ptr = wdev;
  6880. + dev->watchdog_timeo = HZ; /* 1 second timeout */
  6881. + dev->wireless_handlers = &orinoco_handler_def;
  6882. +#ifdef WIRELESS_SPY
  6883. + dev->wireless_data = &priv->wireless_data;
  6884. +#endif
  6885. + /* Default to standard ops if not set */
  6886. + if (ops)
  6887. + dev->netdev_ops = ops;
  6888. + else
  6889. + dev->netdev_ops = &orinoco_netdev_ops;
  6890. +
  6891. + /* we use the default eth_mac_addr for setting the MAC addr */
  6892. +
  6893. + /* Reserve space in skb for the SNAP header */
  6894. + dev->needed_headroom = ENCAPS_OVERHEAD;
  6895. +
  6896. + netif_carrier_off(dev);
  6897. +
  6898. + eth_hw_addr_set(dev, wiphy->perm_addr);
  6899. +
  6900. + dev->base_addr = base_addr;
  6901. + dev->irq = irq;
  6902. +
  6903. + dev->min_mtu = ORINOCO_MIN_MTU;
  6904. + dev->max_mtu = ORINOCO_MAX_MTU;
  6905. +
  6906. + SET_NETDEV_DEV(dev, priv->dev);
  6907. + ret = register_netdev(dev);
  6908. + if (ret)
  6909. + goto fail;
  6910. +
  6911. + priv->ndev = dev;
  6912. +
  6913. + /* Report what we've done */
  6914. + dev_dbg(priv->dev, "Registered interface %s.\n", dev->name);
  6915. +
  6916. + return 0;
  6917. +
  6918. + fail:
  6919. + free_netdev(dev);
  6920. + return ret;
  6921. +}
  6922. +EXPORT_SYMBOL(orinoco_if_add);
  6923. +
  6924. +void orinoco_if_del(struct orinoco_private *priv)
  6925. +{
  6926. + struct net_device *dev = priv->ndev;
  6927. +
  6928. + unregister_netdev(dev);
  6929. + free_netdev(dev);
  6930. +}
  6931. +EXPORT_SYMBOL(orinoco_if_del);
  6932. +
  6933. +void free_orinocodev(struct orinoco_private *priv)
  6934. +{
  6935. + struct wiphy *wiphy = priv_to_wiphy(priv);
  6936. + struct orinoco_rx_data *rx_data, *temp;
  6937. + struct orinoco_scan_data *sd, *sdtemp;
  6938. +
  6939. + /* If the tasklet is scheduled when we call tasklet_kill it
  6940. + * will run one final time. However the tasklet will only
  6941. + * drain priv->rx_list if the hw is still available. */
  6942. + tasklet_kill(&priv->rx_tasklet);
  6943. +
  6944. + /* Explicitly drain priv->rx_list */
  6945. + list_for_each_entry_safe(rx_data, temp, &priv->rx_list, list) {
  6946. + list_del(&rx_data->list);
  6947. +
  6948. + dev_kfree_skb(rx_data->skb);
  6949. + kfree(rx_data->desc);
  6950. + kfree(rx_data);
  6951. + }
  6952. +
  6953. + cancel_work_sync(&priv->process_scan);
  6954. + /* Explicitly drain priv->scan_list */
  6955. + list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
  6956. + list_del(&sd->list);
  6957. +
  6958. + if (sd->len > 0)
  6959. + kfree(sd->buf);
  6960. + kfree(sd);
  6961. + }
  6962. +
  6963. + orinoco_unregister_pm_notifier(priv);
  6964. + orinoco_uncache_fw(priv);
  6965. +
  6966. + priv->wpa_ie_len = 0;
  6967. + kfree(priv->wpa_ie);
  6968. + orinoco_mic_free(priv);
  6969. + wiphy_free(wiphy);
  6970. +}
  6971. +EXPORT_SYMBOL(free_orinocodev);
  6972. +
  6973. +int orinoco_up(struct orinoco_private *priv)
  6974. +{
  6975. + struct net_device *dev = priv->ndev;
  6976. + unsigned long flags;
  6977. + int err;
  6978. +
  6979. + priv->hw.ops->lock_irqsave(&priv->lock, &flags);
  6980. +
  6981. + err = orinoco_reinit_firmware(priv);
  6982. + if (err) {
  6983. + printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
  6984. + dev->name, err);
  6985. + goto exit;
  6986. + }
  6987. +
  6988. + netif_device_attach(dev);
  6989. + priv->hw_unavailable--;
  6990. +
  6991. + if (priv->open && !priv->hw_unavailable) {
  6992. + err = __orinoco_up(priv);
  6993. + if (err)
  6994. + printk(KERN_ERR "%s: Error %d restarting card\n",
  6995. + dev->name, err);
  6996. + }
  6997. +
  6998. +exit:
  6999. + priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
  7000. +
  7001. + return 0;
  7002. +}
  7003. +EXPORT_SYMBOL(orinoco_up);
  7004. +
  7005. +void orinoco_down(struct orinoco_private *priv)
  7006. +{
  7007. + struct net_device *dev = priv->ndev;
  7008. + unsigned long flags;
  7009. + int err;
  7010. +
  7011. + priv->hw.ops->lock_irqsave(&priv->lock, &flags);
  7012. + err = __orinoco_down(priv);
  7013. + if (err)
  7014. + printk(KERN_WARNING "%s: Error %d downing interface\n",
  7015. + dev->name, err);
  7016. +
  7017. + netif_device_detach(dev);
  7018. + priv->hw_unavailable++;
  7019. + priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
  7020. +}
  7021. +EXPORT_SYMBOL(orinoco_down);
  7022. +
  7023. +/********************************************************************/
  7024. +/* Module initialization */
  7025. +/********************************************************************/
  7026. +
  7027. +/* Can't be declared "const" or the whole __initdata section will
  7028. + * become const */
  7029. +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
  7030. + " (David Gibson <hermes@gibson.dropbear.id.au>, "
  7031. + "Pavel Roskin <proski@gnu.org>, et al)";
  7032. +
  7033. +static int __init init_orinoco(void)
  7034. +{
  7035. + printk(KERN_DEBUG "%s\n", version);
  7036. + return 0;
  7037. +}
  7038. +
  7039. +static void __exit exit_orinoco(void)
  7040. +{
  7041. +}
  7042. +
  7043. +module_init(init_orinoco);
  7044. +module_exit(exit_orinoco);
  7045. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/main.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/main.h
  7046. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/main.h 1970-01-01 01:00:00.000000000 +0100
  7047. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/main.h 2026-02-16 14:00:36.623256352 +0100
  7048. @@ -0,0 +1,50 @@
  7049. +/* Exports from main to helper modules
  7050. + *
  7051. + * See copyright notice in main.c
  7052. + */
  7053. +#ifndef _ORINOCO_MAIN_H_
  7054. +#define _ORINOCO_MAIN_H_
  7055. +
  7056. +#include <linux/ieee80211.h>
  7057. +#include "orinoco.h"
  7058. +
  7059. +/********************************************************************/
  7060. +/* Compile time configuration and compatibility stuff */
  7061. +/********************************************************************/
  7062. +
  7063. +/* We do this this way to avoid ifdefs in the actual code */
  7064. +#ifdef WIRELESS_SPY
  7065. +#define SPY_NUMBER(priv) (priv->spy_data.spy_number)
  7066. +#else
  7067. +#define SPY_NUMBER(priv) 0
  7068. +#endif /* WIRELESS_SPY */
  7069. +
  7070. +/********************************************************************/
  7071. +
  7072. +/* Export module parameter */
  7073. +extern int force_monitor;
  7074. +
  7075. +/* Forward declarations */
  7076. +struct net_device;
  7077. +struct work_struct;
  7078. +
  7079. +void set_port_type(struct orinoco_private *priv);
  7080. +int orinoco_commit(struct orinoco_private *priv);
  7081. +void orinoco_reset(struct work_struct *work);
  7082. +
  7083. +/* Information element helpers - find a home for these... */
  7084. +#define WPA_OUI_TYPE "\x00\x50\xF2\x01"
  7085. +#define WPA_SELECTOR_LEN 4
  7086. +static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len)
  7087. +{
  7088. + u8 *p = data;
  7089. + while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) {
  7090. + if ((p[0] == WLAN_EID_VENDOR_SPECIFIC) &&
  7091. + (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0))
  7092. + return p;
  7093. + p += p[1] + 2;
  7094. + }
  7095. + return NULL;
  7096. +}
  7097. +
  7098. +#endif /* _ORINOCO_MAIN_H_ */
  7099. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/Makefile linux-6.18.9/drivers/net/wireless/intersil/orinoco/Makefile
  7100. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/Makefile 1970-01-01 01:00:00.000000000 +0100
  7101. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/Makefile 2026-02-16 14:00:36.623256352 +0100
  7102. @@ -0,0 +1,15 @@
  7103. +# SPDX-License-Identifier: GPL-2.0
  7104. +#
  7105. +# Makefile for the orinoco wireless device drivers.
  7106. +#
  7107. +orinoco-objs := main.o fw.o hw.o mic.o scan.o wext.o hermes_dld.o hermes.o cfg.o
  7108. +
  7109. +obj-$(CONFIG_HERMES) += orinoco.o
  7110. +obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
  7111. +obj-$(CONFIG_APPLE_AIRPORT) += airport.o
  7112. +obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
  7113. +obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
  7114. +obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
  7115. +obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o
  7116. +obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o
  7117. +obj-$(CONFIG_ORINOCO_USB) += orinoco_usb.o
  7118. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/mic.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/mic.c
  7119. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/mic.c 1970-01-01 01:00:00.000000000 +0100
  7120. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/mic.c 2026-02-16 14:00:36.623256352 +0100
  7121. @@ -0,0 +1,89 @@
  7122. +/* Orinoco MIC helpers
  7123. + *
  7124. + * See copyright notice in main.c
  7125. + */
  7126. +#include <linux/kernel.h>
  7127. +#include <linux/string.h>
  7128. +#include <linux/if_ether.h>
  7129. +#include <linux/scatterlist.h>
  7130. +#include <crypto/hash.h>
  7131. +
  7132. +#include "orinoco.h"
  7133. +#include "mic.h"
  7134. +
  7135. +/********************************************************************/
  7136. +/* Michael MIC crypto setup */
  7137. +/********************************************************************/
  7138. +int orinoco_mic_init(struct orinoco_private *priv)
  7139. +{
  7140. + priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0);
  7141. + if (IS_ERR(priv->tx_tfm_mic)) {
  7142. + printk(KERN_DEBUG "%s: could not allocate "
  7143. + "crypto API michael_mic\n", __func__);
  7144. + priv->tx_tfm_mic = NULL;
  7145. + return -ENOMEM;
  7146. + }
  7147. +
  7148. + priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0, 0);
  7149. + if (IS_ERR(priv->rx_tfm_mic)) {
  7150. + printk(KERN_DEBUG "%s: could not allocate "
  7151. + "crypto API michael_mic\n", __func__);
  7152. + priv->rx_tfm_mic = NULL;
  7153. + return -ENOMEM;
  7154. + }
  7155. +
  7156. + return 0;
  7157. +}
  7158. +
  7159. +void orinoco_mic_free(struct orinoco_private *priv)
  7160. +{
  7161. + if (priv->tx_tfm_mic)
  7162. + crypto_free_shash(priv->tx_tfm_mic);
  7163. + if (priv->rx_tfm_mic)
  7164. + crypto_free_shash(priv->rx_tfm_mic);
  7165. +}
  7166. +
  7167. +int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
  7168. + u8 *da, u8 *sa, u8 priority,
  7169. + u8 *data, size_t data_len, u8 *mic)
  7170. +{
  7171. + SHASH_DESC_ON_STACK(desc, tfm_michael);
  7172. + u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
  7173. + int err;
  7174. +
  7175. + if (tfm_michael == NULL) {
  7176. + printk(KERN_WARNING "%s: tfm_michael == NULL\n", __func__);
  7177. + return -1;
  7178. + }
  7179. +
  7180. + /* Copy header into buffer. We need the padding on the end zeroed */
  7181. + memcpy(&hdr[0], da, ETH_ALEN);
  7182. + memcpy(&hdr[ETH_ALEN], sa, ETH_ALEN);
  7183. + hdr[ETH_ALEN * 2] = priority;
  7184. + hdr[ETH_ALEN * 2 + 1] = 0;
  7185. + hdr[ETH_ALEN * 2 + 2] = 0;
  7186. + hdr[ETH_ALEN * 2 + 3] = 0;
  7187. +
  7188. + desc->tfm = tfm_michael;
  7189. +
  7190. + err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN);
  7191. + if (err)
  7192. + return err;
  7193. +
  7194. + err = crypto_shash_init(desc);
  7195. + if (err)
  7196. + return err;
  7197. +
  7198. + err = crypto_shash_update(desc, hdr, sizeof(hdr));
  7199. + if (err)
  7200. + return err;
  7201. +
  7202. + err = crypto_shash_update(desc, data, data_len);
  7203. + if (err)
  7204. + return err;
  7205. +
  7206. + err = crypto_shash_final(desc, mic);
  7207. + shash_desc_zero(desc);
  7208. +
  7209. + return err;
  7210. +}
  7211. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/mic.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/mic.h
  7212. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/mic.h 1970-01-01 01:00:00.000000000 +0100
  7213. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/mic.h 2026-02-16 14:00:36.623256352 +0100
  7214. @@ -0,0 +1,23 @@
  7215. +/* Orinoco MIC helpers
  7216. + *
  7217. + * See copyright notice in main.c
  7218. + */
  7219. +#ifndef _ORINOCO_MIC_H_
  7220. +#define _ORINOCO_MIC_H_
  7221. +
  7222. +#include <linux/types.h>
  7223. +#include <crypto/hash.h>
  7224. +
  7225. +#define MICHAEL_MIC_LEN 8
  7226. +
  7227. +/* Forward declarations */
  7228. +struct orinoco_private;
  7229. +struct crypto_ahash;
  7230. +
  7231. +int orinoco_mic_init(struct orinoco_private *priv);
  7232. +void orinoco_mic_free(struct orinoco_private *priv);
  7233. +int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
  7234. + u8 *da, u8 *sa, u8 priority,
  7235. + u8 *data, size_t data_len, u8 *mic);
  7236. +
  7237. +#endif /* ORINOCO_MIC_H */
  7238. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_cs.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_cs.c
  7239. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_cs.c 1970-01-01 01:00:00.000000000 +0100
  7240. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_cs.c 2026-02-16 14:00:36.623256352 +0100
  7241. @@ -0,0 +1,350 @@
  7242. +/* orinoco_cs.c (formerly known as dldwd_cs.c)
  7243. + *
  7244. + * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
  7245. + * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
  7246. + * EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and others).
  7247. + * It should also be usable on various Prism II based cards such as the
  7248. + * Linksys, D-Link and Farallon Skyline. It should also work on Symbol
  7249. + * cards such as the 3Com AirConnect and Ericsson WLAN.
  7250. + *
  7251. + * Copyright notice & release notes in file main.c
  7252. + */
  7253. +
  7254. +#define DRIVER_NAME "orinoco_cs"
  7255. +#define PFX DRIVER_NAME ": "
  7256. +
  7257. +#include <linux/module.h>
  7258. +#include <linux/kernel.h>
  7259. +#include <linux/delay.h>
  7260. +#include <pcmcia/cistpl.h>
  7261. +#include <pcmcia/cisreg.h>
  7262. +#include <pcmcia/ds.h>
  7263. +
  7264. +#include "orinoco.h"
  7265. +
  7266. +/********************************************************************/
  7267. +/* Module stuff */
  7268. +/********************************************************************/
  7269. +
  7270. +MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
  7271. +MODULE_DESCRIPTION("Driver for PCMCIA Lucent Orinoco,"
  7272. + " Prism II based and similar wireless cards");
  7273. +MODULE_LICENSE("Dual MPL/GPL");
  7274. +
  7275. +/* Module parameters */
  7276. +
  7277. +/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
  7278. + * don't have any CIS entry for it. This workaround it... */
  7279. +static int ignore_cis_vcc; /* = 0 */
  7280. +module_param(ignore_cis_vcc, int, 0);
  7281. +MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
  7282. +
  7283. +/********************************************************************/
  7284. +/* Data structures */
  7285. +/********************************************************************/
  7286. +
  7287. +/* PCMCIA specific device information (goes in the card field of
  7288. + * struct orinoco_private */
  7289. +struct orinoco_pccard {
  7290. + struct pcmcia_device *p_dev;
  7291. +
  7292. + /* Used to handle hard reset */
  7293. + /* yuck, we need this hack to work around the insanity of the
  7294. + * PCMCIA layer */
  7295. + unsigned long hard_reset_in_progress;
  7296. +};
  7297. +
  7298. +
  7299. +/********************************************************************/
  7300. +/* Function prototypes */
  7301. +/********************************************************************/
  7302. +
  7303. +static int orinoco_cs_config(struct pcmcia_device *link);
  7304. +static void orinoco_cs_release(struct pcmcia_device *link);
  7305. +static void orinoco_cs_detach(struct pcmcia_device *p_dev);
  7306. +
  7307. +/********************************************************************/
  7308. +/* Device methods */
  7309. +/********************************************************************/
  7310. +
  7311. +static int
  7312. +orinoco_cs_hard_reset(struct orinoco_private *priv)
  7313. +{
  7314. + struct orinoco_pccard *card = priv->card;
  7315. + struct pcmcia_device *link = card->p_dev;
  7316. + int err;
  7317. +
  7318. + /* We need atomic ops here, because we're not holding the lock */
  7319. + set_bit(0, &card->hard_reset_in_progress);
  7320. +
  7321. + err = pcmcia_reset_card(link->socket);
  7322. + if (err)
  7323. + return err;
  7324. +
  7325. + msleep(100);
  7326. + clear_bit(0, &card->hard_reset_in_progress);
  7327. +
  7328. + return 0;
  7329. +}
  7330. +
  7331. +/********************************************************************/
  7332. +/* PCMCIA stuff */
  7333. +/********************************************************************/
  7334. +
  7335. +static int
  7336. +orinoco_cs_probe(struct pcmcia_device *link)
  7337. +{
  7338. + struct orinoco_private *priv;
  7339. + struct orinoco_pccard *card;
  7340. + int ret;
  7341. +
  7342. + priv = alloc_orinocodev(sizeof(*card), &link->dev,
  7343. + orinoco_cs_hard_reset, NULL);
  7344. + if (!priv)
  7345. + return -ENOMEM;
  7346. + card = priv->card;
  7347. +
  7348. + /* Link both structures together */
  7349. + card->p_dev = link;
  7350. + link->priv = priv;
  7351. +
  7352. + ret = orinoco_cs_config(link);
  7353. + if (ret)
  7354. + goto err_free_orinocodev;
  7355. +
  7356. + return 0;
  7357. +
  7358. +err_free_orinocodev:
  7359. + free_orinocodev(priv);
  7360. + return ret;
  7361. +}
  7362. +
  7363. +static void orinoco_cs_detach(struct pcmcia_device *link)
  7364. +{
  7365. + struct orinoco_private *priv = link->priv;
  7366. +
  7367. + orinoco_if_del(priv);
  7368. +
  7369. + orinoco_cs_release(link);
  7370. +
  7371. + wiphy_unregister(priv_to_wiphy(priv));
  7372. + free_orinocodev(priv);
  7373. +} /* orinoco_cs_detach */
  7374. +
  7375. +static int orinoco_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
  7376. +{
  7377. + if (p_dev->config_index == 0)
  7378. + return -EINVAL;
  7379. +
  7380. + return pcmcia_request_io(p_dev);
  7381. +};
  7382. +
  7383. +static int
  7384. +orinoco_cs_config(struct pcmcia_device *link)
  7385. +{
  7386. + struct orinoco_private *priv = link->priv;
  7387. + struct hermes *hw = &priv->hw;
  7388. + int ret;
  7389. + void __iomem *mem;
  7390. +
  7391. + link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC |
  7392. + CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
  7393. + if (ignore_cis_vcc)
  7394. + link->config_flags &= ~CONF_AUTO_CHECK_VCC;
  7395. + ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL);
  7396. + if (ret) {
  7397. + if (!ignore_cis_vcc)
  7398. + printk(KERN_ERR PFX "GetNextTuple(): No matching "
  7399. + "CIS configuration. Maybe you need the "
  7400. + "ignore_cis_vcc=1 parameter.\n");
  7401. + goto failed;
  7402. + }
  7403. +
  7404. + mem = ioport_map(link->resource[0]->start,
  7405. + resource_size(link->resource[0]));
  7406. + if (!mem)
  7407. + goto failed;
  7408. +
  7409. + /* We initialize the hermes structure before completing PCMCIA
  7410. + * configuration just in case the interrupt handler gets
  7411. + * called. */
  7412. + hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
  7413. +
  7414. + ret = pcmcia_request_irq(link, orinoco_interrupt);
  7415. + if (ret)
  7416. + goto failed;
  7417. +
  7418. + ret = pcmcia_enable_device(link);
  7419. + if (ret)
  7420. + goto failed;
  7421. +
  7422. + /* Initialise the main driver */
  7423. + if (orinoco_init(priv) != 0) {
  7424. + printk(KERN_ERR PFX "orinoco_init() failed\n");
  7425. + goto failed;
  7426. + }
  7427. +
  7428. + /* Register an interface with the stack */
  7429. + if (orinoco_if_add(priv, link->resource[0]->start,
  7430. + link->irq, NULL) != 0) {
  7431. + printk(KERN_ERR PFX "orinoco_if_add() failed\n");
  7432. + goto failed;
  7433. + }
  7434. +
  7435. + return 0;
  7436. +
  7437. + failed:
  7438. + orinoco_cs_release(link);
  7439. + return -ENODEV;
  7440. +} /* orinoco_cs_config */
  7441. +
  7442. +static void
  7443. +orinoco_cs_release(struct pcmcia_device *link)
  7444. +{
  7445. + struct orinoco_private *priv = link->priv;
  7446. + unsigned long flags;
  7447. +
  7448. + /* We're committed to taking the device away now, so mark the
  7449. + * hardware as unavailable */
  7450. + priv->hw.ops->lock_irqsave(&priv->lock, &flags);
  7451. + priv->hw_unavailable++;
  7452. + priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
  7453. +
  7454. + pcmcia_disable_device(link);
  7455. + if (priv->hw.iobase)
  7456. + ioport_unmap(priv->hw.iobase);
  7457. +} /* orinoco_cs_release */
  7458. +
  7459. +static int orinoco_cs_suspend(struct pcmcia_device *link)
  7460. +{
  7461. + struct orinoco_private *priv = link->priv;
  7462. + struct orinoco_pccard *card = priv->card;
  7463. +
  7464. + /* This is probably racy, but I can't think of
  7465. + a better way, short of rewriting the PCMCIA
  7466. + layer to not suck :-( */
  7467. + if (!test_bit(0, &card->hard_reset_in_progress))
  7468. + orinoco_down(priv);
  7469. +
  7470. + return 0;
  7471. +}
  7472. +
  7473. +static int orinoco_cs_resume(struct pcmcia_device *link)
  7474. +{
  7475. + struct orinoco_private *priv = link->priv;
  7476. + struct orinoco_pccard *card = priv->card;
  7477. + int err = 0;
  7478. +
  7479. + if (!test_bit(0, &card->hard_reset_in_progress))
  7480. + err = orinoco_up(priv);
  7481. +
  7482. + return err;
  7483. +}
  7484. +
  7485. +
  7486. +/********************************************************************/
  7487. +/* Module initialization */
  7488. +/********************************************************************/
  7489. +
  7490. +static const struct pcmcia_device_id orinoco_cs_ids[] = {
  7491. + PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
  7492. + PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
  7493. + PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), /* Nortel Networks eMobility 802.11 Wireless Adapter */
  7494. + PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002), /* AirWay 802.11 Adapter (PCMCIA) */
  7495. + PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001), /* ARtem Onair */
  7496. + PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0003), /* ARtem Onair Comcard 11 */
  7497. + PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305), /* Buffalo WLI-PCM-S11 */
  7498. + PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002), /* ASUS SpaceLink WL-100 */
  7499. + PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002), /* SpeedStream SS1021 Wireless Adapter */
  7500. + PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x3021), /* SpeedStream Wireless Adapter */
  7501. + PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001), /* PLANEX RoadLannerWave GW-NS11H */
  7502. + PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
  7503. + PCMCIA_DEVICE_PROD_ID12("Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio", 0x5cd01705, 0x4271660f),
  7504. + PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11B_CF_CARD_25", 0x78fc06ee, 0x45a50c1e),
  7505. + PCMCIA_DEVICE_PROD_ID12("ASUS", "802_11b_PC_CARD_25", 0x78fc06ee, 0xdb9aa842),
  7506. + PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
  7507. + PCMCIA_DEVICE_PROD_ID12("BENQ", "AWL100 PCMCIA ADAPTER", 0x35dadc74, 0x01f7fedb),
  7508. + PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
  7509. + PCMCIA_DEVICE_PROD_ID12("D-Link Corporation", "D-Link DWL-650H 11Mbps WLAN Adapter", 0xef544d24, 0xcd8ea916),
  7510. + PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
  7511. + PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
  7512. + PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless 2011 LAN PC Card", 0x816cc815, 0x07f58077),
  7513. + PCMCIA_DEVICE_PROD_ID12("LeArtery", "SYNCBYAIR 11Mbps Wireless LAN PC Card", 0x7e3b326a, 0x49893e92),
  7514. + PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
  7515. + PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
  7516. + PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
  7517. + PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
  7518. + PCMCIA_DEVICE_PROD_ID12("Nortel Networks", "emobility 802.11 Wireless LAN PC Card", 0x2d617ea0, 0x88cd5767),
  7519. + PCMCIA_DEVICE_PROD_ID12("OTC", "Wireless AirEZY 2411-PCC WLAN Card", 0x4ac44287, 0x235a6bed),
  7520. + PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
  7521. + PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
  7522. + PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
  7523. + PCMCIA_DEVICE_PROD_ID12("Symbol Technologies", "LA4111 Spectrum24 Wireless LAN PC Card", 0x3f02b4d6, 0x3663cb0e),
  7524. + PCMCIA_DEVICE_MANF_CARD_PROD_ID3(0x0156, 0x0002, "Version 01.01", 0xd27deb1a), /* Lucent Orinoco */
  7525. +#ifdef CONFIG_HERMES_PRISM
  7526. + /* Only entries that certainly identify Prism chipset */
  7527. + PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), /* SonicWALL Long Range Wireless Card */
  7528. + PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), /* Sohoware NCP110, Philips 802.11b */
  7529. + PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0002), /* AnyPoint(TM) Wireless II PC Card */
  7530. + PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000), /* PROXIM RangeLAN-DS/LAN PC CARD */
  7531. + PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), /* Compaq WL100 11 Mbps Wireless Adapter */
  7532. + PCMCIA_DEVICE_MANF_CARD(0x01ff, 0x0008), /* Intermec MobileLAN 11Mbps 802.11b WLAN Card */
  7533. + PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002), /* Samsung SWL2000-N 11Mb/s WLAN Card */
  7534. + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612), /* Linksys WPC11 Version 2.5 */
  7535. + PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613), /* Linksys WPC11 Version 3 */
  7536. + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002), /* Compaq HNW-100 11 Mbps Wireless Adapter */
  7537. + PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673), /* Linksys WCF12 Wireless CompactFlash Card */
  7538. + PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300), /* Airvast WN-100 */
  7539. + PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021), /* Adaptec Ultra Wireless ANW-8030 */
  7540. + PCMCIA_DEVICE_MANF_CARD(0xc001, 0x0008), /* CONTEC FLEXSCAN/FX-DDS110-PCC */
  7541. + PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002), /* Conceptronic CON11Cpro, EMTAC A2424i */
  7542. + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002), /* Safeway 802.11b, ZCOMAX AirRunner/XI-300 */
  7543. + PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), /* D-Link DCF660, Sandisk Connect SDWCFB-000 */
  7544. + PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
  7545. + PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
  7546. + PCMCIA_DEVICE_PROD_ID12("Addtron", "AWP-100 Wireless PCMCIA", 0xe6ec52ce, 0x08649af2),
  7547. + PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-CF-S11G", 0x2decece3, 0x82067c18),
  7548. + PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
  7549. + PCMCIA_DEVICE_PROD_ID12("Compaq", "WL200_11Mbps_Wireless_PCI_Card", 0x54f7c49c, 0x15a75e5b),
  7550. + PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
  7551. + PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
  7552. + PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae),
  7553. + PCMCIA_DEVICE_PROD_ID12("Digital Data Communications", "WPC-0100", 0xfdd73470, 0xe0b6f146),
  7554. + PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
  7555. + PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
  7556. + PCMCIA_DEVICE_PROD_ID12(" ", "IEEE 802.11 Wireless LAN/PC Card", 0x3b6e20c8, 0xefccafe9),
  7557. + PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
  7558. + PCMCIA_DEVICE_PROD_ID12("INTERSIL", "I-GATE 11M PC Card / PC Card plus", 0x74c5e40d, 0x8304ff77),
  7559. + PCMCIA_DEVICE_PROD_ID12("Intersil", "PRISM 2_5 PCMCIA ADAPTER", 0x4b801a17, 0x6345a0bf),
  7560. + PCMCIA_DEVICE_PROD_ID12("Linksys", "Wireless CompactFlash Card", 0x0733cc81, 0x0c52f395),
  7561. + PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01),
  7562. + PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1),
  7563. + PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401 Wireless PC", "Card", 0xa37434e9, 0x9762e8f1),
  7564. + PCMCIA_DEVICE_PROD_ID12("OEM", "PRISM2 IEEE 802.11 PC-Card", 0xfea54c90, 0x48f2bdd6),
  7565. + PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
  7566. + PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-NS110", 0x209f40ab, 0x46263178),
  7567. + PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2532W-B EliteConnect Wireless Adapter", 0xc4f8b18b, 0x196bd757),
  7568. + PCMCIA_DEVICE_PROD_ID12("SMC", "SMC2632W", 0xc4f8b18b, 0x474a1f2a),
  7569. + PCMCIA_DEVICE_PROD_ID12("ZoomAir 11Mbps High", "Rate wireless Networking", 0x273fe3db, 0x32a1eaee),
  7570. + PCMCIA_DEVICE_PROD_ID3("HFA3863", 0x355cb092),
  7571. + PCMCIA_DEVICE_PROD_ID3("ISL37100P", 0x630d52b2),
  7572. + PCMCIA_DEVICE_PROD_ID3("ISL37101P-10", 0xdd97a26b),
  7573. + PCMCIA_DEVICE_PROD_ID3("ISL37300P", 0xc9049a39),
  7574. +
  7575. + /* This may be Agere or Intersil Firmware */
  7576. + PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
  7577. +#endif
  7578. + PCMCIA_DEVICE_NULL,
  7579. +};
  7580. +MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
  7581. +
  7582. +static struct pcmcia_driver orinoco_driver = {
  7583. + .owner = THIS_MODULE,
  7584. + .name = DRIVER_NAME,
  7585. + .probe = orinoco_cs_probe,
  7586. + .remove = orinoco_cs_detach,
  7587. + .id_table = orinoco_cs_ids,
  7588. + .suspend = orinoco_cs_suspend,
  7589. + .resume = orinoco_cs_resume,
  7590. +};
  7591. +module_pcmcia_driver(orinoco_driver);
  7592. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco.h
  7593. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco.h 1970-01-01 01:00:00.000000000 +0100
  7594. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco.h 2026-02-16 14:00:36.623256352 +0100
  7595. @@ -0,0 +1,249 @@
  7596. +/* orinoco.h
  7597. + *
  7598. + * Common definitions to all pieces of the various orinoco
  7599. + * drivers
  7600. + */
  7601. +
  7602. +#ifndef _ORINOCO_H
  7603. +#define _ORINOCO_H
  7604. +
  7605. +#define DRIVER_VERSION "0.15"
  7606. +
  7607. +#include <linux/interrupt.h>
  7608. +#include <linux/suspend.h>
  7609. +#include <linux/netdevice.h>
  7610. +#include <linux/wireless.h>
  7611. +#include <net/iw_handler.h>
  7612. +#include <net/cfg80211.h>
  7613. +
  7614. +#include "hermes.h"
  7615. +
  7616. +/* To enable debug messages */
  7617. +/*#define ORINOCO_DEBUG 3*/
  7618. +
  7619. +#define MAX_SCAN_LEN 4096
  7620. +
  7621. +#define ORINOCO_SEQ_LEN 8
  7622. +#define ORINOCO_MAX_KEY_SIZE 14
  7623. +#define ORINOCO_MAX_KEYS 4
  7624. +
  7625. +struct orinoco_key {
  7626. + __le16 len; /* always stored as little-endian */
  7627. + char data[ORINOCO_MAX_KEY_SIZE];
  7628. +} __packed;
  7629. +
  7630. +#define TKIP_KEYLEN 16
  7631. +#define MIC_KEYLEN 8
  7632. +
  7633. +struct orinoco_tkip_key {
  7634. + u8 tkip[TKIP_KEYLEN];
  7635. + u8 tx_mic[MIC_KEYLEN];
  7636. + u8 rx_mic[MIC_KEYLEN];
  7637. +};
  7638. +
  7639. +enum orinoco_alg {
  7640. + ORINOCO_ALG_NONE,
  7641. + ORINOCO_ALG_WEP,
  7642. + ORINOCO_ALG_TKIP
  7643. +};
  7644. +
  7645. +enum fwtype {
  7646. + FIRMWARE_TYPE_AGERE,
  7647. + FIRMWARE_TYPE_INTERSIL,
  7648. + FIRMWARE_TYPE_SYMBOL
  7649. +};
  7650. +
  7651. +struct firmware;
  7652. +
  7653. +struct orinoco_private {
  7654. + void *card; /* Pointer to card dependent structure */
  7655. + struct device *dev;
  7656. + int (*hard_reset)(struct orinoco_private *);
  7657. + int (*stop_fw)(struct orinoco_private *, int);
  7658. +
  7659. + struct ieee80211_supported_band band;
  7660. + struct ieee80211_channel channels[14];
  7661. + u32 cipher_suites[3];
  7662. +
  7663. + /* Synchronisation stuff */
  7664. + spinlock_t lock;
  7665. + int hw_unavailable;
  7666. + struct work_struct reset_work;
  7667. +
  7668. + /* Interrupt tasklets */
  7669. + struct tasklet_struct rx_tasklet;
  7670. + struct list_head rx_list;
  7671. +
  7672. + /* driver state */
  7673. + int open;
  7674. + u16 last_linkstatus;
  7675. + struct work_struct join_work;
  7676. + struct work_struct wevent_work;
  7677. +
  7678. + /* Net device stuff */
  7679. + struct net_device *ndev;
  7680. + struct iw_statistics wstats;
  7681. +
  7682. + /* Hardware control variables */
  7683. + struct hermes hw;
  7684. + u16 txfid;
  7685. +
  7686. + /* Capabilities of the hardware/firmware */
  7687. + enum fwtype firmware_type;
  7688. + int ibss_port;
  7689. + int nicbuf_size;
  7690. + u16 channel_mask;
  7691. +
  7692. + /* Boolean capabilities */
  7693. + unsigned int has_ibss:1;
  7694. + unsigned int has_port3:1;
  7695. + unsigned int has_wep:1;
  7696. + unsigned int has_big_wep:1;
  7697. + unsigned int has_mwo:1;
  7698. + unsigned int has_pm:1;
  7699. + unsigned int has_preamble:1;
  7700. + unsigned int has_sensitivity:1;
  7701. + unsigned int has_hostscan:1;
  7702. + unsigned int has_alt_txcntl:1;
  7703. + unsigned int has_ext_scan:1;
  7704. + unsigned int has_wpa:1;
  7705. + unsigned int do_fw_download:1;
  7706. + unsigned int broken_disableport:1;
  7707. + unsigned int broken_monitor:1;
  7708. + unsigned int prefer_port3:1;
  7709. +
  7710. + /* Configuration paramaters */
  7711. + enum nl80211_iftype iw_mode;
  7712. + enum orinoco_alg encode_alg;
  7713. + u16 wep_restrict, tx_key;
  7714. + struct key_params keys[ORINOCO_MAX_KEYS];
  7715. +
  7716. + int bitratemode;
  7717. + char nick[IW_ESSID_MAX_SIZE + 1];
  7718. + char desired_essid[IW_ESSID_MAX_SIZE + 1];
  7719. + char desired_bssid[ETH_ALEN];
  7720. + int bssid_fixed;
  7721. + u16 frag_thresh, mwo_robust;
  7722. + u16 channel;
  7723. + u16 ap_density, rts_thresh;
  7724. + u16 pm_on, pm_mcast, pm_period, pm_timeout;
  7725. + u16 preamble;
  7726. + u16 short_retry_limit, long_retry_limit;
  7727. + u16 retry_lifetime;
  7728. +#ifdef WIRELESS_SPY
  7729. + struct iw_spy_data spy_data; /* iwspy support */
  7730. + struct iw_public_data wireless_data;
  7731. +#endif
  7732. +
  7733. + /* Configuration dependent variables */
  7734. + int port_type, createibss;
  7735. + int promiscuous, mc_count;
  7736. +
  7737. + /* Scanning support */
  7738. + struct cfg80211_scan_request *scan_request;
  7739. + struct work_struct process_scan;
  7740. + struct list_head scan_list;
  7741. + spinlock_t scan_lock; /* protects the scan list */
  7742. +
  7743. + /* WPA support */
  7744. + u8 *wpa_ie;
  7745. + int wpa_ie_len;
  7746. +
  7747. + struct crypto_shash *rx_tfm_mic;
  7748. + struct crypto_shash *tx_tfm_mic;
  7749. +
  7750. + unsigned int wpa_enabled:1;
  7751. + unsigned int tkip_cm_active:1;
  7752. + unsigned int key_mgmt:3;
  7753. +
  7754. +#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
  7755. + /* Cached in memory firmware to use during ->resume. */
  7756. + const struct firmware *cached_pri_fw;
  7757. + const struct firmware *cached_fw;
  7758. +#endif
  7759. +
  7760. + struct notifier_block pm_notifier;
  7761. +};
  7762. +
  7763. +#ifdef ORINOCO_DEBUG
  7764. +extern int orinoco_debug;
  7765. +#define DEBUG(n, args...) do { \
  7766. + if (orinoco_debug > (n)) \
  7767. + printk(KERN_DEBUG args); \
  7768. +} while (0)
  7769. +#else
  7770. +#define DEBUG(n, args...) do { } while (0)
  7771. +#endif /* ORINOCO_DEBUG */
  7772. +
  7773. +/********************************************************************/
  7774. +/* Exported prototypes */
  7775. +/********************************************************************/
  7776. +
  7777. +struct orinoco_private *alloc_orinocodev(int sizeof_card, struct device *device,
  7778. + int (*hard_reset)(struct orinoco_private *),
  7779. + int (*stop_fw)(struct orinoco_private *, int));
  7780. +void free_orinocodev(struct orinoco_private *priv);
  7781. +int orinoco_init(struct orinoco_private *priv);
  7782. +int orinoco_if_add(struct orinoco_private *priv, unsigned long base_addr,
  7783. + unsigned int irq, const struct net_device_ops *ops);
  7784. +void orinoco_if_del(struct orinoco_private *priv);
  7785. +int orinoco_up(struct orinoco_private *priv);
  7786. +void orinoco_down(struct orinoco_private *priv);
  7787. +irqreturn_t orinoco_interrupt(int irq, void *dev_id);
  7788. +
  7789. +void __orinoco_ev_info(struct net_device *dev, struct hermes *hw);
  7790. +void __orinoco_ev_rx(struct net_device *dev, struct hermes *hw);
  7791. +
  7792. +int orinoco_process_xmit_skb(struct sk_buff *skb,
  7793. + struct net_device *dev,
  7794. + struct orinoco_private *priv,
  7795. + int *tx_control,
  7796. + u8 *mic);
  7797. +
  7798. +/* Common ndo functions exported for reuse by orinoco_usb */
  7799. +int orinoco_open(struct net_device *dev);
  7800. +int orinoco_stop(struct net_device *dev);
  7801. +void orinoco_set_multicast_list(struct net_device *dev);
  7802. +int orinoco_change_mtu(struct net_device *dev, int new_mtu);
  7803. +void orinoco_tx_timeout(struct net_device *dev, unsigned int txqueue);
  7804. +
  7805. +/********************************************************************/
  7806. +/* Locking and synchronization functions */
  7807. +/********************************************************************/
  7808. +
  7809. +static inline int orinoco_lock(struct orinoco_private *priv,
  7810. + unsigned long *flags)
  7811. +{
  7812. + priv->hw.ops->lock_irqsave(&priv->lock, flags);
  7813. + if (priv->hw_unavailable) {
  7814. + DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
  7815. + priv->ndev);
  7816. + priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
  7817. + return -EBUSY;
  7818. + }
  7819. + return 0;
  7820. +}
  7821. +
  7822. +static inline void orinoco_unlock(struct orinoco_private *priv,
  7823. + unsigned long *flags)
  7824. +{
  7825. + priv->hw.ops->unlock_irqrestore(&priv->lock, flags);
  7826. +}
  7827. +
  7828. +static inline void orinoco_lock_irq(struct orinoco_private *priv)
  7829. +{
  7830. + priv->hw.ops->lock_irq(&priv->lock);
  7831. +}
  7832. +
  7833. +static inline void orinoco_unlock_irq(struct orinoco_private *priv)
  7834. +{
  7835. + priv->hw.ops->unlock_irq(&priv->lock);
  7836. +}
  7837. +
  7838. +/*** Navigate from net_device to orinoco_private ***/
  7839. +static inline struct orinoco_private *ndev_priv(struct net_device *dev)
  7840. +{
  7841. + struct wireless_dev *wdev = netdev_priv(dev);
  7842. + return wdev_priv(wdev);
  7843. +}
  7844. +#endif /* _ORINOCO_H */
  7845. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c
  7846. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c 1970-01-01 01:00:00.000000000 +0100
  7847. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_nortel.c 2026-02-16 14:00:36.623256352 +0100
  7848. @@ -0,0 +1,314 @@
  7849. +/* orinoco_nortel.c
  7850. + *
  7851. + * Driver for Prism II devices which would usually be driven by orinoco_cs,
  7852. + * but are connected to the PCI bus by a PCI-to-PCMCIA adapter used in
  7853. + * Nortel emobility, Symbol LA-4113 and Symbol LA-4123.
  7854. + *
  7855. + * Copyright (C) 2002 Tobias Hoffmann
  7856. + * (C) 2003 Christoph Jungegger <disdos@traum404.de>
  7857. + *
  7858. + * Some of this code is borrowed from orinoco_plx.c
  7859. + * Copyright (C) 2001 Daniel Barlow
  7860. + * Some of this code is borrowed from orinoco_pci.c
  7861. + * Copyright (C) 2001 Jean Tourrilhes
  7862. + * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
  7863. + * has been copied from it. linux-wlan-ng-0.1.10 is originally :
  7864. + * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
  7865. + *
  7866. + * The contents of this file are subject to the Mozilla Public License
  7867. + * Version 1.1 (the "License"); you may not use this file except in
  7868. + * compliance with the License. You may obtain a copy of the License
  7869. + * at http://www.mozilla.org/MPL/
  7870. + *
  7871. + * Software distributed under the License is distributed on an "AS IS"
  7872. + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  7873. + * the License for the specific language governing rights and
  7874. + * limitations under the License.
  7875. + *
  7876. + * Alternatively, the contents of this file may be used under the
  7877. + * terms of the GNU General Public License version 2 (the "GPL"), in
  7878. + * which case the provisions of the GPL are applicable instead of the
  7879. + * above. If you wish to allow the use of your version of this file
  7880. + * only under the terms of the GPL and not to allow others to use your
  7881. + * version of this file under the MPL, indicate your decision by
  7882. + * deleting the provisions above and replace them with the notice and
  7883. + * other provisions required by the GPL. If you do not delete the
  7884. + * provisions above, a recipient may use your version of this file
  7885. + * under either the MPL or the GPL.
  7886. + */
  7887. +
  7888. +#define DRIVER_NAME "orinoco_nortel"
  7889. +#define PFX DRIVER_NAME ": "
  7890. +
  7891. +#include <linux/module.h>
  7892. +#include <linux/kernel.h>
  7893. +#include <linux/init.h>
  7894. +#include <linux/delay.h>
  7895. +#include <linux/pci.h>
  7896. +#include <pcmcia/cisreg.h>
  7897. +
  7898. +#include "orinoco.h"
  7899. +#include "orinoco_pci.h"
  7900. +
  7901. +#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */
  7902. +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
  7903. +
  7904. +
  7905. +/*
  7906. + * Do a soft reset of the card using the Configuration Option Register
  7907. + * We need this to get going...
  7908. + * This is the part of the code that is strongly inspired from wlan-ng
  7909. + *
  7910. + * Note bis : Don't try to access HERMES_CMD during the reset phase.
  7911. + * It just won't work !
  7912. + */
  7913. +static int orinoco_nortel_cor_reset(struct orinoco_private *priv)
  7914. +{
  7915. + struct orinoco_pci_card *card = priv->card;
  7916. +
  7917. + /* Assert the reset until the card notices */
  7918. + iowrite16(8, card->bridge_io + 2);
  7919. + ioread16(card->attr_io + COR_OFFSET);
  7920. + iowrite16(0x80, card->attr_io + COR_OFFSET);
  7921. + mdelay(1);
  7922. +
  7923. + /* Give time for the card to recover from this hard effort */
  7924. + iowrite16(0, card->attr_io + COR_OFFSET);
  7925. + iowrite16(0, card->attr_io + COR_OFFSET);
  7926. + mdelay(1);
  7927. +
  7928. + /* Set COR as usual */
  7929. + iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
  7930. + iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
  7931. + mdelay(1);
  7932. +
  7933. + iowrite16(0x228, card->bridge_io + 2);
  7934. +
  7935. + return 0;
  7936. +}
  7937. +
  7938. +static int orinoco_nortel_hw_init(struct orinoco_pci_card *card)
  7939. +{
  7940. + int i;
  7941. + u32 reg;
  7942. +
  7943. + /* Setup bridge */
  7944. + if (ioread16(card->bridge_io) & 1) {
  7945. + printk(KERN_ERR PFX "brg1 answer1 wrong\n");
  7946. + return -EBUSY;
  7947. + }
  7948. + iowrite16(0x118, card->bridge_io + 2);
  7949. + iowrite16(0x108, card->bridge_io + 2);
  7950. + mdelay(30);
  7951. + iowrite16(0x8, card->bridge_io + 2);
  7952. + for (i = 0; i < 30; i++) {
  7953. + mdelay(30);
  7954. + if (ioread16(card->bridge_io) & 0x10)
  7955. + break;
  7956. + }
  7957. + if (i == 30) {
  7958. + printk(KERN_ERR PFX "brg1 timed out\n");
  7959. + return -EBUSY;
  7960. + }
  7961. + if (ioread16(card->attr_io + COR_OFFSET) & 1) {
  7962. + printk(KERN_ERR PFX "brg2 answer1 wrong\n");
  7963. + return -EBUSY;
  7964. + }
  7965. + if (ioread16(card->attr_io + COR_OFFSET + 2) & 1) {
  7966. + printk(KERN_ERR PFX "brg2 answer2 wrong\n");
  7967. + return -EBUSY;
  7968. + }
  7969. + if (ioread16(card->attr_io + COR_OFFSET + 4) & 1) {
  7970. + printk(KERN_ERR PFX "brg2 answer3 wrong\n");
  7971. + return -EBUSY;
  7972. + }
  7973. +
  7974. + /* Set the PCMCIA COR register */
  7975. + iowrite16(COR_VALUE, card->attr_io + COR_OFFSET);
  7976. + mdelay(1);
  7977. + reg = ioread16(card->attr_io + COR_OFFSET);
  7978. + if (reg != COR_VALUE) {
  7979. + printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n",
  7980. + reg);
  7981. + return -EBUSY;
  7982. + }
  7983. +
  7984. + /* Set LEDs */
  7985. + iowrite16(1, card->bridge_io + 10);
  7986. + return 0;
  7987. +}
  7988. +
  7989. +static int orinoco_nortel_init_one(struct pci_dev *pdev,
  7990. + const struct pci_device_id *ent)
  7991. +{
  7992. + int err;
  7993. + struct orinoco_private *priv;
  7994. + struct orinoco_pci_card *card;
  7995. + void __iomem *hermes_io, *bridge_io, *attr_io;
  7996. +
  7997. + err = pci_enable_device(pdev);
  7998. + if (err) {
  7999. + printk(KERN_ERR PFX "Cannot enable PCI device\n");
  8000. + return err;
  8001. + }
  8002. +
  8003. + err = pci_request_regions(pdev, DRIVER_NAME);
  8004. + if (err) {
  8005. + printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
  8006. + goto fail_resources;
  8007. + }
  8008. +
  8009. + bridge_io = pci_iomap(pdev, 0, 0);
  8010. + if (!bridge_io) {
  8011. + printk(KERN_ERR PFX "Cannot map bridge registers\n");
  8012. + err = -EIO;
  8013. + goto fail_map_bridge;
  8014. + }
  8015. +
  8016. + attr_io = pci_iomap(pdev, 1, 0);
  8017. + if (!attr_io) {
  8018. + printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
  8019. + err = -EIO;
  8020. + goto fail_map_attr;
  8021. + }
  8022. +
  8023. + hermes_io = pci_iomap(pdev, 2, 0);
  8024. + if (!hermes_io) {
  8025. + printk(KERN_ERR PFX "Cannot map chipset registers\n");
  8026. + err = -EIO;
  8027. + goto fail_map_hermes;
  8028. + }
  8029. +
  8030. + /* Allocate network device */
  8031. + priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
  8032. + orinoco_nortel_cor_reset, NULL);
  8033. + if (!priv) {
  8034. + printk(KERN_ERR PFX "Cannot allocate network device\n");
  8035. + err = -ENOMEM;
  8036. + goto fail_alloc;
  8037. + }
  8038. +
  8039. + card = priv->card;
  8040. + card->bridge_io = bridge_io;
  8041. + card->attr_io = attr_io;
  8042. +
  8043. + hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
  8044. +
  8045. + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
  8046. + DRIVER_NAME, priv);
  8047. + if (err) {
  8048. + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
  8049. + err = -EBUSY;
  8050. + goto fail_irq;
  8051. + }
  8052. +
  8053. + err = orinoco_nortel_hw_init(card);
  8054. + if (err) {
  8055. + printk(KERN_ERR PFX "Hardware initialization failed\n");
  8056. + goto fail;
  8057. + }
  8058. +
  8059. + err = orinoco_nortel_cor_reset(priv);
  8060. + if (err) {
  8061. + printk(KERN_ERR PFX "Initial reset failed\n");
  8062. + goto fail;
  8063. + }
  8064. +
  8065. + err = orinoco_init(priv);
  8066. + if (err) {
  8067. + printk(KERN_ERR PFX "orinoco_init() failed\n");
  8068. + goto fail;
  8069. + }
  8070. +
  8071. + err = orinoco_if_add(priv, 0, 0, NULL);
  8072. + if (err) {
  8073. + printk(KERN_ERR PFX "orinoco_if_add() failed\n");
  8074. + goto fail_wiphy;
  8075. + }
  8076. +
  8077. + pci_set_drvdata(pdev, priv);
  8078. +
  8079. + return 0;
  8080. +
  8081. + fail_wiphy:
  8082. + wiphy_unregister(priv_to_wiphy(priv));
  8083. + fail:
  8084. + free_irq(pdev->irq, priv);
  8085. +
  8086. + fail_irq:
  8087. + free_orinocodev(priv);
  8088. +
  8089. + fail_alloc:
  8090. + pci_iounmap(pdev, hermes_io);
  8091. +
  8092. + fail_map_hermes:
  8093. + pci_iounmap(pdev, attr_io);
  8094. +
  8095. + fail_map_attr:
  8096. + pci_iounmap(pdev, bridge_io);
  8097. +
  8098. + fail_map_bridge:
  8099. + pci_release_regions(pdev);
  8100. +
  8101. + fail_resources:
  8102. + pci_disable_device(pdev);
  8103. +
  8104. + return err;
  8105. +}
  8106. +
  8107. +static void orinoco_nortel_remove_one(struct pci_dev *pdev)
  8108. +{
  8109. + struct orinoco_private *priv = pci_get_drvdata(pdev);
  8110. + struct orinoco_pci_card *card = priv->card;
  8111. +
  8112. + /* Clear LEDs */
  8113. + iowrite16(0, card->bridge_io + 10);
  8114. +
  8115. + orinoco_if_del(priv);
  8116. + wiphy_unregister(priv_to_wiphy(priv));
  8117. + free_irq(pdev->irq, priv);
  8118. + free_orinocodev(priv);
  8119. + pci_iounmap(pdev, priv->hw.iobase);
  8120. + pci_iounmap(pdev, card->attr_io);
  8121. + pci_iounmap(pdev, card->bridge_io);
  8122. + pci_release_regions(pdev);
  8123. + pci_disable_device(pdev);
  8124. +}
  8125. +
  8126. +static const struct pci_device_id orinoco_nortel_id_table[] = {
  8127. + /* Nortel emobility PCI */
  8128. + {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,},
  8129. + /* Symbol LA-4123 PCI */
  8130. + {0x1562, 0x0001, PCI_ANY_ID, PCI_ANY_ID,},
  8131. + {0,},
  8132. +};
  8133. +
  8134. +MODULE_DEVICE_TABLE(pci, orinoco_nortel_id_table);
  8135. +
  8136. +static struct pci_driver orinoco_nortel_driver = {
  8137. + .name = DRIVER_NAME,
  8138. + .id_table = orinoco_nortel_id_table,
  8139. + .probe = orinoco_nortel_init_one,
  8140. + .remove = orinoco_nortel_remove_one,
  8141. + .driver.pm = &orinoco_pci_pm_ops,
  8142. +};
  8143. +
  8144. +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
  8145. + " (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)";
  8146. +MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>");
  8147. +MODULE_DESCRIPTION("Driver for wireless LAN cards using the Nortel PCI bridge");
  8148. +MODULE_LICENSE("Dual MPL/GPL");
  8149. +
  8150. +static int __init orinoco_nortel_init(void)
  8151. +{
  8152. + printk(KERN_DEBUG "%s\n", version);
  8153. + return pci_register_driver(&orinoco_nortel_driver);
  8154. +}
  8155. +
  8156. +static void __exit orinoco_nortel_exit(void)
  8157. +{
  8158. + pci_unregister_driver(&orinoco_nortel_driver);
  8159. +}
  8160. +
  8161. +module_init(orinoco_nortel_init);
  8162. +module_exit(orinoco_nortel_exit);
  8163. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_pci.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_pci.c
  8164. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_pci.c 1970-01-01 01:00:00.000000000 +0100
  8165. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_pci.c 2026-02-16 14:00:36.623256352 +0100
  8166. @@ -0,0 +1,257 @@
  8167. +/* orinoco_pci.c
  8168. + *
  8169. + * Driver for Prism 2.5/3 devices that have a direct PCI interface
  8170. + * (i.e. these are not PCMCIA cards in a PCMCIA-to-PCI bridge).
  8171. + * The card contains only one PCI region, which contains all the usual
  8172. + * hermes registers, as well as the COR register.
  8173. + *
  8174. + * Current maintainers are:
  8175. + * Pavel Roskin <proski AT gnu.org>
  8176. + * and David Gibson <hermes AT gibson.dropbear.id.au>
  8177. + *
  8178. + * Some of this code is borrowed from orinoco_plx.c
  8179. + * Copyright (C) 2001 Daniel Barlow <dan AT telent.net>
  8180. + * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing
  8181. + * has been copied from it. linux-wlan-ng-0.1.10 is originally :
  8182. + * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
  8183. + * This file originally written by:
  8184. + * Copyright (C) 2001 Jean Tourrilhes <jt AT hpl.hp.com>
  8185. + * And is now maintained by:
  8186. + * (C) Copyright David Gibson, IBM Corp. 2002-2003.
  8187. + *
  8188. + * The contents of this file are subject to the Mozilla Public License
  8189. + * Version 1.1 (the "License"); you may not use this file except in
  8190. + * compliance with the License. You may obtain a copy of the License
  8191. + * at http://www.mozilla.org/MPL/
  8192. + *
  8193. + * Software distributed under the License is distributed on an "AS IS"
  8194. + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  8195. + * the License for the specific language governing rights and
  8196. + * limitations under the License.
  8197. + *
  8198. + * Alternatively, the contents of this file may be used under the
  8199. + * terms of the GNU General Public License version 2 (the "GPL"), in
  8200. + * which case the provisions of the GPL are applicable instead of the
  8201. + * above. If you wish to allow the use of your version of this file
  8202. + * only under the terms of the GPL and not to allow others to use your
  8203. + * version of this file under the MPL, indicate your decision by
  8204. + * deleting the provisions above and replace them with the notice and
  8205. + * other provisions required by the GPL. If you do not delete the
  8206. + * provisions above, a recipient may use your version of this file
  8207. + * under either the MPL or the GPL.
  8208. + */
  8209. +
  8210. +#define DRIVER_NAME "orinoco_pci"
  8211. +#define PFX DRIVER_NAME ": "
  8212. +
  8213. +#include <linux/module.h>
  8214. +#include <linux/kernel.h>
  8215. +#include <linux/init.h>
  8216. +#include <linux/delay.h>
  8217. +#include <linux/pci.h>
  8218. +
  8219. +#include "orinoco.h"
  8220. +#include "orinoco_pci.h"
  8221. +
  8222. +/* Offset of the COR register of the PCI card */
  8223. +#define HERMES_PCI_COR (0x26)
  8224. +
  8225. +/* Bitmask to reset the card */
  8226. +#define HERMES_PCI_COR_MASK (0x0080)
  8227. +
  8228. +/* Magic timeouts for doing the reset.
  8229. + * Those times are straight from wlan-ng, and it is claimed that they
  8230. + * are necessary. Alan will kill me. Take your time and grab a coffee. */
  8231. +#define HERMES_PCI_COR_ONT (250) /* ms */
  8232. +#define HERMES_PCI_COR_OFFT (500) /* ms */
  8233. +#define HERMES_PCI_COR_BUSYT (500) /* ms */
  8234. +
  8235. +/*
  8236. + * Do a soft reset of the card using the Configuration Option Register
  8237. + * We need this to get going...
  8238. + * This is the part of the code that is strongly inspired from wlan-ng
  8239. + *
  8240. + * Note : This code is done with irq enabled. This mean that many
  8241. + * interrupts will occur while we are there. This is why we use the
  8242. + * jiffies to regulate time instead of a straight mdelay(). Usually we
  8243. + * need only around 245 iteration of the loop to do 250 ms delay.
  8244. + *
  8245. + * Note bis : Don't try to access HERMES_CMD during the reset phase.
  8246. + * It just won't work !
  8247. + */
  8248. +static int orinoco_pci_cor_reset(struct orinoco_private *priv)
  8249. +{
  8250. + struct hermes *hw = &priv->hw;
  8251. + unsigned long timeout;
  8252. + u16 reg;
  8253. +
  8254. + /* Assert the reset until the card notices */
  8255. + hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
  8256. + mdelay(HERMES_PCI_COR_ONT);
  8257. +
  8258. + /* Give time for the card to recover from this hard effort */
  8259. + hermes_write_regn(hw, PCI_COR, 0x0000);
  8260. + mdelay(HERMES_PCI_COR_OFFT);
  8261. +
  8262. + /* The card is ready when it's no longer busy */
  8263. + timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT);
  8264. + reg = hermes_read_regn(hw, CMD);
  8265. + while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
  8266. + mdelay(1);
  8267. + reg = hermes_read_regn(hw, CMD);
  8268. + }
  8269. +
  8270. + /* Still busy? */
  8271. + if (reg & HERMES_CMD_BUSY) {
  8272. + printk(KERN_ERR PFX "Busy timeout\n");
  8273. + return -ETIMEDOUT;
  8274. + }
  8275. +
  8276. + return 0;
  8277. +}
  8278. +
  8279. +static int orinoco_pci_init_one(struct pci_dev *pdev,
  8280. + const struct pci_device_id *ent)
  8281. +{
  8282. + int err;
  8283. + struct orinoco_private *priv;
  8284. + struct orinoco_pci_card *card;
  8285. + void __iomem *hermes_io;
  8286. +
  8287. + err = pci_enable_device(pdev);
  8288. + if (err) {
  8289. + printk(KERN_ERR PFX "Cannot enable PCI device\n");
  8290. + return err;
  8291. + }
  8292. +
  8293. + err = pci_request_regions(pdev, DRIVER_NAME);
  8294. + if (err) {
  8295. + printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
  8296. + goto fail_resources;
  8297. + }
  8298. +
  8299. + hermes_io = pci_iomap(pdev, 0, 0);
  8300. + if (!hermes_io) {
  8301. + printk(KERN_ERR PFX "Cannot remap chipset registers\n");
  8302. + err = -EIO;
  8303. + goto fail_map_hermes;
  8304. + }
  8305. +
  8306. + /* Allocate network device */
  8307. + priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
  8308. + orinoco_pci_cor_reset, NULL);
  8309. + if (!priv) {
  8310. + printk(KERN_ERR PFX "Cannot allocate network device\n");
  8311. + err = -ENOMEM;
  8312. + goto fail_alloc;
  8313. + }
  8314. +
  8315. + card = priv->card;
  8316. +
  8317. + hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
  8318. +
  8319. + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
  8320. + DRIVER_NAME, priv);
  8321. + if (err) {
  8322. + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
  8323. + err = -EBUSY;
  8324. + goto fail_irq;
  8325. + }
  8326. +
  8327. + err = orinoco_pci_cor_reset(priv);
  8328. + if (err) {
  8329. + printk(KERN_ERR PFX "Initial reset failed\n");
  8330. + goto fail;
  8331. + }
  8332. +
  8333. + err = orinoco_init(priv);
  8334. + if (err) {
  8335. + printk(KERN_ERR PFX "orinoco_init() failed\n");
  8336. + goto fail;
  8337. + }
  8338. +
  8339. + err = orinoco_if_add(priv, 0, 0, NULL);
  8340. + if (err) {
  8341. + printk(KERN_ERR PFX "orinoco_if_add() failed\n");
  8342. + goto fail_wiphy;
  8343. + }
  8344. +
  8345. + pci_set_drvdata(pdev, priv);
  8346. +
  8347. + return 0;
  8348. +
  8349. + fail_wiphy:
  8350. + wiphy_unregister(priv_to_wiphy(priv));
  8351. + fail:
  8352. + free_irq(pdev->irq, priv);
  8353. +
  8354. + fail_irq:
  8355. + free_orinocodev(priv);
  8356. +
  8357. + fail_alloc:
  8358. + pci_iounmap(pdev, hermes_io);
  8359. +
  8360. + fail_map_hermes:
  8361. + pci_release_regions(pdev);
  8362. +
  8363. + fail_resources:
  8364. + pci_disable_device(pdev);
  8365. +
  8366. + return err;
  8367. +}
  8368. +
  8369. +static void orinoco_pci_remove_one(struct pci_dev *pdev)
  8370. +{
  8371. + struct orinoco_private *priv = pci_get_drvdata(pdev);
  8372. +
  8373. + orinoco_if_del(priv);
  8374. + wiphy_unregister(priv_to_wiphy(priv));
  8375. + free_irq(pdev->irq, priv);
  8376. + free_orinocodev(priv);
  8377. + pci_iounmap(pdev, priv->hw.iobase);
  8378. + pci_release_regions(pdev);
  8379. + pci_disable_device(pdev);
  8380. +}
  8381. +
  8382. +static const struct pci_device_id orinoco_pci_id_table[] = {
  8383. + /* Intersil Prism 3 */
  8384. + {0x1260, 0x3872, PCI_ANY_ID, PCI_ANY_ID,},
  8385. + /* Intersil Prism 2.5 */
  8386. + {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
  8387. + /* Samsung MagicLAN SWL-2210P */
  8388. + {0x167d, 0xa000, PCI_ANY_ID, PCI_ANY_ID,},
  8389. + {0,},
  8390. +};
  8391. +
  8392. +MODULE_DEVICE_TABLE(pci, orinoco_pci_id_table);
  8393. +
  8394. +static struct pci_driver orinoco_pci_driver = {
  8395. + .name = DRIVER_NAME,
  8396. + .id_table = orinoco_pci_id_table,
  8397. + .probe = orinoco_pci_init_one,
  8398. + .remove = orinoco_pci_remove_one,
  8399. + .driver.pm = &orinoco_pci_pm_ops,
  8400. +};
  8401. +
  8402. +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
  8403. + " (Pavel Roskin <proski@gnu.org>,"
  8404. + " David Gibson <hermes@gibson.dropbear.id.au> &"
  8405. + " Jean Tourrilhes <jt@hpl.hp.com>)";
  8406. +MODULE_AUTHOR("Pavel Roskin <proski@gnu.org> &"
  8407. + " David Gibson <hermes@gibson.dropbear.id.au>");
  8408. +MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
  8409. +MODULE_LICENSE("Dual MPL/GPL");
  8410. +
  8411. +static int __init orinoco_pci_init(void)
  8412. +{
  8413. + printk(KERN_DEBUG "%s\n", version);
  8414. + return pci_register_driver(&orinoco_pci_driver);
  8415. +}
  8416. +
  8417. +static void __exit orinoco_pci_exit(void)
  8418. +{
  8419. + pci_unregister_driver(&orinoco_pci_driver);
  8420. +}
  8421. +
  8422. +module_init(orinoco_pci_init);
  8423. +module_exit(orinoco_pci_exit);
  8424. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_pci.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_pci.h
  8425. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_pci.h 1970-01-01 01:00:00.000000000 +0100
  8426. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_pci.h 2026-02-16 14:00:36.623256352 +0100
  8427. @@ -0,0 +1,54 @@
  8428. +/* orinoco_pci.h
  8429. + *
  8430. + * Common code for all Orinoco drivers for PCI devices, including
  8431. + * both native PCI and PCMCIA-to-PCI bridges.
  8432. + *
  8433. + * Copyright (C) 2005, Pavel Roskin.
  8434. + * See main.c for license.
  8435. + */
  8436. +
  8437. +#ifndef _ORINOCO_PCI_H
  8438. +#define _ORINOCO_PCI_H
  8439. +
  8440. +#include <linux/netdevice.h>
  8441. +
  8442. +/* Driver specific data */
  8443. +struct orinoco_pci_card {
  8444. + void __iomem *bridge_io;
  8445. + void __iomem *attr_io;
  8446. +};
  8447. +
  8448. +static int __maybe_unused orinoco_pci_suspend(struct device *dev_d)
  8449. +{
  8450. + struct pci_dev *pdev = to_pci_dev(dev_d);
  8451. + struct orinoco_private *priv = pci_get_drvdata(pdev);
  8452. +
  8453. + orinoco_down(priv);
  8454. + free_irq(pdev->irq, priv);
  8455. +
  8456. + return 0;
  8457. +}
  8458. +
  8459. +static int __maybe_unused orinoco_pci_resume(struct device *dev_d)
  8460. +{
  8461. + struct pci_dev *pdev = to_pci_dev(dev_d);
  8462. + struct orinoco_private *priv = pci_get_drvdata(pdev);
  8463. + struct net_device *dev = priv->ndev;
  8464. + int err;
  8465. +
  8466. + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
  8467. + dev->name, priv);
  8468. + if (err) {
  8469. + printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
  8470. + dev->name);
  8471. + return -EBUSY;
  8472. + }
  8473. +
  8474. + return orinoco_up(priv);
  8475. +}
  8476. +
  8477. +static SIMPLE_DEV_PM_OPS(orinoco_pci_pm_ops,
  8478. + orinoco_pci_suspend,
  8479. + orinoco_pci_resume);
  8480. +
  8481. +#endif /* _ORINOCO_PCI_H */
  8482. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_plx.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_plx.c
  8483. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_plx.c 1970-01-01 01:00:00.000000000 +0100
  8484. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_plx.c 2026-02-16 14:00:36.623256352 +0100
  8485. @@ -0,0 +1,362 @@
  8486. +/* orinoco_plx.c
  8487. + *
  8488. + * Driver for Prism II devices which would usually be driven by orinoco_cs,
  8489. + * but are connected to the PCI bus by a PLX9052.
  8490. + *
  8491. + * Current maintainers are:
  8492. + * Pavel Roskin <proski AT gnu.org>
  8493. + * and David Gibson <hermes AT gibson.dropbear.id.au>
  8494. + *
  8495. + * (C) Copyright David Gibson, IBM Corp. 2001-2003.
  8496. + * Copyright (C) 2001 Daniel Barlow
  8497. + *
  8498. + * The contents of this file are subject to the Mozilla Public License
  8499. + * Version 1.1 (the "License"); you may not use this file except in
  8500. + * compliance with the License. You may obtain a copy of the License
  8501. + * at http://www.mozilla.org/MPL/
  8502. + *
  8503. + * Software distributed under the License is distributed on an "AS IS"
  8504. + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  8505. + * the License for the specific language governing rights and
  8506. + * limitations under the License.
  8507. + *
  8508. + * Alternatively, the contents of this file may be used under the
  8509. + * terms of the GNU General Public License version 2 (the "GPL"), in
  8510. + * which case the provisions of the GPL are applicable instead of the
  8511. + * above. If you wish to allow the use of your version of this file
  8512. + * only under the terms of the GPL and not to allow others to use your
  8513. + * version of this file under the MPL, indicate your decision by
  8514. + * deleting the provisions above and replace them with the notice and
  8515. + * other provisions required by the GPL. If you do not delete the
  8516. + * provisions above, a recipient may use your version of this file
  8517. + * under either the MPL or the GPL.
  8518. + *
  8519. + * Here's the general details on how the PLX9052 adapter works:
  8520. + *
  8521. + * - Two PCI I/O address spaces, one 0x80 long which contains the
  8522. + * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA
  8523. + * slot I/O address space.
  8524. + *
  8525. + * - One PCI memory address space, mapped to the PCMCIA attribute space
  8526. + * (containing the CIS).
  8527. + *
  8528. + * Using the later, you can read through the CIS data to make sure the
  8529. + * card is compatible with the driver. Keep in mind that the PCMCIA
  8530. + * spec specifies the CIS as the lower 8 bits of each word read from
  8531. + * the CIS, so to read the bytes of the CIS, read every other byte
  8532. + * (0,2,4,...). Passing that test, you need to enable the I/O address
  8533. + * space on the PCMCIA card via the PCMCIA COR register. This is the
  8534. + * first byte following the CIS. In my case (which may not have any
  8535. + * relation to what's on the PRISM2 cards), COR was at offset 0x800
  8536. + * within the PCI memory space. Write 0x41 to the COR register to
  8537. + * enable I/O mode and to select level triggered interrupts. To
  8538. + * confirm you actually succeeded, read the COR register back and make
  8539. + * sure it actually got set to 0x41, in case you have an unexpected
  8540. + * card inserted.
  8541. + *
  8542. + * Following that, you can treat the second PCI I/O address space (the
  8543. + * one that's not 0x80 in length) as the PCMCIA I/O space.
  8544. + *
  8545. + * Note that in the Eumitcom's source for their drivers, they register
  8546. + * the interrupt as edge triggered when registering it with the
  8547. + * Windows kernel. I don't recall how to register edge triggered on
  8548. + * Linux (if it can be done at all). But in some experimentation, I
  8549. + * don't see much operational difference between using either
  8550. + * interrupt mode. Don't mess with the interrupt mode in the COR
  8551. + * register though, as the PLX9052 wants level triggers with the way
  8552. + * the serial EEPROM configures it on the WL11000.
  8553. + *
  8554. + * There's some other little quirks related to timing that I bumped
  8555. + * into, but I don't recall right now. Also, there's two variants of
  8556. + * the WL11000 I've seen, revision A1 and T2. These seem to differ
  8557. + * slightly in the timings configured in the wait-state generator in
  8558. + * the PLX9052. There have also been some comments from Eumitcom that
  8559. + * cards shouldn't be hot swapped, apparently due to risk of cooking
  8560. + * the PLX9052. I'm unsure why they believe this, as I can't see
  8561. + * anything in the design that would really cause a problem, except
  8562. + * for crashing drivers not written to expect it. And having developed
  8563. + * drivers for the WL11000, I'd say it's quite tricky to write code
  8564. + * that will successfully deal with a hot unplug. Very odd things
  8565. + * happen on the I/O side of things. But anyway, be warned. Despite
  8566. + * that, I've hot-swapped a number of times during debugging and
  8567. + * driver development for various reasons (stuck WAIT# line after the
  8568. + * radio card's firmware locks up).
  8569. + */
  8570. +
  8571. +#define DRIVER_NAME "orinoco_plx"
  8572. +#define PFX DRIVER_NAME ": "
  8573. +
  8574. +#include <linux/module.h>
  8575. +#include <linux/kernel.h>
  8576. +#include <linux/init.h>
  8577. +#include <linux/delay.h>
  8578. +#include <linux/pci.h>
  8579. +#include <pcmcia/cisreg.h>
  8580. +
  8581. +#include "orinoco.h"
  8582. +#include "orinoco_pci.h"
  8583. +
  8584. +#define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */
  8585. +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
  8586. +#define COR_RESET (0x80) /* reset bit in the COR register */
  8587. +#define PLX_RESET_TIME (500) /* milliseconds */
  8588. +
  8589. +#define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */
  8590. +#define PLX_INTCSR_INTEN (1 << 6) /* Interrupt Enable bit */
  8591. +
  8592. +/*
  8593. + * Do a soft reset of the card using the Configuration Option Register
  8594. + */
  8595. +static int orinoco_plx_cor_reset(struct orinoco_private *priv)
  8596. +{
  8597. + struct hermes *hw = &priv->hw;
  8598. + struct orinoco_pci_card *card = priv->card;
  8599. + unsigned long timeout;
  8600. + u16 reg;
  8601. +
  8602. + iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET);
  8603. + mdelay(1);
  8604. +
  8605. + iowrite8(COR_VALUE, card->attr_io + COR_OFFSET);
  8606. + mdelay(1);
  8607. +
  8608. + /* Just in case, wait more until the card is no longer busy */
  8609. + timeout = jiffies + msecs_to_jiffies(PLX_RESET_TIME);
  8610. + reg = hermes_read_regn(hw, CMD);
  8611. + while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
  8612. + mdelay(1);
  8613. + reg = hermes_read_regn(hw, CMD);
  8614. + }
  8615. +
  8616. + /* Still busy? */
  8617. + if (reg & HERMES_CMD_BUSY) {
  8618. + printk(KERN_ERR PFX "Busy timeout\n");
  8619. + return -ETIMEDOUT;
  8620. + }
  8621. +
  8622. + return 0;
  8623. +}
  8624. +
  8625. +static int orinoco_plx_hw_init(struct orinoco_pci_card *card)
  8626. +{
  8627. + int i;
  8628. + u32 csr_reg;
  8629. + static const u8 cis_magic[] = {
  8630. + 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67
  8631. + };
  8632. +
  8633. + printk(KERN_DEBUG PFX "CIS: ");
  8634. + for (i = 0; i < 16; i++)
  8635. + printk("%02X:", ioread8(card->attr_io + (i << 1)));
  8636. + printk("\n");
  8637. +
  8638. + /* Verify whether a supported PC card is present */
  8639. + /* FIXME: we probably need to be smarted about this */
  8640. + for (i = 0; i < sizeof(cis_magic); i++) {
  8641. + if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) {
  8642. + printk(KERN_ERR PFX "The CIS value of Prism2 PC "
  8643. + "card is unexpected\n");
  8644. + return -ENODEV;
  8645. + }
  8646. + }
  8647. +
  8648. + /* bjoern: We need to tell the card to enable interrupts, in
  8649. + case the serial eprom didn't do this already. See the
  8650. + PLX9052 data book, p8-1 and 8-24 for reference. */
  8651. + csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
  8652. + if (!(csr_reg & PLX_INTCSR_INTEN)) {
  8653. + csr_reg |= PLX_INTCSR_INTEN;
  8654. + iowrite32(csr_reg, card->bridge_io + PLX_INTCSR);
  8655. + csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
  8656. + if (!(csr_reg & PLX_INTCSR_INTEN)) {
  8657. + printk(KERN_ERR PFX "Cannot enable interrupts\n");
  8658. + return -EIO;
  8659. + }
  8660. + }
  8661. +
  8662. + return 0;
  8663. +}
  8664. +
  8665. +static int orinoco_plx_init_one(struct pci_dev *pdev,
  8666. + const struct pci_device_id *ent)
  8667. +{
  8668. + int err;
  8669. + struct orinoco_private *priv;
  8670. + struct orinoco_pci_card *card;
  8671. + void __iomem *hermes_io, *attr_io, *bridge_io;
  8672. +
  8673. + err = pci_enable_device(pdev);
  8674. + if (err) {
  8675. + printk(KERN_ERR PFX "Cannot enable PCI device\n");
  8676. + return err;
  8677. + }
  8678. +
  8679. + err = pci_request_regions(pdev, DRIVER_NAME);
  8680. + if (err) {
  8681. + printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
  8682. + goto fail_resources;
  8683. + }
  8684. +
  8685. + bridge_io = pci_iomap(pdev, 1, 0);
  8686. + if (!bridge_io) {
  8687. + printk(KERN_ERR PFX "Cannot map bridge registers\n");
  8688. + err = -EIO;
  8689. + goto fail_map_bridge;
  8690. + }
  8691. +
  8692. + attr_io = pci_iomap(pdev, 2, 0);
  8693. + if (!attr_io) {
  8694. + printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
  8695. + err = -EIO;
  8696. + goto fail_map_attr;
  8697. + }
  8698. +
  8699. + hermes_io = pci_iomap(pdev, 3, 0);
  8700. + if (!hermes_io) {
  8701. + printk(KERN_ERR PFX "Cannot map chipset registers\n");
  8702. + err = -EIO;
  8703. + goto fail_map_hermes;
  8704. + }
  8705. +
  8706. + /* Allocate network device */
  8707. + priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
  8708. + orinoco_plx_cor_reset, NULL);
  8709. + if (!priv) {
  8710. + printk(KERN_ERR PFX "Cannot allocate network device\n");
  8711. + err = -ENOMEM;
  8712. + goto fail_alloc;
  8713. + }
  8714. +
  8715. + card = priv->card;
  8716. + card->bridge_io = bridge_io;
  8717. + card->attr_io = attr_io;
  8718. +
  8719. + hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
  8720. +
  8721. + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
  8722. + DRIVER_NAME, priv);
  8723. + if (err) {
  8724. + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
  8725. + err = -EBUSY;
  8726. + goto fail_irq;
  8727. + }
  8728. +
  8729. + err = orinoco_plx_hw_init(card);
  8730. + if (err) {
  8731. + printk(KERN_ERR PFX "Hardware initialization failed\n");
  8732. + goto fail;
  8733. + }
  8734. +
  8735. + err = orinoco_plx_cor_reset(priv);
  8736. + if (err) {
  8737. + printk(KERN_ERR PFX "Initial reset failed\n");
  8738. + goto fail;
  8739. + }
  8740. +
  8741. + err = orinoco_init(priv);
  8742. + if (err) {
  8743. + printk(KERN_ERR PFX "orinoco_init() failed\n");
  8744. + goto fail;
  8745. + }
  8746. +
  8747. + err = orinoco_if_add(priv, 0, 0, NULL);
  8748. + if (err) {
  8749. + printk(KERN_ERR PFX "orinoco_if_add() failed\n");
  8750. + goto fail_wiphy;
  8751. + }
  8752. +
  8753. + pci_set_drvdata(pdev, priv);
  8754. +
  8755. + return 0;
  8756. +
  8757. + fail_wiphy:
  8758. + wiphy_unregister(priv_to_wiphy(priv));
  8759. + fail:
  8760. + free_irq(pdev->irq, priv);
  8761. +
  8762. + fail_irq:
  8763. + free_orinocodev(priv);
  8764. +
  8765. + fail_alloc:
  8766. + pci_iounmap(pdev, hermes_io);
  8767. +
  8768. + fail_map_hermes:
  8769. + pci_iounmap(pdev, attr_io);
  8770. +
  8771. + fail_map_attr:
  8772. + pci_iounmap(pdev, bridge_io);
  8773. +
  8774. + fail_map_bridge:
  8775. + pci_release_regions(pdev);
  8776. +
  8777. + fail_resources:
  8778. + pci_disable_device(pdev);
  8779. +
  8780. + return err;
  8781. +}
  8782. +
  8783. +static void orinoco_plx_remove_one(struct pci_dev *pdev)
  8784. +{
  8785. + struct orinoco_private *priv = pci_get_drvdata(pdev);
  8786. + struct orinoco_pci_card *card = priv->card;
  8787. +
  8788. + orinoco_if_del(priv);
  8789. + wiphy_unregister(priv_to_wiphy(priv));
  8790. + free_irq(pdev->irq, priv);
  8791. + free_orinocodev(priv);
  8792. + pci_iounmap(pdev, priv->hw.iobase);
  8793. + pci_iounmap(pdev, card->attr_io);
  8794. + pci_iounmap(pdev, card->bridge_io);
  8795. + pci_release_regions(pdev);
  8796. + pci_disable_device(pdev);
  8797. +}
  8798. +
  8799. +static const struct pci_device_id orinoco_plx_id_table[] = {
  8800. + {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */
  8801. + {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */
  8802. + {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */
  8803. + {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W,
  8804. + Eumitcom PCI WL11000,
  8805. + Addtron AWA-100 */
  8806. + {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */
  8807. + {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */
  8808. + {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */
  8809. + {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */
  8810. + {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by
  8811. + Brendan W. McAdams <rit AT jacked-in.org> */
  8812. + {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by
  8813. + Damien Persohn <damien AT persohn.net> */
  8814. + {0,},
  8815. +};
  8816. +
  8817. +MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table);
  8818. +
  8819. +static struct pci_driver orinoco_plx_driver = {
  8820. + .name = DRIVER_NAME,
  8821. + .id_table = orinoco_plx_id_table,
  8822. + .probe = orinoco_plx_init_one,
  8823. + .remove = orinoco_plx_remove_one,
  8824. + .driver.pm = &orinoco_pci_pm_ops,
  8825. +};
  8826. +
  8827. +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
  8828. + " (Pavel Roskin <proski@gnu.org>,"
  8829. + " David Gibson <hermes@gibson.dropbear.id.au>,"
  8830. + " Daniel Barlow <dan@telent.net>)";
  8831. +MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
  8832. +MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
  8833. +MODULE_LICENSE("Dual MPL/GPL");
  8834. +
  8835. +static int __init orinoco_plx_init(void)
  8836. +{
  8837. + printk(KERN_DEBUG "%s\n", version);
  8838. + return pci_register_driver(&orinoco_plx_driver);
  8839. +}
  8840. +
  8841. +static void __exit orinoco_plx_exit(void)
  8842. +{
  8843. + pci_unregister_driver(&orinoco_plx_driver);
  8844. +}
  8845. +
  8846. +module_init(orinoco_plx_init);
  8847. +module_exit(orinoco_plx_exit);
  8848. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c
  8849. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c 1970-01-01 01:00:00.000000000 +0100
  8850. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_tmd.c 2026-02-16 14:00:36.623256352 +0100
  8851. @@ -0,0 +1,237 @@
  8852. +/* orinoco_tmd.c
  8853. + *
  8854. + * Driver for Prism II devices which would usually be driven by orinoco_cs,
  8855. + * but are connected to the PCI bus by a TMD7160.
  8856. + *
  8857. + * Copyright (C) 2003 Joerg Dorchain <joerg AT dorchain.net>
  8858. + * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow
  8859. + *
  8860. + * The contents of this file are subject to the Mozilla Public License
  8861. + * Version 1.1 (the "License"); you may not use this file except in
  8862. + * compliance with the License. You may obtain a copy of the License
  8863. + * at http://www.mozilla.org/MPL/
  8864. + *
  8865. + * Software distributed under the License is distributed on an "AS IS"
  8866. + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  8867. + * the License for the specific language governing rights and
  8868. + * limitations under the License.
  8869. + *
  8870. + * Alternatively, the contents of this file may be used under the
  8871. + * terms of the GNU General Public License version 2 (the "GPL"), in
  8872. + * which case the provisions of the GPL are applicable instead of the
  8873. + * above. If you wish to allow the use of your version of this file
  8874. + * only under the terms of the GPL and not to allow others to use your
  8875. + * version of this file under the MPL, indicate your decision by
  8876. + * deleting the provisions above and replace them with the notice and
  8877. + * other provisions required by the GPL. If you do not delete the
  8878. + * provisions above, a recipient may use your version of this file
  8879. + * under either the MPL or the GPL.
  8880. + *
  8881. + * The actual driving is done by main.c, this is just resource
  8882. + * allocation stuff.
  8883. + *
  8884. + * This driver is modeled after the orinoco_plx driver. The main
  8885. + * difference is that the TMD chip has only IO port ranges and doesn't
  8886. + * provide access to the PCMCIA attribute space.
  8887. + *
  8888. + * Pheecom sells cards with the TMD chip as "ASIC version"
  8889. + */
  8890. +
  8891. +#define DRIVER_NAME "orinoco_tmd"
  8892. +#define PFX DRIVER_NAME ": "
  8893. +
  8894. +#include <linux/module.h>
  8895. +#include <linux/kernel.h>
  8896. +#include <linux/init.h>
  8897. +#include <linux/delay.h>
  8898. +#include <linux/pci.h>
  8899. +#include <pcmcia/cisreg.h>
  8900. +
  8901. +#include "orinoco.h"
  8902. +#include "orinoco_pci.h"
  8903. +
  8904. +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */
  8905. +#define COR_RESET (0x80) /* reset bit in the COR register */
  8906. +#define TMD_RESET_TIME (500) /* milliseconds */
  8907. +
  8908. +/*
  8909. + * Do a soft reset of the card using the Configuration Option Register
  8910. + */
  8911. +static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
  8912. +{
  8913. + struct hermes *hw = &priv->hw;
  8914. + struct orinoco_pci_card *card = priv->card;
  8915. + unsigned long timeout;
  8916. + u16 reg;
  8917. +
  8918. + iowrite8(COR_VALUE | COR_RESET, card->bridge_io);
  8919. + mdelay(1);
  8920. +
  8921. + iowrite8(COR_VALUE, card->bridge_io);
  8922. + mdelay(1);
  8923. +
  8924. + /* Just in case, wait more until the card is no longer busy */
  8925. + timeout = jiffies + msecs_to_jiffies(TMD_RESET_TIME);
  8926. + reg = hermes_read_regn(hw, CMD);
  8927. + while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
  8928. + mdelay(1);
  8929. + reg = hermes_read_regn(hw, CMD);
  8930. + }
  8931. +
  8932. + /* Still busy? */
  8933. + if (reg & HERMES_CMD_BUSY) {
  8934. + printk(KERN_ERR PFX "Busy timeout\n");
  8935. + return -ETIMEDOUT;
  8936. + }
  8937. +
  8938. + return 0;
  8939. +}
  8940. +
  8941. +
  8942. +static int orinoco_tmd_init_one(struct pci_dev *pdev,
  8943. + const struct pci_device_id *ent)
  8944. +{
  8945. + int err;
  8946. + struct orinoco_private *priv;
  8947. + struct orinoco_pci_card *card;
  8948. + void __iomem *hermes_io, *bridge_io;
  8949. +
  8950. + err = pci_enable_device(pdev);
  8951. + if (err) {
  8952. + printk(KERN_ERR PFX "Cannot enable PCI device\n");
  8953. + return err;
  8954. + }
  8955. +
  8956. + err = pci_request_regions(pdev, DRIVER_NAME);
  8957. + if (err) {
  8958. + printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
  8959. + goto fail_resources;
  8960. + }
  8961. +
  8962. + bridge_io = pci_iomap(pdev, 1, 0);
  8963. + if (!bridge_io) {
  8964. + printk(KERN_ERR PFX "Cannot map bridge registers\n");
  8965. + err = -EIO;
  8966. + goto fail_map_bridge;
  8967. + }
  8968. +
  8969. + hermes_io = pci_iomap(pdev, 2, 0);
  8970. + if (!hermes_io) {
  8971. + printk(KERN_ERR PFX "Cannot map chipset registers\n");
  8972. + err = -EIO;
  8973. + goto fail_map_hermes;
  8974. + }
  8975. +
  8976. + /* Allocate network device */
  8977. + priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
  8978. + orinoco_tmd_cor_reset, NULL);
  8979. + if (!priv) {
  8980. + printk(KERN_ERR PFX "Cannot allocate network device\n");
  8981. + err = -ENOMEM;
  8982. + goto fail_alloc;
  8983. + }
  8984. +
  8985. + card = priv->card;
  8986. + card->bridge_io = bridge_io;
  8987. +
  8988. + hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
  8989. +
  8990. + err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
  8991. + DRIVER_NAME, priv);
  8992. + if (err) {
  8993. + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
  8994. + err = -EBUSY;
  8995. + goto fail_irq;
  8996. + }
  8997. +
  8998. + err = orinoco_tmd_cor_reset(priv);
  8999. + if (err) {
  9000. + printk(KERN_ERR PFX "Initial reset failed\n");
  9001. + goto fail;
  9002. + }
  9003. +
  9004. + err = orinoco_init(priv);
  9005. + if (err) {
  9006. + printk(KERN_ERR PFX "orinoco_init() failed\n");
  9007. + goto fail;
  9008. + }
  9009. +
  9010. + err = orinoco_if_add(priv, 0, 0, NULL);
  9011. + if (err) {
  9012. + printk(KERN_ERR PFX "orinoco_if_add() failed\n");
  9013. + goto fail;
  9014. + }
  9015. +
  9016. + pci_set_drvdata(pdev, priv);
  9017. +
  9018. + return 0;
  9019. +
  9020. + fail:
  9021. + free_irq(pdev->irq, priv);
  9022. +
  9023. + fail_irq:
  9024. + free_orinocodev(priv);
  9025. +
  9026. + fail_alloc:
  9027. + pci_iounmap(pdev, hermes_io);
  9028. +
  9029. + fail_map_hermes:
  9030. + pci_iounmap(pdev, bridge_io);
  9031. +
  9032. + fail_map_bridge:
  9033. + pci_release_regions(pdev);
  9034. +
  9035. + fail_resources:
  9036. + pci_disable_device(pdev);
  9037. +
  9038. + return err;
  9039. +}
  9040. +
  9041. +static void orinoco_tmd_remove_one(struct pci_dev *pdev)
  9042. +{
  9043. + struct orinoco_private *priv = pci_get_drvdata(pdev);
  9044. + struct orinoco_pci_card *card = priv->card;
  9045. +
  9046. + orinoco_if_del(priv);
  9047. + free_irq(pdev->irq, priv);
  9048. + free_orinocodev(priv);
  9049. + pci_iounmap(pdev, priv->hw.iobase);
  9050. + pci_iounmap(pdev, card->bridge_io);
  9051. + pci_release_regions(pdev);
  9052. + pci_disable_device(pdev);
  9053. +}
  9054. +
  9055. +static const struct pci_device_id orinoco_tmd_id_table[] = {
  9056. + {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */
  9057. + {0,},
  9058. +};
  9059. +
  9060. +MODULE_DEVICE_TABLE(pci, orinoco_tmd_id_table);
  9061. +
  9062. +static struct pci_driver orinoco_tmd_driver = {
  9063. + .name = DRIVER_NAME,
  9064. + .id_table = orinoco_tmd_id_table,
  9065. + .probe = orinoco_tmd_init_one,
  9066. + .remove = orinoco_tmd_remove_one,
  9067. + .driver.pm = &orinoco_pci_pm_ops,
  9068. +};
  9069. +
  9070. +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
  9071. + " (Joerg Dorchain <joerg@dorchain.net>)";
  9072. +MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
  9073. +MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge");
  9074. +MODULE_LICENSE("Dual MPL/GPL");
  9075. +
  9076. +static int __init orinoco_tmd_init(void)
  9077. +{
  9078. + printk(KERN_DEBUG "%s\n", version);
  9079. + return pci_register_driver(&orinoco_tmd_driver);
  9080. +}
  9081. +
  9082. +static void __exit orinoco_tmd_exit(void)
  9083. +{
  9084. + pci_unregister_driver(&orinoco_tmd_driver);
  9085. +}
  9086. +
  9087. +module_init(orinoco_tmd_init);
  9088. +module_exit(orinoco_tmd_exit);
  9089. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_usb.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
  9090. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/orinoco_usb.c 1970-01-01 01:00:00.000000000 +0100
  9091. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/orinoco_usb.c 2026-02-16 14:00:36.623256352 +0100
  9092. @@ -0,0 +1,1787 @@
  9093. +/*
  9094. + * USB Orinoco driver
  9095. + *
  9096. + * Copyright (c) 2003 Manuel Estrada Sainz
  9097. + *
  9098. + * The contents of this file are subject to the Mozilla Public License
  9099. + * Version 1.1 (the "License"); you may not use this file except in
  9100. + * compliance with the License. You may obtain a copy of the License
  9101. + * at http://www.mozilla.org/MPL/
  9102. + *
  9103. + * Software distributed under the License is distributed on an "AS IS"
  9104. + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  9105. + * the License for the specific language governing rights and
  9106. + * limitations under the License.
  9107. + *
  9108. + * Alternatively, the contents of this file may be used under the
  9109. + * terms of the GNU General Public License version 2 (the "GPL"), in
  9110. + * which case the provisions of the GPL are applicable instead of the
  9111. + * above. If you wish to allow the use of your version of this file
  9112. + * only under the terms of the GPL and not to allow others to use your
  9113. + * version of this file under the MPL, indicate your decision by
  9114. + * deleting the provisions above and replace them with the notice and
  9115. + * other provisions required by the GPL. If you do not delete the
  9116. + * provisions above, a recipient may use your version of this file
  9117. + * under either the MPL or the GPL.
  9118. + *
  9119. + * Queueing code based on linux-wlan-ng 0.2.1-pre5
  9120. + *
  9121. + * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
  9122. + *
  9123. + * The license is the same as above.
  9124. + *
  9125. + * Initialy based on USB Skeleton driver - 0.7
  9126. + *
  9127. + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
  9128. + *
  9129. + * This program is free software; you can redistribute it and/or
  9130. + * modify it under the terms of the GNU General Public License as
  9131. + * published by the Free Software Foundation; either version 2 of
  9132. + * the License, or (at your option) any later version.
  9133. + *
  9134. + * NOTE: The original USB Skeleton driver is GPL, but all that code is
  9135. + * gone so MPL/GPL applies.
  9136. + */
  9137. +
  9138. +#define DRIVER_NAME "orinoco_usb"
  9139. +#define PFX DRIVER_NAME ": "
  9140. +
  9141. +#include <linux/module.h>
  9142. +#include <linux/kernel.h>
  9143. +#include <linux/sched.h>
  9144. +#include <linux/signal.h>
  9145. +#include <linux/errno.h>
  9146. +#include <linux/poll.h>
  9147. +#include <linux/slab.h>
  9148. +#include <linux/fcntl.h>
  9149. +#include <linux/spinlock.h>
  9150. +#include <linux/list.h>
  9151. +#include <linux/usb.h>
  9152. +#include <linux/timer.h>
  9153. +
  9154. +#include <linux/netdevice.h>
  9155. +#include <linux/if_arp.h>
  9156. +#include <linux/etherdevice.h>
  9157. +#include <linux/wireless.h>
  9158. +#include <linux/firmware.h>
  9159. +#include <linux/refcount.h>
  9160. +
  9161. +#include "mic.h"
  9162. +#include "orinoco.h"
  9163. +
  9164. +#ifndef URB_ASYNC_UNLINK
  9165. +#define URB_ASYNC_UNLINK 0
  9166. +#endif
  9167. +
  9168. +struct header_struct {
  9169. + /* 802.3 */
  9170. + u8 dest[ETH_ALEN];
  9171. + u8 src[ETH_ALEN];
  9172. + __be16 len;
  9173. + /* 802.2 */
  9174. + u8 dsap;
  9175. + u8 ssap;
  9176. + u8 ctrl;
  9177. + /* SNAP */
  9178. + u8 oui[3];
  9179. + __be16 ethertype;
  9180. +} __packed;
  9181. +
  9182. +struct ez_usb_fw {
  9183. + u16 size;
  9184. + const u8 *code;
  9185. +};
  9186. +
  9187. +static struct ez_usb_fw firmware = {
  9188. + .size = 0,
  9189. + .code = NULL,
  9190. +};
  9191. +
  9192. +/* Debugging macros */
  9193. +#undef err
  9194. +#define err(format, arg...) \
  9195. + do { printk(KERN_ERR PFX format "\n", ## arg); } while (0)
  9196. +
  9197. +MODULE_FIRMWARE("orinoco_ezusb_fw");
  9198. +
  9199. +/*
  9200. + * Under some conditions, the card gets stuck and stops paying attention
  9201. + * to the world (i.e. data communication stalls) until we do something to
  9202. + * it. Sending an INQ_TALLIES command seems to be enough and should be
  9203. + * harmless otherwise. This behaviour has been observed when using the
  9204. + * driver on a systemimager client during installation. In the past a
  9205. + * timer was used to send INQ_TALLIES commands when there was no other
  9206. + * activity, but it was troublesome and was removed.
  9207. + */
  9208. +
  9209. +#define USB_COMPAQ_VENDOR_ID 0x049f /* Compaq Computer Corp. */
  9210. +#define USB_COMPAQ_WL215_ID 0x001f /* Compaq WL215 USB Adapter */
  9211. +#define USB_COMPAQ_W200_ID 0x0076 /* Compaq W200 USB Adapter */
  9212. +#define USB_HP_WL215_ID 0x0082 /* Compaq WL215 USB Adapter */
  9213. +
  9214. +#define USB_MELCO_VENDOR_ID 0x0411
  9215. +#define USB_BUFFALO_L11_ID 0x0006 /* BUFFALO WLI-USB-L11 */
  9216. +#define USB_BUFFALO_L11G_WR_ID 0x000B /* BUFFALO WLI-USB-L11G-WR */
  9217. +#define USB_BUFFALO_L11G_ID 0x000D /* BUFFALO WLI-USB-L11G */
  9218. +
  9219. +#define USB_LUCENT_VENDOR_ID 0x047E /* Lucent Technologies */
  9220. +#define USB_LUCENT_ORINOCO_ID 0x0300 /* Lucent/Agere Orinoco USB Client */
  9221. +
  9222. +#define USB_AVAYA8_VENDOR_ID 0x0D98
  9223. +#define USB_AVAYAE_VENDOR_ID 0x0D9E
  9224. +#define USB_AVAYA_WIRELESS_ID 0x0300 /* Avaya USB Wireless Card */
  9225. +
  9226. +#define USB_AGERE_VENDOR_ID 0x0D4E /* Agere Systems */
  9227. +#define USB_AGERE_MODEL0801_ID 0x1000 /* USB Wireless Card Model 0801 */
  9228. +#define USB_AGERE_MODEL0802_ID 0x1001 /* USB Wireless Card Model 0802 */
  9229. +#define USB_AGERE_REBRANDED_ID 0x047A /* USB WLAN Card */
  9230. +
  9231. +#define USB_ELSA_VENDOR_ID 0x05CC
  9232. +#define USB_ELSA_AIRLANCER_ID 0x3100 /* ELSA AirLancer USB-11 */
  9233. +
  9234. +#define USB_LEGEND_VENDOR_ID 0x0E7C
  9235. +#define USB_LEGEND_JOYNET_ID 0x0300 /* Joynet USB WLAN Card */
  9236. +
  9237. +#define USB_SAMSUNG_VENDOR_ID 0x04E8
  9238. +#define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */
  9239. +#define USB_SAMSUNG_SEW2001U2_ID 0x5B11 /* Samsung SEW-2001u Card */
  9240. +#define USB_SAMSUNG_SEW2003U_ID 0x7011 /* Samsung SEW-2003U Card */
  9241. +
  9242. +#define USB_IGATE_VENDOR_ID 0x0681
  9243. +#define USB_IGATE_IGATE_11M_ID 0x0012 /* I-GATE 11M USB Card */
  9244. +
  9245. +#define USB_FUJITSU_VENDOR_ID 0x0BF8
  9246. +#define USB_FUJITSU_E1100_ID 0x1002 /* connect2AIR WLAN E-1100 USB */
  9247. +
  9248. +#define USB_2WIRE_VENDOR_ID 0x1630
  9249. +#define USB_2WIRE_WIRELESS_ID 0xff81 /* 2Wire USB Wireless adapter */
  9250. +
  9251. +
  9252. +#define EZUSB_REQUEST_FW_TRANS 0xA0
  9253. +#define EZUSB_REQUEST_TRIGGER 0xAA
  9254. +#define EZUSB_REQUEST_TRIG_AC 0xAC
  9255. +#define EZUSB_CPUCS_REG 0x7F92
  9256. +
  9257. +#define EZUSB_RID_TX 0x0700
  9258. +#define EZUSB_RID_RX 0x0701
  9259. +#define EZUSB_RID_INIT1 0x0702
  9260. +#define EZUSB_RID_ACK 0x0710
  9261. +#define EZUSB_RID_READ_PDA 0x0800
  9262. +#define EZUSB_RID_PROG_INIT 0x0852
  9263. +#define EZUSB_RID_PROG_SET_ADDR 0x0853
  9264. +#define EZUSB_RID_PROG_BYTES 0x0854
  9265. +#define EZUSB_RID_PROG_END 0x0855
  9266. +#define EZUSB_RID_DOCMD 0x0860
  9267. +
  9268. +/* Recognize info frames */
  9269. +#define EZUSB_IS_INFO(id) ((id >= 0xF000) && (id <= 0xF2FF))
  9270. +
  9271. +#define EZUSB_MAGIC 0x0210
  9272. +
  9273. +#define EZUSB_FRAME_DATA 1
  9274. +#define EZUSB_FRAME_CONTROL 2
  9275. +
  9276. +#define DEF_TIMEOUT (3 * HZ)
  9277. +
  9278. +#define BULK_BUF_SIZE 2048
  9279. +
  9280. +#define MAX_DL_SIZE (BULK_BUF_SIZE - sizeof(struct ezusb_packet))
  9281. +
  9282. +#define FW_BUF_SIZE 64
  9283. +#define FW_VAR_OFFSET_PTR 0x359
  9284. +#define FW_VAR_VALUE 0
  9285. +#define FW_HOLE_START 0x100
  9286. +#define FW_HOLE_END 0x300
  9287. +
  9288. +struct ezusb_packet {
  9289. + __le16 magic; /* 0x0210 */
  9290. + u8 req_reply_count;
  9291. + u8 ans_reply_count;
  9292. + __le16 frame_type; /* 0x01 for data frames, 0x02 otherwise */
  9293. + __le16 size; /* transport size */
  9294. + __le16 crc; /* CRC up to here */
  9295. + __le16 hermes_len;
  9296. + __le16 hermes_rid;
  9297. + u8 data[];
  9298. +} __packed;
  9299. +
  9300. +/* Table of devices that work or may work with this driver */
  9301. +static const struct usb_device_id ezusb_table[] = {
  9302. + {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_WL215_ID)},
  9303. + {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_HP_WL215_ID)},
  9304. + {USB_DEVICE(USB_COMPAQ_VENDOR_ID, USB_COMPAQ_W200_ID)},
  9305. + {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11_ID)},
  9306. + {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_WR_ID)},
  9307. + {USB_DEVICE(USB_MELCO_VENDOR_ID, USB_BUFFALO_L11G_ID)},
  9308. + {USB_DEVICE(USB_LUCENT_VENDOR_ID, USB_LUCENT_ORINOCO_ID)},
  9309. + {USB_DEVICE(USB_AVAYA8_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
  9310. + {USB_DEVICE(USB_AVAYAE_VENDOR_ID, USB_AVAYA_WIRELESS_ID)},
  9311. + {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0801_ID)},
  9312. + {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_MODEL0802_ID)},
  9313. + {USB_DEVICE(USB_ELSA_VENDOR_ID, USB_ELSA_AIRLANCER_ID)},
  9314. + {USB_DEVICE(USB_LEGEND_VENDOR_ID, USB_LEGEND_JOYNET_ID)},
  9315. + {USB_DEVICE_VER(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U1_ID,
  9316. + 0, 0)},
  9317. + {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2001U2_ID)},
  9318. + {USB_DEVICE(USB_SAMSUNG_VENDOR_ID, USB_SAMSUNG_SEW2003U_ID)},
  9319. + {USB_DEVICE(USB_IGATE_VENDOR_ID, USB_IGATE_IGATE_11M_ID)},
  9320. + {USB_DEVICE(USB_FUJITSU_VENDOR_ID, USB_FUJITSU_E1100_ID)},
  9321. + {USB_DEVICE(USB_2WIRE_VENDOR_ID, USB_2WIRE_WIRELESS_ID)},
  9322. + {USB_DEVICE(USB_AGERE_VENDOR_ID, USB_AGERE_REBRANDED_ID)},
  9323. + {} /* Terminating entry */
  9324. +};
  9325. +
  9326. +MODULE_DEVICE_TABLE(usb, ezusb_table);
  9327. +
  9328. +/* Structure to hold all of our device specific stuff */
  9329. +struct ezusb_priv {
  9330. + struct usb_device *udev;
  9331. + struct net_device *dev;
  9332. + struct mutex mtx;
  9333. + spinlock_t req_lock;
  9334. + struct list_head req_pending;
  9335. + struct list_head req_active;
  9336. + spinlock_t reply_count_lock;
  9337. + u16 hermes_reg_fake[0x40];
  9338. + u8 *bap_buf;
  9339. + struct urb *read_urb;
  9340. + int read_pipe;
  9341. + int write_pipe;
  9342. + u8 reply_count;
  9343. +};
  9344. +
  9345. +enum ezusb_state {
  9346. + EZUSB_CTX_START,
  9347. + EZUSB_CTX_QUEUED,
  9348. + EZUSB_CTX_REQ_SUBMITTED,
  9349. + EZUSB_CTX_REQ_COMPLETE,
  9350. + EZUSB_CTX_RESP_RECEIVED,
  9351. + EZUSB_CTX_REQ_TIMEOUT,
  9352. + EZUSB_CTX_REQ_FAILED,
  9353. + EZUSB_CTX_RESP_TIMEOUT,
  9354. + EZUSB_CTX_REQSUBMIT_FAIL,
  9355. + EZUSB_CTX_COMPLETE,
  9356. +};
  9357. +
  9358. +struct request_context {
  9359. + struct list_head list;
  9360. + refcount_t refcount;
  9361. + struct completion done; /* Signals that CTX is dead */
  9362. + int killed;
  9363. + struct urb *outurb; /* OUT for req pkt */
  9364. + struct ezusb_priv *upriv;
  9365. + struct ezusb_packet *buf;
  9366. + int buf_length;
  9367. + struct timer_list timer; /* Timeout handling */
  9368. + enum ezusb_state state; /* Current state */
  9369. + /* the RID that we will wait for */
  9370. + u16 out_rid;
  9371. + u16 in_rid;
  9372. +};
  9373. +
  9374. +
  9375. +/* Forward declarations */
  9376. +static void ezusb_ctx_complete(struct request_context *ctx);
  9377. +static void ezusb_req_queue_run(struct ezusb_priv *upriv);
  9378. +static void ezusb_bulk_in_callback(struct urb *urb);
  9379. +
  9380. +static inline u8 ezusb_reply_inc(u8 count)
  9381. +{
  9382. + if (count < 0x7F)
  9383. + return count + 1;
  9384. + else
  9385. + return 1;
  9386. +}
  9387. +
  9388. +static void ezusb_request_context_put(struct request_context *ctx)
  9389. +{
  9390. + if (!refcount_dec_and_test(&ctx->refcount))
  9391. + return;
  9392. +
  9393. + WARN_ON(!ctx->done.done);
  9394. + BUG_ON(ctx->outurb->status == -EINPROGRESS);
  9395. + BUG_ON(timer_pending(&ctx->timer));
  9396. + usb_free_urb(ctx->outurb);
  9397. + kfree(ctx->buf);
  9398. + kfree(ctx);
  9399. +}
  9400. +
  9401. +static inline void ezusb_mod_timer(struct ezusb_priv *upriv,
  9402. + struct timer_list *timer,
  9403. + unsigned long expire)
  9404. +{
  9405. + if (!upriv->udev)
  9406. + return;
  9407. + mod_timer(timer, expire);
  9408. +}
  9409. +
  9410. +static void ezusb_request_timerfn(struct timer_list *t)
  9411. +{
  9412. + struct request_context *ctx = from_timer(ctx, t, timer);
  9413. +
  9414. + ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
  9415. + if (usb_unlink_urb(ctx->outurb) == -EINPROGRESS) {
  9416. + ctx->state = EZUSB_CTX_REQ_TIMEOUT;
  9417. + } else {
  9418. + ctx->state = EZUSB_CTX_RESP_TIMEOUT;
  9419. + dev_dbg(&ctx->outurb->dev->dev, "couldn't unlink\n");
  9420. + refcount_inc(&ctx->refcount);
  9421. + ctx->killed = 1;
  9422. + ezusb_ctx_complete(ctx);
  9423. + ezusb_request_context_put(ctx);
  9424. + }
  9425. +};
  9426. +
  9427. +static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
  9428. + u16 out_rid, u16 in_rid)
  9429. +{
  9430. + struct request_context *ctx;
  9431. +
  9432. + ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
  9433. + if (!ctx)
  9434. + return NULL;
  9435. +
  9436. + ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC);
  9437. + if (!ctx->buf) {
  9438. + kfree(ctx);
  9439. + return NULL;
  9440. + }
  9441. + ctx->outurb = usb_alloc_urb(0, GFP_ATOMIC);
  9442. + if (!ctx->outurb) {
  9443. + kfree(ctx->buf);
  9444. + kfree(ctx);
  9445. + return NULL;
  9446. + }
  9447. +
  9448. + ctx->upriv = upriv;
  9449. + ctx->state = EZUSB_CTX_START;
  9450. + ctx->out_rid = out_rid;
  9451. + ctx->in_rid = in_rid;
  9452. +
  9453. + refcount_set(&ctx->refcount, 1);
  9454. + init_completion(&ctx->done);
  9455. +
  9456. + timer_setup(&ctx->timer, ezusb_request_timerfn, 0);
  9457. + return ctx;
  9458. +}
  9459. +
  9460. +static void ezusb_ctx_complete(struct request_context *ctx)
  9461. +{
  9462. + struct ezusb_priv *upriv = ctx->upriv;
  9463. + unsigned long flags;
  9464. +
  9465. + spin_lock_irqsave(&upriv->req_lock, flags);
  9466. +
  9467. + list_del_init(&ctx->list);
  9468. + if (upriv->udev) {
  9469. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9470. + ezusb_req_queue_run(upriv);
  9471. + spin_lock_irqsave(&upriv->req_lock, flags);
  9472. + }
  9473. +
  9474. + switch (ctx->state) {
  9475. + case EZUSB_CTX_COMPLETE:
  9476. + case EZUSB_CTX_REQSUBMIT_FAIL:
  9477. + case EZUSB_CTX_REQ_FAILED:
  9478. + case EZUSB_CTX_REQ_TIMEOUT:
  9479. + case EZUSB_CTX_RESP_TIMEOUT:
  9480. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9481. +
  9482. + if ((ctx->out_rid == EZUSB_RID_TX) && upriv->dev) {
  9483. + struct net_device *dev = upriv->dev;
  9484. + struct net_device_stats *stats = &dev->stats;
  9485. +
  9486. + if (ctx->state != EZUSB_CTX_COMPLETE)
  9487. + stats->tx_errors++;
  9488. + else
  9489. + stats->tx_packets++;
  9490. +
  9491. + netif_wake_queue(dev);
  9492. + }
  9493. + complete_all(&ctx->done);
  9494. + ezusb_request_context_put(ctx);
  9495. + break;
  9496. +
  9497. + default:
  9498. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9499. + if (!upriv->udev) {
  9500. + /* This is normal, as all request contexts get flushed
  9501. + * when the device is disconnected */
  9502. + err("Called, CTX not terminating, but device gone");
  9503. + complete_all(&ctx->done);
  9504. + ezusb_request_context_put(ctx);
  9505. + break;
  9506. + }
  9507. +
  9508. + err("Called, CTX not in terminating state.");
  9509. + /* Things are really bad if this happens. Just leak
  9510. + * the CTX because it may still be linked to the
  9511. + * queue or the OUT urb may still be active.
  9512. + * Just leaking at least prevents an Oops or Panic.
  9513. + */
  9514. + break;
  9515. + }
  9516. +}
  9517. +
  9518. +/*
  9519. + * ezusb_req_queue_run:
  9520. + * Description:
  9521. + * Note: Only one active CTX at any one time, because there's no
  9522. + * other (reliable) way to match the response URB to the correct
  9523. + * CTX.
  9524. + */
  9525. +static void ezusb_req_queue_run(struct ezusb_priv *upriv)
  9526. +{
  9527. + unsigned long flags;
  9528. + struct request_context *ctx;
  9529. + int result;
  9530. +
  9531. + spin_lock_irqsave(&upriv->req_lock, flags);
  9532. +
  9533. + if (!list_empty(&upriv->req_active))
  9534. + goto unlock;
  9535. +
  9536. + if (list_empty(&upriv->req_pending))
  9537. + goto unlock;
  9538. +
  9539. + ctx =
  9540. + list_entry(upriv->req_pending.next, struct request_context,
  9541. + list);
  9542. +
  9543. + if (!ctx->upriv->udev)
  9544. + goto unlock;
  9545. +
  9546. + /* We need to split this off to avoid a race condition */
  9547. + list_move_tail(&ctx->list, &upriv->req_active);
  9548. +
  9549. + if (ctx->state == EZUSB_CTX_QUEUED) {
  9550. + refcount_inc(&ctx->refcount);
  9551. + result = usb_submit_urb(ctx->outurb, GFP_ATOMIC);
  9552. + if (result) {
  9553. + ctx->state = EZUSB_CTX_REQSUBMIT_FAIL;
  9554. +
  9555. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9556. +
  9557. + err("Fatal, failed to submit command urb."
  9558. + " error=%d\n", result);
  9559. +
  9560. + ezusb_ctx_complete(ctx);
  9561. + ezusb_request_context_put(ctx);
  9562. + goto done;
  9563. + }
  9564. +
  9565. + ctx->state = EZUSB_CTX_REQ_SUBMITTED;
  9566. + ezusb_mod_timer(ctx->upriv, &ctx->timer,
  9567. + jiffies + DEF_TIMEOUT);
  9568. + }
  9569. +
  9570. + unlock:
  9571. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9572. +
  9573. + done:
  9574. + return;
  9575. +}
  9576. +
  9577. +static void ezusb_req_enqueue_run(struct ezusb_priv *upriv,
  9578. + struct request_context *ctx)
  9579. +{
  9580. + unsigned long flags;
  9581. +
  9582. + spin_lock_irqsave(&upriv->req_lock, flags);
  9583. +
  9584. + if (!ctx->upriv->udev) {
  9585. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9586. + goto done;
  9587. + }
  9588. + refcount_inc(&ctx->refcount);
  9589. + list_add_tail(&ctx->list, &upriv->req_pending);
  9590. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9591. +
  9592. + ctx->state = EZUSB_CTX_QUEUED;
  9593. + ezusb_req_queue_run(upriv);
  9594. +
  9595. + done:
  9596. + return;
  9597. +}
  9598. +
  9599. +static void ezusb_request_out_callback(struct urb *urb)
  9600. +{
  9601. + unsigned long flags;
  9602. + enum ezusb_state state;
  9603. + struct request_context *ctx = urb->context;
  9604. + struct ezusb_priv *upriv = ctx->upriv;
  9605. +
  9606. + spin_lock_irqsave(&upriv->req_lock, flags);
  9607. +
  9608. + del_timer(&ctx->timer);
  9609. +
  9610. + if (ctx->killed) {
  9611. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9612. + pr_warn("interrupt called with dead ctx\n");
  9613. + goto out;
  9614. + }
  9615. +
  9616. + state = ctx->state;
  9617. +
  9618. + if (urb->status == 0) {
  9619. + switch (state) {
  9620. + case EZUSB_CTX_REQ_SUBMITTED:
  9621. + if (ctx->in_rid) {
  9622. + ctx->state = EZUSB_CTX_REQ_COMPLETE;
  9623. + /* reply URB still pending */
  9624. + ezusb_mod_timer(upriv, &ctx->timer,
  9625. + jiffies + DEF_TIMEOUT);
  9626. + spin_unlock_irqrestore(&upriv->req_lock,
  9627. + flags);
  9628. + break;
  9629. + }
  9630. + fallthrough;
  9631. + case EZUSB_CTX_RESP_RECEIVED:
  9632. + /* IN already received before this OUT-ACK */
  9633. + ctx->state = EZUSB_CTX_COMPLETE;
  9634. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9635. + ezusb_ctx_complete(ctx);
  9636. + break;
  9637. +
  9638. + default:
  9639. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9640. + err("Unexpected state(0x%x, %d) in OUT URB",
  9641. + state, urb->status);
  9642. + break;
  9643. + }
  9644. + } else {
  9645. + /* If someone cancels the OUT URB then its status
  9646. + * should be either -ECONNRESET or -ENOENT.
  9647. + */
  9648. + switch (state) {
  9649. + case EZUSB_CTX_REQ_SUBMITTED:
  9650. + case EZUSB_CTX_RESP_RECEIVED:
  9651. + ctx->state = EZUSB_CTX_REQ_FAILED;
  9652. + fallthrough;
  9653. +
  9654. + case EZUSB_CTX_REQ_FAILED:
  9655. + case EZUSB_CTX_REQ_TIMEOUT:
  9656. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9657. +
  9658. + ezusb_ctx_complete(ctx);
  9659. + break;
  9660. +
  9661. + default:
  9662. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9663. +
  9664. + err("Unexpected state(0x%x, %d) in OUT URB",
  9665. + state, urb->status);
  9666. + break;
  9667. + }
  9668. + }
  9669. + out:
  9670. + ezusb_request_context_put(ctx);
  9671. +}
  9672. +
  9673. +static void ezusb_request_in_callback(struct ezusb_priv *upriv,
  9674. + struct urb *urb)
  9675. +{
  9676. + struct ezusb_packet *ans = urb->transfer_buffer;
  9677. + struct request_context *ctx = NULL;
  9678. + enum ezusb_state state;
  9679. + unsigned long flags;
  9680. +
  9681. + /* Find the CTX on the active queue that requested this URB */
  9682. + spin_lock_irqsave(&upriv->req_lock, flags);
  9683. + if (upriv->udev) {
  9684. + struct list_head *item;
  9685. +
  9686. + list_for_each(item, &upriv->req_active) {
  9687. + struct request_context *c;
  9688. + int reply_count;
  9689. +
  9690. + c = list_entry(item, struct request_context, list);
  9691. + reply_count =
  9692. + ezusb_reply_inc(c->buf->req_reply_count);
  9693. + if ((ans->ans_reply_count == reply_count)
  9694. + && (le16_to_cpu(ans->hermes_rid) == c->in_rid)) {
  9695. + ctx = c;
  9696. + break;
  9697. + }
  9698. + netdev_dbg(upriv->dev, "Skipped (0x%x/0x%x) (%d/%d)\n",
  9699. + le16_to_cpu(ans->hermes_rid), c->in_rid,
  9700. + ans->ans_reply_count, reply_count);
  9701. + }
  9702. + }
  9703. +
  9704. + if (ctx == NULL) {
  9705. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9706. + err("%s: got unexpected RID: 0x%04X", __func__,
  9707. + le16_to_cpu(ans->hermes_rid));
  9708. + ezusb_req_queue_run(upriv);
  9709. + return;
  9710. + }
  9711. +
  9712. + /* The data we want is in the in buffer, exchange */
  9713. + urb->transfer_buffer = ctx->buf;
  9714. + ctx->buf = (void *) ans;
  9715. + ctx->buf_length = urb->actual_length;
  9716. +
  9717. + state = ctx->state;
  9718. + switch (state) {
  9719. + case EZUSB_CTX_REQ_SUBMITTED:
  9720. + /* We have received our response URB before
  9721. + * our request has been acknowledged. Do NOT
  9722. + * destroy our CTX yet, because our OUT URB
  9723. + * is still alive ...
  9724. + */
  9725. + ctx->state = EZUSB_CTX_RESP_RECEIVED;
  9726. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9727. +
  9728. + /* Let the machine continue running. */
  9729. + break;
  9730. +
  9731. + case EZUSB_CTX_REQ_COMPLETE:
  9732. + /* This is the usual path: our request
  9733. + * has already been acknowledged, and
  9734. + * we have now received the reply.
  9735. + */
  9736. + ctx->state = EZUSB_CTX_COMPLETE;
  9737. +
  9738. + /* Stop the intimer */
  9739. + del_timer(&ctx->timer);
  9740. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9741. +
  9742. + /* Call the completion handler */
  9743. + ezusb_ctx_complete(ctx);
  9744. + break;
  9745. +
  9746. + default:
  9747. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  9748. +
  9749. + pr_warn("Matched IN URB, unexpected context state(0x%x)\n",
  9750. + state);
  9751. + /* Throw this CTX away and try submitting another */
  9752. + del_timer(&ctx->timer);
  9753. + ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
  9754. + usb_unlink_urb(ctx->outurb);
  9755. + ezusb_req_queue_run(upriv);
  9756. + break;
  9757. + } /* switch */
  9758. +}
  9759. +
  9760. +typedef void (*ezusb_ctx_wait)(struct ezusb_priv *, struct request_context *);
  9761. +
  9762. +static void ezusb_req_ctx_wait_compl(struct ezusb_priv *upriv,
  9763. + struct request_context *ctx)
  9764. +{
  9765. + switch (ctx->state) {
  9766. + case EZUSB_CTX_QUEUED:
  9767. + case EZUSB_CTX_REQ_SUBMITTED:
  9768. + case EZUSB_CTX_REQ_COMPLETE:
  9769. + case EZUSB_CTX_RESP_RECEIVED:
  9770. + wait_for_completion(&ctx->done);
  9771. + break;
  9772. + default:
  9773. + /* Done or failed - nothing to wait for */
  9774. + break;
  9775. + }
  9776. +}
  9777. +
  9778. +static void ezusb_req_ctx_wait_poll(struct ezusb_priv *upriv,
  9779. + struct request_context *ctx)
  9780. +{
  9781. + int msecs;
  9782. +
  9783. + switch (ctx->state) {
  9784. + case EZUSB_CTX_QUEUED:
  9785. + case EZUSB_CTX_REQ_SUBMITTED:
  9786. + case EZUSB_CTX_REQ_COMPLETE:
  9787. + case EZUSB_CTX_RESP_RECEIVED:
  9788. + /* If we get called from a timer or with our lock acquired, then
  9789. + * we can't wait for the completion and have to poll. This won't
  9790. + * happen if the USB controller completes the URB requests in
  9791. + * BH.
  9792. + */
  9793. + msecs = DEF_TIMEOUT * (1000 / HZ);
  9794. +
  9795. + while (!try_wait_for_completion(&ctx->done) && msecs--)
  9796. + udelay(1000);
  9797. + break;
  9798. + default:
  9799. + /* Done or failed - nothing to wait for */
  9800. + break;
  9801. + }
  9802. +}
  9803. +
  9804. +static void ezusb_req_ctx_wait_skip(struct ezusb_priv *upriv,
  9805. + struct request_context *ctx)
  9806. +{
  9807. + WARN(1, "Shouldn't be invoked for in_rid\n");
  9808. +}
  9809. +
  9810. +static inline u16 build_crc(struct ezusb_packet *data)
  9811. +{
  9812. + u16 crc = 0;
  9813. + u8 *bytes = (u8 *)data;
  9814. + int i;
  9815. +
  9816. + for (i = 0; i < 8; i++)
  9817. + crc = (crc << 1) + bytes[i];
  9818. +
  9819. + return crc;
  9820. +}
  9821. +
  9822. +/*
  9823. + * ezusb_fill_req:
  9824. + *
  9825. + * if data == NULL and length > 0 the data is assumed to be already in
  9826. + * the target buffer and only the header is filled.
  9827. + *
  9828. + */
  9829. +static int ezusb_fill_req(struct ezusb_packet *req, u16 length, u16 rid,
  9830. + const void *data, u16 frame_type, u8 reply_count)
  9831. +{
  9832. + int total_size = sizeof(*req) + length;
  9833. +
  9834. + BUG_ON(total_size > BULK_BUF_SIZE);
  9835. +
  9836. + req->magic = cpu_to_le16(EZUSB_MAGIC);
  9837. + req->req_reply_count = reply_count;
  9838. + req->ans_reply_count = 0;
  9839. + req->frame_type = cpu_to_le16(frame_type);
  9840. + req->size = cpu_to_le16(length + 4);
  9841. + req->crc = cpu_to_le16(build_crc(req));
  9842. + req->hermes_len = cpu_to_le16(HERMES_BYTES_TO_RECLEN(length));
  9843. + req->hermes_rid = cpu_to_le16(rid);
  9844. + if (data)
  9845. + memcpy(req->data, data, length);
  9846. + return total_size;
  9847. +}
  9848. +
  9849. +static int ezusb_submit_in_urb(struct ezusb_priv *upriv)
  9850. +{
  9851. + int retval = 0;
  9852. + void *cur_buf = upriv->read_urb->transfer_buffer;
  9853. +
  9854. + if (upriv->read_urb->status == -EINPROGRESS) {
  9855. + netdev_dbg(upriv->dev, "urb busy, not resubmiting\n");
  9856. + retval = -EBUSY;
  9857. + goto exit;
  9858. + }
  9859. + usb_fill_bulk_urb(upriv->read_urb, upriv->udev, upriv->read_pipe,
  9860. + cur_buf, BULK_BUF_SIZE,
  9861. + ezusb_bulk_in_callback, upriv);
  9862. + upriv->read_urb->transfer_flags = 0;
  9863. + retval = usb_submit_urb(upriv->read_urb, GFP_ATOMIC);
  9864. + if (retval)
  9865. + err("%s submit failed %d", __func__, retval);
  9866. +
  9867. + exit:
  9868. + return retval;
  9869. +}
  9870. +
  9871. +static inline int ezusb_8051_cpucs(struct ezusb_priv *upriv, int reset)
  9872. +{
  9873. + int ret;
  9874. + u8 *res_val = NULL;
  9875. +
  9876. + if (!upriv->udev) {
  9877. + err("%s: !upriv->udev", __func__);
  9878. + return -EFAULT;
  9879. + }
  9880. +
  9881. + res_val = kmalloc(sizeof(*res_val), GFP_KERNEL);
  9882. +
  9883. + if (!res_val)
  9884. + return -ENOMEM;
  9885. +
  9886. + *res_val = reset; /* avoid argument promotion */
  9887. +
  9888. + ret = usb_control_msg(upriv->udev,
  9889. + usb_sndctrlpipe(upriv->udev, 0),
  9890. + EZUSB_REQUEST_FW_TRANS,
  9891. + USB_TYPE_VENDOR | USB_RECIP_DEVICE |
  9892. + USB_DIR_OUT, EZUSB_CPUCS_REG, 0, res_val,
  9893. + sizeof(*res_val), DEF_TIMEOUT);
  9894. +
  9895. + kfree(res_val);
  9896. +
  9897. + return ret;
  9898. +}
  9899. +
  9900. +static int ezusb_firmware_download(struct ezusb_priv *upriv,
  9901. + struct ez_usb_fw *fw)
  9902. +{
  9903. + u8 *fw_buffer;
  9904. + int retval, addr;
  9905. + int variant_offset;
  9906. +
  9907. + fw_buffer = kmalloc(FW_BUF_SIZE, GFP_KERNEL);
  9908. + if (!fw_buffer) {
  9909. + printk(KERN_ERR PFX "Out of memory for firmware buffer.\n");
  9910. + return -ENOMEM;
  9911. + }
  9912. + /*
  9913. + * This byte is 1 and should be replaced with 0. The offset is
  9914. + * 0x10AD in version 0.0.6. The byte in question should follow
  9915. + * the end of the code pointed to by the jump in the beginning
  9916. + * of the firmware. Also, it is read by code located at 0x358.
  9917. + */
  9918. + variant_offset = be16_to_cpup((__be16 *) &fw->code[FW_VAR_OFFSET_PTR]);
  9919. + if (variant_offset >= fw->size) {
  9920. + printk(KERN_ERR PFX "Invalid firmware variant offset: "
  9921. + "0x%04x\n", variant_offset);
  9922. + retval = -EINVAL;
  9923. + goto fail;
  9924. + }
  9925. +
  9926. + retval = ezusb_8051_cpucs(upriv, 1);
  9927. + if (retval < 0)
  9928. + goto fail;
  9929. + for (addr = 0; addr < fw->size; addr += FW_BUF_SIZE) {
  9930. + /* 0x100-0x300 should be left alone, it contains card
  9931. + * specific data, like USB enumeration information */
  9932. + if ((addr >= FW_HOLE_START) && (addr < FW_HOLE_END))
  9933. + continue;
  9934. +
  9935. + memcpy(fw_buffer, &fw->code[addr], FW_BUF_SIZE);
  9936. + if (variant_offset >= addr &&
  9937. + variant_offset < addr + FW_BUF_SIZE) {
  9938. + netdev_dbg(upriv->dev,
  9939. + "Patching card_variant byte at 0x%04X\n",
  9940. + variant_offset);
  9941. + fw_buffer[variant_offset - addr] = FW_VAR_VALUE;
  9942. + }
  9943. + retval = usb_control_msg(upriv->udev,
  9944. + usb_sndctrlpipe(upriv->udev, 0),
  9945. + EZUSB_REQUEST_FW_TRANS,
  9946. + USB_TYPE_VENDOR | USB_RECIP_DEVICE
  9947. + | USB_DIR_OUT,
  9948. + addr, 0x0,
  9949. + fw_buffer, FW_BUF_SIZE,
  9950. + DEF_TIMEOUT);
  9951. +
  9952. + if (retval < 0)
  9953. + goto fail;
  9954. + }
  9955. + retval = ezusb_8051_cpucs(upriv, 0);
  9956. + if (retval < 0)
  9957. + goto fail;
  9958. +
  9959. + goto exit;
  9960. + fail:
  9961. + printk(KERN_ERR PFX "Firmware download failed, error %d\n",
  9962. + retval);
  9963. + exit:
  9964. + kfree(fw_buffer);
  9965. + return retval;
  9966. +}
  9967. +
  9968. +static int ezusb_access_ltv(struct ezusb_priv *upriv,
  9969. + struct request_context *ctx,
  9970. + u16 length, const void *data, u16 frame_type,
  9971. + void *ans_buff, unsigned ans_size, u16 *ans_length,
  9972. + ezusb_ctx_wait ezusb_ctx_wait_func)
  9973. +{
  9974. + int req_size;
  9975. + int retval = 0;
  9976. + enum ezusb_state state;
  9977. +
  9978. + if (!upriv->udev) {
  9979. + retval = -ENODEV;
  9980. + goto exit;
  9981. + }
  9982. +
  9983. + if (upriv->read_urb->status != -EINPROGRESS)
  9984. + err("%s: in urb not pending", __func__);
  9985. +
  9986. + /* protect upriv->reply_count, guarantee sequential numbers */
  9987. + spin_lock_bh(&upriv->reply_count_lock);
  9988. + req_size = ezusb_fill_req(ctx->buf, length, ctx->out_rid, data,
  9989. + frame_type, upriv->reply_count);
  9990. + usb_fill_bulk_urb(ctx->outurb, upriv->udev, upriv->write_pipe,
  9991. + ctx->buf, req_size,
  9992. + ezusb_request_out_callback, ctx);
  9993. +
  9994. + if (ctx->in_rid)
  9995. + upriv->reply_count = ezusb_reply_inc(upriv->reply_count);
  9996. +
  9997. + ezusb_req_enqueue_run(upriv, ctx);
  9998. +
  9999. + spin_unlock_bh(&upriv->reply_count_lock);
  10000. +
  10001. + if (ctx->in_rid)
  10002. + ezusb_ctx_wait_func(upriv, ctx);
  10003. +
  10004. + state = ctx->state;
  10005. + switch (state) {
  10006. + case EZUSB_CTX_COMPLETE:
  10007. + retval = ctx->outurb->status;
  10008. + break;
  10009. +
  10010. + case EZUSB_CTX_QUEUED:
  10011. + case EZUSB_CTX_REQ_SUBMITTED:
  10012. + if (!ctx->in_rid)
  10013. + break;
  10014. + fallthrough;
  10015. + default:
  10016. + err("%s: Unexpected context state %d", __func__,
  10017. + state);
  10018. + fallthrough;
  10019. + case EZUSB_CTX_REQ_TIMEOUT:
  10020. + case EZUSB_CTX_REQ_FAILED:
  10021. + case EZUSB_CTX_RESP_TIMEOUT:
  10022. + case EZUSB_CTX_REQSUBMIT_FAIL:
  10023. + printk(KERN_ERR PFX "Access failed, resetting (state %d,"
  10024. + " reply_count %d)\n", state, upriv->reply_count);
  10025. + upriv->reply_count = 0;
  10026. + if (state == EZUSB_CTX_REQ_TIMEOUT
  10027. + || state == EZUSB_CTX_RESP_TIMEOUT) {
  10028. + printk(KERN_ERR PFX "ctx timed out\n");
  10029. + retval = -ETIMEDOUT;
  10030. + } else {
  10031. + printk(KERN_ERR PFX "ctx failed\n");
  10032. + retval = -EFAULT;
  10033. + }
  10034. + goto exit;
  10035. + }
  10036. + if (ctx->in_rid) {
  10037. + struct ezusb_packet *ans = ctx->buf;
  10038. + unsigned exp_len;
  10039. +
  10040. + if (ans->hermes_len != 0)
  10041. + exp_len = le16_to_cpu(ans->hermes_len) * 2 + 12;
  10042. + else
  10043. + exp_len = 14;
  10044. +
  10045. + if (exp_len != ctx->buf_length) {
  10046. + err("%s: length mismatch for RID 0x%04x: "
  10047. + "expected %d, got %d", __func__,
  10048. + ctx->in_rid, exp_len, ctx->buf_length);
  10049. + retval = -EIO;
  10050. + goto exit;
  10051. + }
  10052. +
  10053. + if (ans_buff)
  10054. + memcpy(ans_buff, ans->data, min(exp_len, ans_size));
  10055. + if (ans_length)
  10056. + *ans_length = le16_to_cpu(ans->hermes_len);
  10057. + }
  10058. + exit:
  10059. + ezusb_request_context_put(ctx);
  10060. + return retval;
  10061. +}
  10062. +
  10063. +static int __ezusb_write_ltv(struct hermes *hw, int bap, u16 rid,
  10064. + u16 length, const void *data,
  10065. + ezusb_ctx_wait ezusb_ctx_wait_func)
  10066. +{
  10067. + struct ezusb_priv *upriv = hw->priv;
  10068. + u16 frame_type;
  10069. + struct request_context *ctx;
  10070. +
  10071. + if (length == 0)
  10072. + return -EINVAL;
  10073. +
  10074. + length = HERMES_RECLEN_TO_BYTES(length);
  10075. +
  10076. + /* On memory mapped devices HERMES_RID_CNFGROUPADDRESSES can be
  10077. + * set to be empty, but the USB bridge doesn't like it */
  10078. + if (length == 0)
  10079. + return 0;
  10080. +
  10081. + ctx = ezusb_alloc_ctx(upriv, rid, EZUSB_RID_ACK);
  10082. + if (!ctx)
  10083. + return -ENOMEM;
  10084. +
  10085. + if (rid == EZUSB_RID_TX)
  10086. + frame_type = EZUSB_FRAME_DATA;
  10087. + else
  10088. + frame_type = EZUSB_FRAME_CONTROL;
  10089. +
  10090. + return ezusb_access_ltv(upriv, ctx, length, data, frame_type,
  10091. + NULL, 0, NULL, ezusb_ctx_wait_func);
  10092. +}
  10093. +
  10094. +static int ezusb_write_ltv(struct hermes *hw, int bap, u16 rid,
  10095. + u16 length, const void *data)
  10096. +{
  10097. + return __ezusb_write_ltv(hw, bap, rid, length, data,
  10098. + ezusb_req_ctx_wait_poll);
  10099. +}
  10100. +
  10101. +static int __ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
  10102. + unsigned bufsize, u16 *length, void *buf,
  10103. + ezusb_ctx_wait ezusb_ctx_wait_func)
  10104. +
  10105. +{
  10106. + struct ezusb_priv *upriv = hw->priv;
  10107. + struct request_context *ctx;
  10108. +
  10109. + if (bufsize % 2)
  10110. + return -EINVAL;
  10111. +
  10112. + ctx = ezusb_alloc_ctx(upriv, rid, rid);
  10113. + if (!ctx)
  10114. + return -ENOMEM;
  10115. +
  10116. + return ezusb_access_ltv(upriv, ctx, 0, NULL, EZUSB_FRAME_CONTROL,
  10117. + buf, bufsize, length, ezusb_req_ctx_wait_poll);
  10118. +}
  10119. +
  10120. +static int ezusb_read_ltv(struct hermes *hw, int bap, u16 rid,
  10121. + unsigned bufsize, u16 *length, void *buf)
  10122. +{
  10123. + return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf,
  10124. + ezusb_req_ctx_wait_poll);
  10125. +}
  10126. +
  10127. +static int ezusb_read_ltv_preempt(struct hermes *hw, int bap, u16 rid,
  10128. + unsigned bufsize, u16 *length, void *buf)
  10129. +{
  10130. + return __ezusb_read_ltv(hw, bap, rid, bufsize, length, buf,
  10131. + ezusb_req_ctx_wait_compl);
  10132. +}
  10133. +
  10134. +static int ezusb_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1,
  10135. + u16 parm2, struct hermes_response *resp)
  10136. +{
  10137. + WARN_ON_ONCE(1);
  10138. + return -EINVAL;
  10139. +}
  10140. +
  10141. +static int __ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
  10142. + struct hermes_response *resp,
  10143. + ezusb_ctx_wait ezusb_ctx_wait_func)
  10144. +{
  10145. + struct ezusb_priv *upriv = hw->priv;
  10146. + struct request_context *ctx;
  10147. +
  10148. + __le16 data[4] = {
  10149. + cpu_to_le16(cmd),
  10150. + cpu_to_le16(parm0),
  10151. + 0,
  10152. + 0,
  10153. + };
  10154. + netdev_dbg(upriv->dev, "0x%04X, parm0 0x%04X\n", cmd, parm0);
  10155. + ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_DOCMD, EZUSB_RID_ACK);
  10156. + if (!ctx)
  10157. + return -ENOMEM;
  10158. +
  10159. + return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
  10160. + EZUSB_FRAME_CONTROL, NULL, 0, NULL,
  10161. + ezusb_ctx_wait_func);
  10162. +}
  10163. +
  10164. +static int ezusb_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0,
  10165. + struct hermes_response *resp)
  10166. +{
  10167. + return __ezusb_docmd_wait(hw, cmd, parm0, resp, ezusb_req_ctx_wait_poll);
  10168. +}
  10169. +
  10170. +static int ezusb_bap_pread(struct hermes *hw, int bap,
  10171. + void *buf, int len, u16 id, u16 offset)
  10172. +{
  10173. + struct ezusb_priv *upriv = hw->priv;
  10174. + struct ezusb_packet *ans = (void *) upriv->read_urb->transfer_buffer;
  10175. + int actual_length = upriv->read_urb->actual_length;
  10176. +
  10177. + if (id == EZUSB_RID_RX) {
  10178. + if ((sizeof(*ans) + offset + len) > actual_length) {
  10179. + printk(KERN_ERR PFX "BAP read beyond buffer end "
  10180. + "in rx frame\n");
  10181. + return -EINVAL;
  10182. + }
  10183. + memcpy(buf, ans->data + offset, len);
  10184. + return 0;
  10185. + }
  10186. +
  10187. + if (EZUSB_IS_INFO(id)) {
  10188. + /* Include 4 bytes for length/type */
  10189. + if ((sizeof(*ans) + offset + len - 4) > actual_length) {
  10190. + printk(KERN_ERR PFX "BAP read beyond buffer end "
  10191. + "in info frame\n");
  10192. + return -EFAULT;
  10193. + }
  10194. + memcpy(buf, ans->data + offset - 4, len);
  10195. + } else {
  10196. + printk(KERN_ERR PFX "Unexpected fid 0x%04x\n", id);
  10197. + return -EINVAL;
  10198. + }
  10199. +
  10200. + return 0;
  10201. +}
  10202. +
  10203. +static int ezusb_read_pda(struct hermes *hw, __le16 *pda,
  10204. + u32 pda_addr, u16 pda_len)
  10205. +{
  10206. + struct ezusb_priv *upriv = hw->priv;
  10207. + struct request_context *ctx;
  10208. + __le16 data[] = {
  10209. + cpu_to_le16(pda_addr & 0xffff),
  10210. + cpu_to_le16(pda_len - 4)
  10211. + };
  10212. + ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_READ_PDA, EZUSB_RID_READ_PDA);
  10213. + if (!ctx)
  10214. + return -ENOMEM;
  10215. +
  10216. + /* wl_lkm does not include PDA size in the PDA area.
  10217. + * We will pad the information into pda, so other routines
  10218. + * don't have to be modified */
  10219. + pda[0] = cpu_to_le16(pda_len - 2);
  10220. + /* Includes CFG_PROD_DATA but not itself */
  10221. + pda[1] = cpu_to_le16(0x0800); /* CFG_PROD_DATA */
  10222. +
  10223. + return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
  10224. + EZUSB_FRAME_CONTROL, &pda[2], pda_len - 4,
  10225. + NULL, ezusb_req_ctx_wait_compl);
  10226. +}
  10227. +
  10228. +static int ezusb_program_init(struct hermes *hw, u32 entry_point)
  10229. +{
  10230. + struct ezusb_priv *upriv = hw->priv;
  10231. + struct request_context *ctx;
  10232. + __le32 data = cpu_to_le32(entry_point);
  10233. +
  10234. + ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_INIT, EZUSB_RID_ACK);
  10235. + if (!ctx)
  10236. + return -ENOMEM;
  10237. +
  10238. + return ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
  10239. + EZUSB_FRAME_CONTROL, NULL, 0, NULL,
  10240. + ezusb_req_ctx_wait_compl);
  10241. +}
  10242. +
  10243. +static int ezusb_program_end(struct hermes *hw)
  10244. +{
  10245. + struct ezusb_priv *upriv = hw->priv;
  10246. + struct request_context *ctx;
  10247. +
  10248. + ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_END, EZUSB_RID_ACK);
  10249. + if (!ctx)
  10250. + return -ENOMEM;
  10251. +
  10252. + return ezusb_access_ltv(upriv, ctx, 0, NULL,
  10253. + EZUSB_FRAME_CONTROL, NULL, 0, NULL,
  10254. + ezusb_req_ctx_wait_compl);
  10255. +}
  10256. +
  10257. +static int ezusb_program_bytes(struct hermes *hw, const char *buf,
  10258. + u32 addr, u32 len)
  10259. +{
  10260. + struct ezusb_priv *upriv = hw->priv;
  10261. + struct request_context *ctx;
  10262. + __le32 data = cpu_to_le32(addr);
  10263. + int err;
  10264. +
  10265. + ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_SET_ADDR, EZUSB_RID_ACK);
  10266. + if (!ctx)
  10267. + return -ENOMEM;
  10268. +
  10269. + err = ezusb_access_ltv(upriv, ctx, sizeof(data), &data,
  10270. + EZUSB_FRAME_CONTROL, NULL, 0, NULL,
  10271. + ezusb_req_ctx_wait_compl);
  10272. + if (err)
  10273. + return err;
  10274. +
  10275. + ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_PROG_BYTES, EZUSB_RID_ACK);
  10276. + if (!ctx)
  10277. + return -ENOMEM;
  10278. +
  10279. + return ezusb_access_ltv(upriv, ctx, len, buf,
  10280. + EZUSB_FRAME_CONTROL, NULL, 0, NULL,
  10281. + ezusb_req_ctx_wait_compl);
  10282. +}
  10283. +
  10284. +static int ezusb_program(struct hermes *hw, const char *buf,
  10285. + u32 addr, u32 len)
  10286. +{
  10287. + u32 ch_addr;
  10288. + u32 ch_len;
  10289. + int err = 0;
  10290. +
  10291. + /* We can only send 2048 bytes out of the bulk xmit at a time,
  10292. + * so we have to split any programming into chunks of <2048
  10293. + * bytes. */
  10294. +
  10295. + ch_len = (len < MAX_DL_SIZE) ? len : MAX_DL_SIZE;
  10296. + ch_addr = addr;
  10297. +
  10298. + while (ch_addr < (addr + len)) {
  10299. + pr_debug("Programming subblock of length %d "
  10300. + "to address 0x%08x. Data @ %p\n",
  10301. + ch_len, ch_addr, &buf[ch_addr - addr]);
  10302. +
  10303. + err = ezusb_program_bytes(hw, &buf[ch_addr - addr],
  10304. + ch_addr, ch_len);
  10305. + if (err)
  10306. + break;
  10307. +
  10308. + ch_addr += ch_len;
  10309. + ch_len = ((addr + len - ch_addr) < MAX_DL_SIZE) ?
  10310. + (addr + len - ch_addr) : MAX_DL_SIZE;
  10311. + }
  10312. +
  10313. + return err;
  10314. +}
  10315. +
  10316. +static netdev_tx_t ezusb_xmit(struct sk_buff *skb, struct net_device *dev)
  10317. +{
  10318. + struct orinoco_private *priv = ndev_priv(dev);
  10319. + struct net_device_stats *stats = &dev->stats;
  10320. + struct ezusb_priv *upriv = priv->card;
  10321. + u8 mic[MICHAEL_MIC_LEN + 1];
  10322. + int err = 0;
  10323. + int tx_control;
  10324. + unsigned long flags;
  10325. + struct request_context *ctx;
  10326. + u8 *buf;
  10327. + int tx_size;
  10328. +
  10329. + if (!netif_running(dev)) {
  10330. + printk(KERN_ERR "%s: Tx on stopped device!\n",
  10331. + dev->name);
  10332. + return NETDEV_TX_BUSY;
  10333. + }
  10334. +
  10335. + if (netif_queue_stopped(dev)) {
  10336. + printk(KERN_DEBUG "%s: Tx while transmitter busy!\n",
  10337. + dev->name);
  10338. + return NETDEV_TX_BUSY;
  10339. + }
  10340. +
  10341. + if (orinoco_lock(priv, &flags) != 0) {
  10342. + printk(KERN_ERR
  10343. + "%s: ezusb_xmit() called while hw_unavailable\n",
  10344. + dev->name);
  10345. + return NETDEV_TX_BUSY;
  10346. + }
  10347. +
  10348. + if (!netif_carrier_ok(dev) ||
  10349. + (priv->iw_mode == NL80211_IFTYPE_MONITOR)) {
  10350. + /* Oops, the firmware hasn't established a connection,
  10351. + silently drop the packet (this seems to be the
  10352. + safest approach). */
  10353. + goto drop;
  10354. + }
  10355. +
  10356. + /* Check packet length */
  10357. + if (skb->len < ETH_HLEN)
  10358. + goto drop;
  10359. +
  10360. + tx_control = 0;
  10361. +
  10362. + err = orinoco_process_xmit_skb(skb, dev, priv, &tx_control,
  10363. + &mic[0]);
  10364. + if (err)
  10365. + goto drop;
  10366. +
  10367. + ctx = ezusb_alloc_ctx(upriv, EZUSB_RID_TX, 0);
  10368. + if (!ctx)
  10369. + goto drop;
  10370. +
  10371. + memset(ctx->buf, 0, BULK_BUF_SIZE);
  10372. + buf = ctx->buf->data;
  10373. +
  10374. + {
  10375. + __le16 *tx_cntl = (__le16 *)buf;
  10376. + *tx_cntl = cpu_to_le16(tx_control);
  10377. + buf += sizeof(*tx_cntl);
  10378. + }
  10379. +
  10380. + memcpy(buf, skb->data, skb->len);
  10381. + buf += skb->len;
  10382. +
  10383. + if (tx_control & HERMES_TXCTRL_MIC) {
  10384. + u8 *m = mic;
  10385. + /* Mic has been offset so it can be copied to an even
  10386. + * address. We're copying eveything anyway, so we
  10387. + * don't need to copy that first byte. */
  10388. + if (skb->len % 2)
  10389. + m++;
  10390. + memcpy(buf, m, MICHAEL_MIC_LEN);
  10391. + buf += MICHAEL_MIC_LEN;
  10392. + }
  10393. +
  10394. + /* Finally, we actually initiate the send */
  10395. + netif_stop_queue(dev);
  10396. +
  10397. + /* The card may behave better if we send evenly sized usb transfers */
  10398. + tx_size = ALIGN(buf - ctx->buf->data, 2);
  10399. +
  10400. + err = ezusb_access_ltv(upriv, ctx, tx_size, NULL,
  10401. + EZUSB_FRAME_DATA, NULL, 0, NULL,
  10402. + ezusb_req_ctx_wait_skip);
  10403. +
  10404. + if (err) {
  10405. + netif_start_queue(dev);
  10406. + if (net_ratelimit())
  10407. + printk(KERN_ERR "%s: Error %d transmitting packet\n",
  10408. + dev->name, err);
  10409. + goto busy;
  10410. + }
  10411. +
  10412. + netif_trans_update(dev);
  10413. + stats->tx_bytes += skb->len;
  10414. + goto ok;
  10415. +
  10416. + drop:
  10417. + stats->tx_errors++;
  10418. + stats->tx_dropped++;
  10419. +
  10420. + ok:
  10421. + orinoco_unlock(priv, &flags);
  10422. + dev_kfree_skb(skb);
  10423. + return NETDEV_TX_OK;
  10424. +
  10425. + busy:
  10426. + orinoco_unlock(priv, &flags);
  10427. + return NETDEV_TX_BUSY;
  10428. +}
  10429. +
  10430. +static int ezusb_allocate(struct hermes *hw, u16 size, u16 *fid)
  10431. +{
  10432. + *fid = EZUSB_RID_TX;
  10433. + return 0;
  10434. +}
  10435. +
  10436. +
  10437. +static int ezusb_hard_reset(struct orinoco_private *priv)
  10438. +{
  10439. + struct ezusb_priv *upriv = priv->card;
  10440. + int retval = ezusb_8051_cpucs(upriv, 1);
  10441. +
  10442. + if (retval < 0) {
  10443. + err("Failed to reset");
  10444. + return retval;
  10445. + }
  10446. +
  10447. + retval = ezusb_8051_cpucs(upriv, 0);
  10448. + if (retval < 0) {
  10449. + err("Failed to unreset");
  10450. + return retval;
  10451. + }
  10452. +
  10453. + netdev_dbg(upriv->dev, "sending control message\n");
  10454. + retval = usb_control_msg(upriv->udev,
  10455. + usb_sndctrlpipe(upriv->udev, 0),
  10456. + EZUSB_REQUEST_TRIGGER,
  10457. + USB_TYPE_VENDOR | USB_RECIP_DEVICE |
  10458. + USB_DIR_OUT, 0x0, 0x0, NULL, 0,
  10459. + DEF_TIMEOUT);
  10460. + if (retval < 0) {
  10461. + err("EZUSB_REQUEST_TRIGGER failed retval %d", retval);
  10462. + return retval;
  10463. + }
  10464. +#if 0
  10465. + dbg("Sending EZUSB_REQUEST_TRIG_AC");
  10466. + retval = usb_control_msg(upriv->udev,
  10467. + usb_sndctrlpipe(upriv->udev, 0),
  10468. + EZUSB_REQUEST_TRIG_AC,
  10469. + USB_TYPE_VENDOR | USB_RECIP_DEVICE |
  10470. + USB_DIR_OUT, 0x00FA, 0x0, NULL, 0,
  10471. + DEF_TIMEOUT);
  10472. + if (retval < 0) {
  10473. + err("EZUSB_REQUEST_TRIG_AC failed retval %d", retval);
  10474. + return retval;
  10475. + }
  10476. +#endif
  10477. +
  10478. + return 0;
  10479. +}
  10480. +
  10481. +
  10482. +static int ezusb_init(struct hermes *hw)
  10483. +{
  10484. + struct ezusb_priv *upriv = hw->priv;
  10485. + int retval;
  10486. +
  10487. + if (!upriv)
  10488. + return -EINVAL;
  10489. +
  10490. + upriv->reply_count = 0;
  10491. + /* Write the MAGIC number on the simulated registers to keep
  10492. + * orinoco.c happy */
  10493. + hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
  10494. + hermes_write_regn(hw, RXFID, EZUSB_RID_RX);
  10495. +
  10496. + usb_kill_urb(upriv->read_urb);
  10497. + ezusb_submit_in_urb(upriv);
  10498. +
  10499. + retval = __ezusb_write_ltv(hw, 0, EZUSB_RID_INIT1,
  10500. + HERMES_BYTES_TO_RECLEN(2), "\x10\x00",
  10501. + ezusb_req_ctx_wait_compl);
  10502. + if (retval < 0) {
  10503. + printk(KERN_ERR PFX "EZUSB_RID_INIT1 error %d\n", retval);
  10504. + return retval;
  10505. + }
  10506. +
  10507. + retval = __ezusb_docmd_wait(hw, HERMES_CMD_INIT, 0, NULL,
  10508. + ezusb_req_ctx_wait_compl);
  10509. + if (retval < 0) {
  10510. + printk(KERN_ERR PFX "HERMES_CMD_INIT error %d\n", retval);
  10511. + return retval;
  10512. + }
  10513. +
  10514. + return 0;
  10515. +}
  10516. +
  10517. +static void ezusb_bulk_in_callback(struct urb *urb)
  10518. +{
  10519. + struct ezusb_priv *upriv = (struct ezusb_priv *) urb->context;
  10520. + struct ezusb_packet *ans = urb->transfer_buffer;
  10521. + u16 crc;
  10522. + u16 hermes_rid;
  10523. +
  10524. + if (upriv->udev == NULL)
  10525. + return;
  10526. +
  10527. + if (urb->status == -ETIMEDOUT) {
  10528. + /* When a device gets unplugged we get this every time
  10529. + * we resubmit, flooding the logs. Since we don't use
  10530. + * USB timeouts, it shouldn't happen any other time*/
  10531. + pr_warn("%s: urb timed out, not resubmitting\n", __func__);
  10532. + return;
  10533. + }
  10534. + if (urb->status == -ECONNABORTED) {
  10535. + pr_warn("%s: connection abort, resubmitting urb\n",
  10536. + __func__);
  10537. + goto resubmit;
  10538. + }
  10539. + if ((urb->status == -EILSEQ)
  10540. + || (urb->status == -ENOENT)
  10541. + || (urb->status == -ECONNRESET)) {
  10542. + netdev_dbg(upriv->dev, "status %d, not resubmiting\n",
  10543. + urb->status);
  10544. + return;
  10545. + }
  10546. + if (urb->status)
  10547. + netdev_dbg(upriv->dev, "status: %d length: %d\n",
  10548. + urb->status, urb->actual_length);
  10549. + if (urb->actual_length < sizeof(*ans)) {
  10550. + err("%s: short read, ignoring", __func__);
  10551. + goto resubmit;
  10552. + }
  10553. + crc = build_crc(ans);
  10554. + if (le16_to_cpu(ans->crc) != crc) {
  10555. + err("CRC error, ignoring packet");
  10556. + goto resubmit;
  10557. + }
  10558. +
  10559. + hermes_rid = le16_to_cpu(ans->hermes_rid);
  10560. + if ((hermes_rid != EZUSB_RID_RX) && !EZUSB_IS_INFO(hermes_rid)) {
  10561. + ezusb_request_in_callback(upriv, urb);
  10562. + } else if (upriv->dev) {
  10563. + struct net_device *dev = upriv->dev;
  10564. + struct orinoco_private *priv = ndev_priv(dev);
  10565. + struct hermes *hw = &priv->hw;
  10566. +
  10567. + if (hermes_rid == EZUSB_RID_RX) {
  10568. + __orinoco_ev_rx(dev, hw);
  10569. + } else {
  10570. + hermes_write_regn(hw, INFOFID,
  10571. + le16_to_cpu(ans->hermes_rid));
  10572. + __orinoco_ev_info(dev, hw);
  10573. + }
  10574. + }
  10575. +
  10576. + resubmit:
  10577. + if (upriv->udev)
  10578. + ezusb_submit_in_urb(upriv);
  10579. +}
  10580. +
  10581. +static inline void ezusb_delete(struct ezusb_priv *upriv)
  10582. +{
  10583. + struct list_head *item;
  10584. + struct list_head *tmp_item;
  10585. + unsigned long flags;
  10586. +
  10587. + BUG_ON(!upriv);
  10588. +
  10589. + mutex_lock(&upriv->mtx);
  10590. +
  10591. + upriv->udev = NULL; /* No timer will be rearmed from here */
  10592. +
  10593. + usb_kill_urb(upriv->read_urb);
  10594. +
  10595. + spin_lock_irqsave(&upriv->req_lock, flags);
  10596. + list_for_each_safe(item, tmp_item, &upriv->req_active) {
  10597. + struct request_context *ctx;
  10598. + int err;
  10599. +
  10600. + ctx = list_entry(item, struct request_context, list);
  10601. + refcount_inc(&ctx->refcount);
  10602. +
  10603. + ctx->outurb->transfer_flags |= URB_ASYNC_UNLINK;
  10604. + err = usb_unlink_urb(ctx->outurb);
  10605. +
  10606. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  10607. + if (err == -EINPROGRESS)
  10608. + wait_for_completion(&ctx->done);
  10609. +
  10610. + del_timer_sync(&ctx->timer);
  10611. + /* FIXME: there is an slight chance for the irq handler to
  10612. + * be running */
  10613. + if (!list_empty(&ctx->list))
  10614. + ezusb_ctx_complete(ctx);
  10615. +
  10616. + ezusb_request_context_put(ctx);
  10617. + spin_lock_irqsave(&upriv->req_lock, flags);
  10618. + }
  10619. + spin_unlock_irqrestore(&upriv->req_lock, flags);
  10620. +
  10621. + list_for_each_safe(item, tmp_item, &upriv->req_pending)
  10622. + ezusb_ctx_complete(list_entry(item,
  10623. + struct request_context, list));
  10624. +
  10625. + if (upriv->read_urb && upriv->read_urb->status == -EINPROGRESS)
  10626. + printk(KERN_ERR PFX "Some URB in progress\n");
  10627. +
  10628. + mutex_unlock(&upriv->mtx);
  10629. +
  10630. + if (upriv->read_urb) {
  10631. + kfree(upriv->read_urb->transfer_buffer);
  10632. + usb_free_urb(upriv->read_urb);
  10633. + }
  10634. + kfree(upriv->bap_buf);
  10635. + if (upriv->dev) {
  10636. + struct orinoco_private *priv = ndev_priv(upriv->dev);
  10637. + orinoco_if_del(priv);
  10638. + wiphy_unregister(priv_to_wiphy(upriv));
  10639. + free_orinocodev(priv);
  10640. + }
  10641. +}
  10642. +
  10643. +static void ezusb_lock_irqsave(spinlock_t *lock,
  10644. + unsigned long *flags) __acquires(lock)
  10645. +{
  10646. + spin_lock_bh(lock);
  10647. +}
  10648. +
  10649. +static void ezusb_unlock_irqrestore(spinlock_t *lock,
  10650. + unsigned long *flags) __releases(lock)
  10651. +{
  10652. + spin_unlock_bh(lock);
  10653. +}
  10654. +
  10655. +static void ezusb_lock_irq(spinlock_t *lock) __acquires(lock)
  10656. +{
  10657. + spin_lock_bh(lock);
  10658. +}
  10659. +
  10660. +static void ezusb_unlock_irq(spinlock_t *lock) __releases(lock)
  10661. +{
  10662. + spin_unlock_bh(lock);
  10663. +}
  10664. +
  10665. +static const struct hermes_ops ezusb_ops = {
  10666. + .init = ezusb_init,
  10667. + .cmd_wait = ezusb_docmd_wait,
  10668. + .init_cmd_wait = ezusb_doicmd_wait,
  10669. + .allocate = ezusb_allocate,
  10670. + .read_ltv = ezusb_read_ltv,
  10671. + .read_ltv_pr = ezusb_read_ltv_preempt,
  10672. + .write_ltv = ezusb_write_ltv,
  10673. + .bap_pread = ezusb_bap_pread,
  10674. + .read_pda = ezusb_read_pda,
  10675. + .program_init = ezusb_program_init,
  10676. + .program_end = ezusb_program_end,
  10677. + .program = ezusb_program,
  10678. + .lock_irqsave = ezusb_lock_irqsave,
  10679. + .unlock_irqrestore = ezusb_unlock_irqrestore,
  10680. + .lock_irq = ezusb_lock_irq,
  10681. + .unlock_irq = ezusb_unlock_irq,
  10682. +};
  10683. +
  10684. +static const struct net_device_ops ezusb_netdev_ops = {
  10685. + .ndo_open = orinoco_open,
  10686. + .ndo_stop = orinoco_stop,
  10687. + .ndo_start_xmit = ezusb_xmit,
  10688. + .ndo_set_rx_mode = orinoco_set_multicast_list,
  10689. + .ndo_change_mtu = orinoco_change_mtu,
  10690. + .ndo_set_mac_address = eth_mac_addr,
  10691. + .ndo_validate_addr = eth_validate_addr,
  10692. + .ndo_tx_timeout = orinoco_tx_timeout,
  10693. +};
  10694. +
  10695. +static int ezusb_probe(struct usb_interface *interface,
  10696. + const struct usb_device_id *id)
  10697. +{
  10698. + struct usb_device *udev = interface_to_usbdev(interface);
  10699. + struct orinoco_private *priv;
  10700. + struct hermes *hw;
  10701. + struct ezusb_priv *upriv = NULL;
  10702. + struct usb_interface_descriptor *iface_desc;
  10703. + struct usb_endpoint_descriptor *ep;
  10704. + const struct firmware *fw_entry = NULL;
  10705. + int retval = 0;
  10706. + int i;
  10707. +
  10708. + priv = alloc_orinocodev(sizeof(*upriv), &udev->dev,
  10709. + ezusb_hard_reset, NULL);
  10710. + if (!priv) {
  10711. + err("Couldn't allocate orinocodev");
  10712. + retval = -ENOMEM;
  10713. + goto exit;
  10714. + }
  10715. +
  10716. + hw = &priv->hw;
  10717. +
  10718. + upriv = priv->card;
  10719. +
  10720. + mutex_init(&upriv->mtx);
  10721. + spin_lock_init(&upriv->reply_count_lock);
  10722. +
  10723. + spin_lock_init(&upriv->req_lock);
  10724. + INIT_LIST_HEAD(&upriv->req_pending);
  10725. + INIT_LIST_HEAD(&upriv->req_active);
  10726. +
  10727. + upriv->udev = udev;
  10728. +
  10729. + hw->iobase = (void __force __iomem *) &upriv->hermes_reg_fake;
  10730. + hw->reg_spacing = HERMES_16BIT_REGSPACING;
  10731. + hw->priv = upriv;
  10732. + hw->ops = &ezusb_ops;
  10733. +
  10734. + /* set up the endpoint information */
  10735. + /* check out the endpoints */
  10736. +
  10737. + iface_desc = &interface->cur_altsetting->desc;
  10738. + for (i = 0; i < iface_desc->bNumEndpoints; ++i) {
  10739. + ep = &interface->cur_altsetting->endpoint[i].desc;
  10740. +
  10741. + if (usb_endpoint_is_bulk_in(ep)) {
  10742. + /* we found a bulk in endpoint */
  10743. + if (upriv->read_urb != NULL) {
  10744. + pr_warn("Found a second bulk in ep, ignored\n");
  10745. + continue;
  10746. + }
  10747. +
  10748. + upriv->read_urb = usb_alloc_urb(0, GFP_KERNEL);
  10749. + if (!upriv->read_urb)
  10750. + goto error;
  10751. + if (le16_to_cpu(ep->wMaxPacketSize) != 64)
  10752. + pr_warn("bulk in: wMaxPacketSize!= 64\n");
  10753. + if (ep->bEndpointAddress != (2 | USB_DIR_IN))
  10754. + pr_warn("bulk in: bEndpointAddress: %d\n",
  10755. + ep->bEndpointAddress);
  10756. + upriv->read_pipe = usb_rcvbulkpipe(udev,
  10757. + ep->
  10758. + bEndpointAddress);
  10759. + upriv->read_urb->transfer_buffer =
  10760. + kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
  10761. + if (!upriv->read_urb->transfer_buffer) {
  10762. + err("Couldn't allocate IN buffer");
  10763. + goto error;
  10764. + }
  10765. + }
  10766. +
  10767. + if (usb_endpoint_is_bulk_out(ep)) {
  10768. + /* we found a bulk out endpoint */
  10769. + if (upriv->bap_buf != NULL) {
  10770. + pr_warn("Found a second bulk out ep, ignored\n");
  10771. + continue;
  10772. + }
  10773. +
  10774. + if (le16_to_cpu(ep->wMaxPacketSize) != 64)
  10775. + pr_warn("bulk out: wMaxPacketSize != 64\n");
  10776. + if (ep->bEndpointAddress != 2)
  10777. + pr_warn("bulk out: bEndpointAddress: %d\n",
  10778. + ep->bEndpointAddress);
  10779. + upriv->write_pipe = usb_sndbulkpipe(udev,
  10780. + ep->
  10781. + bEndpointAddress);
  10782. + upriv->bap_buf = kmalloc(BULK_BUF_SIZE, GFP_KERNEL);
  10783. + if (!upriv->bap_buf) {
  10784. + err("Couldn't allocate bulk_out_buffer");
  10785. + goto error;
  10786. + }
  10787. + }
  10788. + }
  10789. + if (!upriv->bap_buf || !upriv->read_urb) {
  10790. + err("Didn't find the required bulk endpoints");
  10791. + goto error;
  10792. + }
  10793. +
  10794. + if (request_firmware(&fw_entry, "orinoco_ezusb_fw",
  10795. + &interface->dev) == 0) {
  10796. + firmware.size = fw_entry->size;
  10797. + firmware.code = fw_entry->data;
  10798. + }
  10799. + if (firmware.size && firmware.code) {
  10800. + if (ezusb_firmware_download(upriv, &firmware) < 0)
  10801. + goto error;
  10802. + } else {
  10803. + err("No firmware to download");
  10804. + goto error;
  10805. + }
  10806. +
  10807. + if (ezusb_hard_reset(priv) < 0) {
  10808. + err("Cannot reset the device");
  10809. + goto error;
  10810. + }
  10811. +
  10812. + /* If the firmware is already downloaded orinoco.c will call
  10813. + * ezusb_init but if the firmware is not already there, that will make
  10814. + * the kernel very unstable, so we try initializing here and quit in
  10815. + * case of error */
  10816. + if (ezusb_init(hw) < 0) {
  10817. + err("Couldn't initialize the device");
  10818. + err("Firmware may not be downloaded or may be wrong.");
  10819. + goto error;
  10820. + }
  10821. +
  10822. + /* Initialise the main driver */
  10823. + if (orinoco_init(priv) != 0) {
  10824. + err("orinoco_init() failed\n");
  10825. + goto error;
  10826. + }
  10827. +
  10828. + if (orinoco_if_add(priv, 0, 0, &ezusb_netdev_ops) != 0) {
  10829. + upriv->dev = NULL;
  10830. + err("%s: orinoco_if_add() failed", __func__);
  10831. + wiphy_unregister(priv_to_wiphy(priv));
  10832. + goto error;
  10833. + }
  10834. + upriv->dev = priv->ndev;
  10835. +
  10836. + goto exit;
  10837. +
  10838. + error:
  10839. + ezusb_delete(upriv);
  10840. + if (upriv->dev) {
  10841. + /* upriv->dev was 0, so ezusb_delete() didn't free it */
  10842. + free_orinocodev(priv);
  10843. + }
  10844. + upriv = NULL;
  10845. + retval = -EFAULT;
  10846. + exit:
  10847. + if (fw_entry) {
  10848. + firmware.code = NULL;
  10849. + firmware.size = 0;
  10850. + release_firmware(fw_entry);
  10851. + }
  10852. + usb_set_intfdata(interface, upriv);
  10853. + return retval;
  10854. +}
  10855. +
  10856. +
  10857. +static void ezusb_disconnect(struct usb_interface *intf)
  10858. +{
  10859. + struct ezusb_priv *upriv = usb_get_intfdata(intf);
  10860. + usb_set_intfdata(intf, NULL);
  10861. + ezusb_delete(upriv);
  10862. + printk(KERN_INFO PFX "Disconnected\n");
  10863. +}
  10864. +
  10865. +
  10866. +/* usb specific object needed to register this driver with the usb subsystem */
  10867. +static struct usb_driver orinoco_driver = {
  10868. + .name = DRIVER_NAME,
  10869. + .probe = ezusb_probe,
  10870. + .disconnect = ezusb_disconnect,
  10871. + .id_table = ezusb_table,
  10872. + .disable_hub_initiated_lpm = 1,
  10873. +};
  10874. +
  10875. +module_usb_driver(orinoco_driver);
  10876. +
  10877. +MODULE_AUTHOR("Manuel Estrada Sainz");
  10878. +MODULE_DESCRIPTION("Driver for Orinoco wireless LAN cards using EZUSB bridge");
  10879. +MODULE_LICENSE("Dual MPL/GPL");
  10880. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/scan.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/scan.c
  10881. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/scan.c 1970-01-01 01:00:00.000000000 +0100
  10882. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/scan.c 2026-02-16 14:00:36.623256352 +0100
  10883. @@ -0,0 +1,259 @@
  10884. +/* Helpers for managing scan queues
  10885. + *
  10886. + * See copyright notice in main.c
  10887. + */
  10888. +
  10889. +#include <linux/gfp.h>
  10890. +#include <linux/kernel.h>
  10891. +#include <linux/string.h>
  10892. +#include <linux/ieee80211.h>
  10893. +#include <net/cfg80211.h>
  10894. +
  10895. +#include "hermes.h"
  10896. +#include "orinoco.h"
  10897. +#include "main.h"
  10898. +
  10899. +#include "scan.h"
  10900. +
  10901. +#define ZERO_DBM_OFFSET 0x95
  10902. +#define MAX_SIGNAL_LEVEL 0x8A
  10903. +#define MIN_SIGNAL_LEVEL 0x2F
  10904. +
  10905. +#define SIGNAL_TO_DBM(x) \
  10906. + (clamp_t(s32, (x), MIN_SIGNAL_LEVEL, MAX_SIGNAL_LEVEL) \
  10907. + - ZERO_DBM_OFFSET)
  10908. +#define SIGNAL_TO_MBM(x) (SIGNAL_TO_DBM(x) * 100)
  10909. +
  10910. +static int symbol_build_supp_rates(u8 *buf, const __le16 *rates)
  10911. +{
  10912. + int i;
  10913. + u8 rate;
  10914. +
  10915. + buf[0] = WLAN_EID_SUPP_RATES;
  10916. + for (i = 0; i < 5; i++) {
  10917. + rate = le16_to_cpu(rates[i]);
  10918. + /* NULL terminated */
  10919. + if (rate == 0x0)
  10920. + break;
  10921. + buf[i + 2] = rate;
  10922. + }
  10923. + buf[1] = i;
  10924. +
  10925. + return i + 2;
  10926. +}
  10927. +
  10928. +static int prism_build_supp_rates(u8 *buf, const u8 *rates)
  10929. +{
  10930. + int i;
  10931. +
  10932. + buf[0] = WLAN_EID_SUPP_RATES;
  10933. + for (i = 0; i < 8; i++) {
  10934. + /* NULL terminated */
  10935. + if (rates[i] == 0x0)
  10936. + break;
  10937. + buf[i + 2] = rates[i];
  10938. + }
  10939. + buf[1] = i;
  10940. +
  10941. + /* We might still have another 2 rates, which need to go in
  10942. + * extended supported rates */
  10943. + if (i == 8 && rates[i] > 0) {
  10944. + buf[10] = WLAN_EID_EXT_SUPP_RATES;
  10945. + for (; i < 10; i++) {
  10946. + /* NULL terminated */
  10947. + if (rates[i] == 0x0)
  10948. + break;
  10949. + buf[i + 2] = rates[i];
  10950. + }
  10951. + buf[11] = i - 8;
  10952. + }
  10953. +
  10954. + return (i < 8) ? i + 2 : i + 4;
  10955. +}
  10956. +
  10957. +static void orinoco_add_hostscan_result(struct orinoco_private *priv,
  10958. + const union hermes_scan_info *bss)
  10959. +{
  10960. + struct wiphy *wiphy = priv_to_wiphy(priv);
  10961. + struct ieee80211_channel *channel;
  10962. + struct cfg80211_bss *cbss;
  10963. + u8 *ie;
  10964. + u8 ie_buf[46];
  10965. + u64 timestamp;
  10966. + s32 signal;
  10967. + u16 capability;
  10968. + u16 beacon_interval;
  10969. + int ie_len;
  10970. + int freq;
  10971. + int len;
  10972. +
  10973. + len = le16_to_cpu(bss->a.essid_len);
  10974. +
  10975. + /* Reconstruct SSID and bitrate IEs to pass up */
  10976. + ie_buf[0] = WLAN_EID_SSID;
  10977. + ie_buf[1] = len;
  10978. + memcpy(&ie_buf[2], bss->a.essid, len);
  10979. +
  10980. + ie = ie_buf + len + 2;
  10981. + ie_len = ie_buf[1] + 2;
  10982. + switch (priv->firmware_type) {
  10983. + case FIRMWARE_TYPE_SYMBOL:
  10984. + ie_len += symbol_build_supp_rates(ie, bss->s.rates);
  10985. + break;
  10986. +
  10987. + case FIRMWARE_TYPE_INTERSIL:
  10988. + ie_len += prism_build_supp_rates(ie, bss->p.rates);
  10989. + break;
  10990. +
  10991. + case FIRMWARE_TYPE_AGERE:
  10992. + default:
  10993. + break;
  10994. + }
  10995. +
  10996. + freq = ieee80211_channel_to_frequency(
  10997. + le16_to_cpu(bss->a.channel), NL80211_BAND_2GHZ);
  10998. + channel = ieee80211_get_channel(wiphy, freq);
  10999. + if (!channel) {
  11000. + printk(KERN_DEBUG "Invalid channel designation %04X(%04X)",
  11001. + bss->a.channel, freq);
  11002. + return; /* Then ignore it for now */
  11003. + }
  11004. + timestamp = 0;
  11005. + capability = le16_to_cpu(bss->a.capabilities);
  11006. + beacon_interval = le16_to_cpu(bss->a.beacon_interv);
  11007. + signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
  11008. +
  11009. + cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
  11010. + bss->a.bssid, timestamp, capability,
  11011. + beacon_interval, ie_buf, ie_len, signal,
  11012. + GFP_KERNEL);
  11013. + cfg80211_put_bss(wiphy, cbss);
  11014. +}
  11015. +
  11016. +void orinoco_add_extscan_result(struct orinoco_private *priv,
  11017. + struct agere_ext_scan_info *bss,
  11018. + size_t len)
  11019. +{
  11020. + struct wiphy *wiphy = priv_to_wiphy(priv);
  11021. + struct ieee80211_channel *channel;
  11022. + struct cfg80211_bss *cbss;
  11023. + const u8 *ie;
  11024. + u64 timestamp;
  11025. + s32 signal;
  11026. + u16 capability;
  11027. + u16 beacon_interval;
  11028. + size_t ie_len;
  11029. + int chan, freq;
  11030. +
  11031. + ie_len = len - sizeof(*bss);
  11032. + ie = cfg80211_find_ie(WLAN_EID_DS_PARAMS, bss->data, ie_len);
  11033. + chan = ie ? ie[2] : 0;
  11034. + freq = ieee80211_channel_to_frequency(chan, NL80211_BAND_2GHZ);
  11035. + channel = ieee80211_get_channel(wiphy, freq);
  11036. +
  11037. + timestamp = le64_to_cpu(bss->timestamp);
  11038. + capability = le16_to_cpu(bss->capabilities);
  11039. + beacon_interval = le16_to_cpu(bss->beacon_interval);
  11040. + ie = bss->data;
  11041. + signal = SIGNAL_TO_MBM(bss->level);
  11042. +
  11043. + cbss = cfg80211_inform_bss(wiphy, channel, CFG80211_BSS_FTYPE_UNKNOWN,
  11044. + bss->bssid, timestamp, capability,
  11045. + beacon_interval, ie, ie_len, signal,
  11046. + GFP_KERNEL);
  11047. + cfg80211_put_bss(wiphy, cbss);
  11048. +}
  11049. +
  11050. +void orinoco_add_hostscan_results(struct orinoco_private *priv,
  11051. + unsigned char *buf,
  11052. + size_t len)
  11053. +{
  11054. + int offset; /* In the scan data */
  11055. + size_t atom_len;
  11056. + bool abort = false;
  11057. +
  11058. + switch (priv->firmware_type) {
  11059. + case FIRMWARE_TYPE_AGERE:
  11060. + atom_len = sizeof(struct agere_scan_apinfo);
  11061. + offset = 0;
  11062. + break;
  11063. +
  11064. + case FIRMWARE_TYPE_SYMBOL:
  11065. + /* Lack of documentation necessitates this hack.
  11066. + * Different firmwares have 68 or 76 byte long atoms.
  11067. + * We try modulo first. If the length divides by both,
  11068. + * we check what would be the channel in the second
  11069. + * frame for a 68-byte atom. 76-byte atoms have 0 there.
  11070. + * Valid channel cannot be 0. */
  11071. + if (len % 76)
  11072. + atom_len = 68;
  11073. + else if (len % 68)
  11074. + atom_len = 76;
  11075. + else if (len >= 1292 && buf[68] == 0)
  11076. + atom_len = 76;
  11077. + else
  11078. + atom_len = 68;
  11079. + offset = 0;
  11080. + break;
  11081. +
  11082. + case FIRMWARE_TYPE_INTERSIL:
  11083. + offset = 4;
  11084. + if (priv->has_hostscan) {
  11085. + atom_len = le16_to_cpup((__le16 *)buf);
  11086. + /* Sanity check for atom_len */
  11087. + if (atom_len < sizeof(struct prism2_scan_apinfo)) {
  11088. + printk(KERN_ERR "%s: Invalid atom_len in scan "
  11089. + "data: %zu\n", priv->ndev->name,
  11090. + atom_len);
  11091. + abort = true;
  11092. + goto scan_abort;
  11093. + }
  11094. + } else
  11095. + atom_len = offsetof(struct prism2_scan_apinfo, atim);
  11096. + break;
  11097. +
  11098. + default:
  11099. + abort = true;
  11100. + goto scan_abort;
  11101. + }
  11102. +
  11103. + /* Check that we got an whole number of atoms */
  11104. + if ((len - offset) % atom_len) {
  11105. + printk(KERN_ERR "%s: Unexpected scan data length %zu, "
  11106. + "atom_len %zu, offset %d\n", priv->ndev->name, len,
  11107. + atom_len, offset);
  11108. + abort = true;
  11109. + goto scan_abort;
  11110. + }
  11111. +
  11112. + /* Process the entries one by one */
  11113. + for (; offset + atom_len <= len; offset += atom_len) {
  11114. + union hermes_scan_info *atom;
  11115. +
  11116. + atom = (union hermes_scan_info *) (buf + offset);
  11117. +
  11118. + orinoco_add_hostscan_result(priv, atom);
  11119. + }
  11120. +
  11121. + scan_abort:
  11122. + if (priv->scan_request) {
  11123. + struct cfg80211_scan_info info = {
  11124. + .aborted = abort,
  11125. + };
  11126. +
  11127. + cfg80211_scan_done(priv->scan_request, &info);
  11128. + priv->scan_request = NULL;
  11129. + }
  11130. +}
  11131. +
  11132. +void orinoco_scan_done(struct orinoco_private *priv, bool abort)
  11133. +{
  11134. + if (priv->scan_request) {
  11135. + struct cfg80211_scan_info info = {
  11136. + .aborted = abort,
  11137. + };
  11138. +
  11139. + cfg80211_scan_done(priv->scan_request, &info);
  11140. + priv->scan_request = NULL;
  11141. + }
  11142. +}
  11143. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/scan.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/scan.h
  11144. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/scan.h 1970-01-01 01:00:00.000000000 +0100
  11145. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/scan.h 2026-02-16 14:00:36.623256352 +0100
  11146. @@ -0,0 +1,21 @@
  11147. +/* Helpers for managing scan queues
  11148. + *
  11149. + * See copyright notice in main.c
  11150. + */
  11151. +#ifndef _ORINOCO_SCAN_H_
  11152. +#define _ORINOCO_SCAN_H_
  11153. +
  11154. +/* Forward declarations */
  11155. +struct orinoco_private;
  11156. +struct agere_ext_scan_info;
  11157. +
  11158. +/* Add scan results */
  11159. +void orinoco_add_extscan_result(struct orinoco_private *priv,
  11160. + struct agere_ext_scan_info *atom,
  11161. + size_t len);
  11162. +void orinoco_add_hostscan_results(struct orinoco_private *dev,
  11163. + unsigned char *buf,
  11164. + size_t len);
  11165. +void orinoco_scan_done(struct orinoco_private *priv, bool abort);
  11166. +
  11167. +#endif /* _ORINOCO_SCAN_H_ */
  11168. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/spectrum_cs.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/spectrum_cs.c
  11169. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/spectrum_cs.c 1970-01-01 01:00:00.000000000 +0100
  11170. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/spectrum_cs.c 2026-02-16 14:00:36.623256352 +0100
  11171. @@ -0,0 +1,328 @@
  11172. +/*
  11173. + * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as
  11174. + * Symbol Wireless Networker LA4137, CompactFlash cards by Socket
  11175. + * Communications and Intel PRO/Wireless 2011B.
  11176. + *
  11177. + * The driver implements Symbol firmware download. The rest is handled
  11178. + * in hermes.c and main.c.
  11179. + *
  11180. + * Utilities for downloading the Symbol firmware are available at
  11181. + * http://sourceforge.net/projects/orinoco/
  11182. + *
  11183. + * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org>
  11184. + * Portions based on orinoco_cs.c:
  11185. + * Copyright (C) David Gibson, Linuxcare Australia
  11186. + * Portions based on Spectrum24tDnld.c from original spectrum24 driver:
  11187. + * Copyright (C) Symbol Technologies.
  11188. + *
  11189. + * See copyright notice in file main.c.
  11190. + */
  11191. +
  11192. +#define DRIVER_NAME "spectrum_cs"
  11193. +#define PFX DRIVER_NAME ": "
  11194. +
  11195. +#include <linux/module.h>
  11196. +#include <linux/kernel.h>
  11197. +#include <linux/delay.h>
  11198. +#include <pcmcia/cistpl.h>
  11199. +#include <pcmcia/cisreg.h>
  11200. +#include <pcmcia/ds.h>
  11201. +
  11202. +#include "orinoco.h"
  11203. +
  11204. +/********************************************************************/
  11205. +/* Module stuff */
  11206. +/********************************************************************/
  11207. +
  11208. +MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
  11209. +MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader");
  11210. +MODULE_LICENSE("Dual MPL/GPL");
  11211. +
  11212. +/* Module parameters */
  11213. +
  11214. +/* Some D-Link cards have buggy CIS. They do work at 5v properly, but
  11215. + * don't have any CIS entry for it. This workaround it... */
  11216. +static int ignore_cis_vcc; /* = 0 */
  11217. +module_param(ignore_cis_vcc, int, 0);
  11218. +MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket");
  11219. +
  11220. +/********************************************************************/
  11221. +/* Data structures */
  11222. +/********************************************************************/
  11223. +
  11224. +/* PCMCIA specific device information (goes in the card field of
  11225. + * struct orinoco_private */
  11226. +struct orinoco_pccard {
  11227. + struct pcmcia_device *p_dev;
  11228. +};
  11229. +
  11230. +/********************************************************************/
  11231. +/* Function prototypes */
  11232. +/********************************************************************/
  11233. +
  11234. +static int spectrum_cs_config(struct pcmcia_device *link);
  11235. +static void spectrum_cs_release(struct pcmcia_device *link);
  11236. +
  11237. +/* Constants for the CISREG_CCSR register */
  11238. +#define HCR_RUN 0x07 /* run firmware after reset */
  11239. +#define HCR_IDLE 0x0E /* don't run firmware after reset */
  11240. +#define HCR_MEM16 0x10 /* memory width bit, should be preserved */
  11241. +
  11242. +
  11243. +/*
  11244. + * Reset the card using configuration registers COR and CCSR.
  11245. + * If IDLE is 1, stop the firmware, so that it can be safely rewritten.
  11246. + */
  11247. +static int
  11248. +spectrum_reset(struct pcmcia_device *link, int idle)
  11249. +{
  11250. + int ret;
  11251. + u8 save_cor;
  11252. + u8 ccsr;
  11253. +
  11254. + /* Doing it if hardware is gone is guaranteed crash */
  11255. + if (!pcmcia_dev_present(link))
  11256. + return -ENODEV;
  11257. +
  11258. + /* Save original COR value */
  11259. + ret = pcmcia_read_config_byte(link, CISREG_COR, &save_cor);
  11260. + if (ret)
  11261. + goto failed;
  11262. +
  11263. + /* Soft-Reset card */
  11264. + ret = pcmcia_write_config_byte(link, CISREG_COR,
  11265. + (save_cor | COR_SOFT_RESET));
  11266. + if (ret)
  11267. + goto failed;
  11268. + udelay(1000);
  11269. +
  11270. + /* Read CCSR */
  11271. + ret = pcmcia_read_config_byte(link, CISREG_CCSR, &ccsr);
  11272. + if (ret)
  11273. + goto failed;
  11274. +
  11275. + /*
  11276. + * Start or stop the firmware. Memory width bit should be
  11277. + * preserved from the value we've just read.
  11278. + */
  11279. + ccsr = (idle ? HCR_IDLE : HCR_RUN) | (ccsr & HCR_MEM16);
  11280. + ret = pcmcia_write_config_byte(link, CISREG_CCSR, ccsr);
  11281. + if (ret)
  11282. + goto failed;
  11283. + udelay(1000);
  11284. +
  11285. + /* Restore original COR configuration index */
  11286. + ret = pcmcia_write_config_byte(link, CISREG_COR,
  11287. + (save_cor & ~COR_SOFT_RESET));
  11288. + if (ret)
  11289. + goto failed;
  11290. + udelay(1000);
  11291. + return 0;
  11292. +
  11293. +failed:
  11294. + return -ENODEV;
  11295. +}
  11296. +
  11297. +/********************************************************************/
  11298. +/* Device methods */
  11299. +/********************************************************************/
  11300. +
  11301. +static int
  11302. +spectrum_cs_hard_reset(struct orinoco_private *priv)
  11303. +{
  11304. + struct orinoco_pccard *card = priv->card;
  11305. + struct pcmcia_device *link = card->p_dev;
  11306. +
  11307. + /* Soft reset using COR and HCR */
  11308. + spectrum_reset(link, 0);
  11309. +
  11310. + return 0;
  11311. +}
  11312. +
  11313. +static int
  11314. +spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
  11315. +{
  11316. + struct orinoco_pccard *card = priv->card;
  11317. + struct pcmcia_device *link = card->p_dev;
  11318. +
  11319. + return spectrum_reset(link, idle);
  11320. +}
  11321. +
  11322. +/********************************************************************/
  11323. +/* PCMCIA stuff */
  11324. +/********************************************************************/
  11325. +
  11326. +static int
  11327. +spectrum_cs_probe(struct pcmcia_device *link)
  11328. +{
  11329. + struct orinoco_private *priv;
  11330. + struct orinoco_pccard *card;
  11331. + int ret;
  11332. +
  11333. + priv = alloc_orinocodev(sizeof(*card), &link->dev,
  11334. + spectrum_cs_hard_reset,
  11335. + spectrum_cs_stop_firmware);
  11336. + if (!priv)
  11337. + return -ENOMEM;
  11338. + card = priv->card;
  11339. +
  11340. + /* Link both structures together */
  11341. + card->p_dev = link;
  11342. + link->priv = priv;
  11343. +
  11344. + ret = spectrum_cs_config(link);
  11345. + if (ret)
  11346. + goto err_free_orinocodev;
  11347. +
  11348. + return 0;
  11349. +
  11350. +err_free_orinocodev:
  11351. + free_orinocodev(priv);
  11352. + return ret;
  11353. +}
  11354. +
  11355. +static void spectrum_cs_detach(struct pcmcia_device *link)
  11356. +{
  11357. + struct orinoco_private *priv = link->priv;
  11358. +
  11359. + orinoco_if_del(priv);
  11360. +
  11361. + spectrum_cs_release(link);
  11362. +
  11363. + free_orinocodev(priv);
  11364. +} /* spectrum_cs_detach */
  11365. +
  11366. +static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
  11367. + void *priv_data)
  11368. +{
  11369. + if (p_dev->config_index == 0)
  11370. + return -EINVAL;
  11371. +
  11372. + return pcmcia_request_io(p_dev);
  11373. +};
  11374. +
  11375. +static int
  11376. +spectrum_cs_config(struct pcmcia_device *link)
  11377. +{
  11378. + struct orinoco_private *priv = link->priv;
  11379. + struct hermes *hw = &priv->hw;
  11380. + int ret;
  11381. + void __iomem *mem;
  11382. +
  11383. + link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC |
  11384. + CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
  11385. + if (ignore_cis_vcc)
  11386. + link->config_flags &= ~CONF_AUTO_CHECK_VCC;
  11387. + ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL);
  11388. + if (ret) {
  11389. + if (!ignore_cis_vcc)
  11390. + printk(KERN_ERR PFX "GetNextTuple(): No matching "
  11391. + "CIS configuration. Maybe you need the "
  11392. + "ignore_cis_vcc=1 parameter.\n");
  11393. + goto failed;
  11394. + }
  11395. +
  11396. + mem = ioport_map(link->resource[0]->start,
  11397. + resource_size(link->resource[0]));
  11398. + if (!mem)
  11399. + goto failed;
  11400. +
  11401. + /* We initialize the hermes structure before completing PCMCIA
  11402. + * configuration just in case the interrupt handler gets
  11403. + * called. */
  11404. + hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
  11405. + hw->eeprom_pda = true;
  11406. +
  11407. + ret = pcmcia_request_irq(link, orinoco_interrupt);
  11408. + if (ret)
  11409. + goto failed;
  11410. +
  11411. + ret = pcmcia_enable_device(link);
  11412. + if (ret)
  11413. + goto failed;
  11414. +
  11415. + /* Reset card */
  11416. + if (spectrum_cs_hard_reset(priv) != 0)
  11417. + goto failed;
  11418. +
  11419. + /* Initialise the main driver */
  11420. + if (orinoco_init(priv) != 0) {
  11421. + printk(KERN_ERR PFX "orinoco_init() failed\n");
  11422. + goto failed;
  11423. + }
  11424. +
  11425. + /* Register an interface with the stack */
  11426. + if (orinoco_if_add(priv, link->resource[0]->start,
  11427. + link->irq, NULL) != 0) {
  11428. + printk(KERN_ERR PFX "orinoco_if_add() failed\n");
  11429. + goto failed;
  11430. + }
  11431. +
  11432. + return 0;
  11433. +
  11434. + failed:
  11435. + spectrum_cs_release(link);
  11436. + return -ENODEV;
  11437. +} /* spectrum_cs_config */
  11438. +
  11439. +static void
  11440. +spectrum_cs_release(struct pcmcia_device *link)
  11441. +{
  11442. + struct orinoco_private *priv = link->priv;
  11443. + unsigned long flags;
  11444. +
  11445. + /* We're committed to taking the device away now, so mark the
  11446. + * hardware as unavailable */
  11447. + priv->hw.ops->lock_irqsave(&priv->lock, &flags);
  11448. + priv->hw_unavailable++;
  11449. + priv->hw.ops->unlock_irqrestore(&priv->lock, &flags);
  11450. +
  11451. + pcmcia_disable_device(link);
  11452. + if (priv->hw.iobase)
  11453. + ioport_unmap(priv->hw.iobase);
  11454. +} /* spectrum_cs_release */
  11455. +
  11456. +
  11457. +static int
  11458. +spectrum_cs_suspend(struct pcmcia_device *link)
  11459. +{
  11460. + struct orinoco_private *priv = link->priv;
  11461. +
  11462. + /* Mark the device as stopped, to block IO until later */
  11463. + orinoco_down(priv);
  11464. +
  11465. + return 0;
  11466. +}
  11467. +
  11468. +static int
  11469. +spectrum_cs_resume(struct pcmcia_device *link)
  11470. +{
  11471. + struct orinoco_private *priv = link->priv;
  11472. + int err = orinoco_up(priv);
  11473. +
  11474. + return err;
  11475. +}
  11476. +
  11477. +
  11478. +/********************************************************************/
  11479. +/* Module initialization */
  11480. +/********************************************************************/
  11481. +
  11482. +static const struct pcmcia_device_id spectrum_cs_ids[] = {
  11483. + PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
  11484. + PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
  11485. + PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
  11486. + PCMCIA_DEVICE_NULL,
  11487. +};
  11488. +MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
  11489. +
  11490. +static struct pcmcia_driver orinoco_driver = {
  11491. + .owner = THIS_MODULE,
  11492. + .name = DRIVER_NAME,
  11493. + .probe = spectrum_cs_probe,
  11494. + .remove = spectrum_cs_detach,
  11495. + .suspend = spectrum_cs_suspend,
  11496. + .resume = spectrum_cs_resume,
  11497. + .id_table = spectrum_cs_ids,
  11498. +};
  11499. +module_pcmcia_driver(orinoco_driver);
  11500. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/wext.c linux-6.18.9/drivers/net/wireless/intersil/orinoco/wext.c
  11501. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/wext.c 1970-01-01 01:00:00.000000000 +0100
  11502. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/wext.c 2026-02-16 14:00:36.623256352 +0100
  11503. @@ -0,0 +1,1415 @@
  11504. +/* Wireless extensions support.
  11505. + *
  11506. + * See copyright notice in main.c
  11507. + */
  11508. +#include <linux/slab.h>
  11509. +#include <linux/kernel.h>
  11510. +#include <linux/if_arp.h>
  11511. +#include <linux/wireless.h>
  11512. +#include <linux/ieee80211.h>
  11513. +#include <linux/etherdevice.h>
  11514. +#include <net/iw_handler.h>
  11515. +#include <net/cfg80211.h>
  11516. +#include <net/cfg80211-wext.h>
  11517. +
  11518. +#include "hermes.h"
  11519. +#include "hermes_rid.h"
  11520. +#include "orinoco.h"
  11521. +
  11522. +#include "hw.h"
  11523. +#include "mic.h"
  11524. +#include "scan.h"
  11525. +#include "main.h"
  11526. +
  11527. +#include "wext.h"
  11528. +
  11529. +#define MAX_RID_LEN 1024
  11530. +
  11531. +/* Helper routine to record keys
  11532. + * It is called under orinoco_lock so it may not sleep */
  11533. +static int orinoco_set_key(struct orinoco_private *priv, int index,
  11534. + enum orinoco_alg alg, const u8 *key, int key_len,
  11535. + const u8 *seq, int seq_len)
  11536. +{
  11537. + kfree_sensitive(priv->keys[index].key);
  11538. + kfree_sensitive(priv->keys[index].seq);
  11539. +
  11540. + if (key_len) {
  11541. + priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC);
  11542. + if (!priv->keys[index].key)
  11543. + goto nomem;
  11544. + } else
  11545. + priv->keys[index].key = NULL;
  11546. +
  11547. + if (seq_len) {
  11548. + priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC);
  11549. + if (!priv->keys[index].seq)
  11550. + goto free_key;
  11551. + } else
  11552. + priv->keys[index].seq = NULL;
  11553. +
  11554. + priv->keys[index].key_len = key_len;
  11555. + priv->keys[index].seq_len = seq_len;
  11556. +
  11557. + if (key_len)
  11558. + memcpy((void *)priv->keys[index].key, key, key_len);
  11559. + if (seq_len)
  11560. + memcpy((void *)priv->keys[index].seq, seq, seq_len);
  11561. +
  11562. + switch (alg) {
  11563. + case ORINOCO_ALG_TKIP:
  11564. + priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
  11565. + break;
  11566. +
  11567. + case ORINOCO_ALG_WEP:
  11568. + priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
  11569. + WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
  11570. + break;
  11571. +
  11572. + case ORINOCO_ALG_NONE:
  11573. + default:
  11574. + priv->keys[index].cipher = 0;
  11575. + break;
  11576. + }
  11577. +
  11578. + return 0;
  11579. +
  11580. +free_key:
  11581. + kfree(priv->keys[index].key);
  11582. + priv->keys[index].key = NULL;
  11583. +
  11584. +nomem:
  11585. + priv->keys[index].key_len = 0;
  11586. + priv->keys[index].seq_len = 0;
  11587. + priv->keys[index].cipher = 0;
  11588. +
  11589. + return -ENOMEM;
  11590. +}
  11591. +
  11592. +static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
  11593. +{
  11594. + struct orinoco_private *priv = ndev_priv(dev);
  11595. + struct hermes *hw = &priv->hw;
  11596. + struct iw_statistics *wstats = &priv->wstats;
  11597. + int err;
  11598. + unsigned long flags;
  11599. +
  11600. + if (!netif_device_present(dev)) {
  11601. + printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n",
  11602. + dev->name);
  11603. + return NULL; /* FIXME: Can we do better than this? */
  11604. + }
  11605. +
  11606. + /* If busy, return the old stats. Returning NULL may cause
  11607. + * the interface to disappear from /proc/net/wireless */
  11608. + if (orinoco_lock(priv, &flags) != 0)
  11609. + return wstats;
  11610. +
  11611. + /* We can't really wait for the tallies inquiry command to
  11612. + * complete, so we just use the previous results and trigger
  11613. + * a new tallies inquiry command for next time - Jean II */
  11614. + /* FIXME: Really we should wait for the inquiry to come back -
  11615. + * as it is the stats we give don't make a whole lot of sense.
  11616. + * Unfortunately, it's not clear how to do that within the
  11617. + * wireless extensions framework: I think we're in user
  11618. + * context, but a lock seems to be held by the time we get in
  11619. + * here so we're not safe to sleep here. */
  11620. + hermes_inquire(hw, HERMES_INQ_TALLIES);
  11621. +
  11622. + if (priv->iw_mode == NL80211_IFTYPE_ADHOC) {
  11623. + memset(&wstats->qual, 0, sizeof(wstats->qual));
  11624. + } else {
  11625. + struct {
  11626. + __le16 qual, signal, noise, unused;
  11627. + } __packed cq;
  11628. +
  11629. + err = HERMES_READ_RECORD(hw, USER_BAP,
  11630. + HERMES_RID_COMMSQUALITY, &cq);
  11631. +
  11632. + if (!err) {
  11633. + wstats->qual.qual = (int)le16_to_cpu(cq.qual);
  11634. + wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95;
  11635. + wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95;
  11636. + wstats->qual.updated =
  11637. + IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
  11638. + }
  11639. + }
  11640. +
  11641. + orinoco_unlock(priv, &flags);
  11642. + return wstats;
  11643. +}
  11644. +
  11645. +/********************************************************************/
  11646. +/* Wireless extensions */
  11647. +/********************************************************************/
  11648. +
  11649. +static int orinoco_ioctl_setwap(struct net_device *dev,
  11650. + struct iw_request_info *info,
  11651. + union iwreq_data *wrqu,
  11652. + char *extra)
  11653. +{
  11654. + struct sockaddr *ap_addr = &wrqu->ap_addr;
  11655. + struct orinoco_private *priv = ndev_priv(dev);
  11656. + int err = -EINPROGRESS; /* Call commit handler */
  11657. + unsigned long flags;
  11658. +
  11659. + if (orinoco_lock(priv, &flags) != 0)
  11660. + return -EBUSY;
  11661. +
  11662. + /* Enable automatic roaming - no sanity checks are needed */
  11663. + if (is_zero_ether_addr(ap_addr->sa_data) ||
  11664. + is_broadcast_ether_addr(ap_addr->sa_data)) {
  11665. + priv->bssid_fixed = 0;
  11666. + eth_zero_addr(priv->desired_bssid);
  11667. +
  11668. + /* "off" means keep existing connection */
  11669. + if (ap_addr->sa_data[0] == 0) {
  11670. + __orinoco_hw_set_wap(priv);
  11671. + err = 0;
  11672. + }
  11673. + goto out;
  11674. + }
  11675. +
  11676. + if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
  11677. + printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
  11678. + "support manual roaming\n",
  11679. + dev->name);
  11680. + err = -EOPNOTSUPP;
  11681. + goto out;
  11682. + }
  11683. +
  11684. + if (priv->iw_mode != NL80211_IFTYPE_STATION) {
  11685. + printk(KERN_WARNING "%s: Manual roaming supported only in "
  11686. + "managed mode\n", dev->name);
  11687. + err = -EOPNOTSUPP;
  11688. + goto out;
  11689. + }
  11690. +
  11691. + /* Intersil firmware hangs without Desired ESSID */
  11692. + if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
  11693. + strlen(priv->desired_essid) == 0) {
  11694. + printk(KERN_WARNING "%s: Desired ESSID must be set for "
  11695. + "manual roaming\n", dev->name);
  11696. + err = -EOPNOTSUPP;
  11697. + goto out;
  11698. + }
  11699. +
  11700. + /* Finally, enable manual roaming */
  11701. + priv->bssid_fixed = 1;
  11702. + memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
  11703. +
  11704. + out:
  11705. + orinoco_unlock(priv, &flags);
  11706. + return err;
  11707. +}
  11708. +
  11709. +static int orinoco_ioctl_getwap(struct net_device *dev,
  11710. + struct iw_request_info *info,
  11711. + union iwreq_data *wrqu,
  11712. + char *extra)
  11713. +{
  11714. + struct sockaddr *ap_addr = &wrqu->ap_addr;
  11715. + struct orinoco_private *priv = ndev_priv(dev);
  11716. +
  11717. + int err = 0;
  11718. + unsigned long flags;
  11719. +
  11720. + if (orinoco_lock(priv, &flags) != 0)
  11721. + return -EBUSY;
  11722. +
  11723. + ap_addr->sa_family = ARPHRD_ETHER;
  11724. + err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data);
  11725. +
  11726. + orinoco_unlock(priv, &flags);
  11727. +
  11728. + return err;
  11729. +}
  11730. +
  11731. +static int orinoco_ioctl_setiwencode(struct net_device *dev,
  11732. + struct iw_request_info *info,
  11733. + union iwreq_data *wrqu,
  11734. + char *keybuf)
  11735. +{
  11736. + struct iw_point *erq = &wrqu->encoding;
  11737. + struct orinoco_private *priv = ndev_priv(dev);
  11738. + int index = (erq->flags & IW_ENCODE_INDEX) - 1;
  11739. + int setindex = priv->tx_key;
  11740. + enum orinoco_alg encode_alg = priv->encode_alg;
  11741. + int restricted = priv->wep_restrict;
  11742. + int err = -EINPROGRESS; /* Call commit handler */
  11743. + unsigned long flags;
  11744. +
  11745. + if (!priv->has_wep)
  11746. + return -EOPNOTSUPP;
  11747. +
  11748. + if (erq->pointer) {
  11749. + /* We actually have a key to set - check its length */
  11750. + if (erq->length > LARGE_KEY_SIZE)
  11751. + return -E2BIG;
  11752. +
  11753. + if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep)
  11754. + return -E2BIG;
  11755. + }
  11756. +
  11757. + if (orinoco_lock(priv, &flags) != 0)
  11758. + return -EBUSY;
  11759. +
  11760. + /* Clear any TKIP key we have */
  11761. + if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP))
  11762. + (void) orinoco_clear_tkip_key(priv, setindex);
  11763. +
  11764. + if (erq->length > 0) {
  11765. + if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
  11766. + index = priv->tx_key;
  11767. +
  11768. + /* Switch on WEP if off */
  11769. + if (encode_alg != ORINOCO_ALG_WEP) {
  11770. + setindex = index;
  11771. + encode_alg = ORINOCO_ALG_WEP;
  11772. + }
  11773. + } else {
  11774. + /* Important note : if the user do "iwconfig eth0 enc off",
  11775. + * we will arrive there with an index of -1. This is valid
  11776. + * but need to be taken care off... Jean II */
  11777. + if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) {
  11778. + if ((index != -1) || (erq->flags == 0)) {
  11779. + err = -EINVAL;
  11780. + goto out;
  11781. + }
  11782. + } else {
  11783. + /* Set the index : Check that the key is valid */
  11784. + if (priv->keys[index].key_len == 0) {
  11785. + err = -EINVAL;
  11786. + goto out;
  11787. + }
  11788. + setindex = index;
  11789. + }
  11790. + }
  11791. +
  11792. + if (erq->flags & IW_ENCODE_DISABLED)
  11793. + encode_alg = ORINOCO_ALG_NONE;
  11794. + if (erq->flags & IW_ENCODE_OPEN)
  11795. + restricted = 0;
  11796. + if (erq->flags & IW_ENCODE_RESTRICTED)
  11797. + restricted = 1;
  11798. +
  11799. + if (erq->pointer && erq->length > 0) {
  11800. + err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
  11801. + erq->length, NULL, 0);
  11802. + }
  11803. + priv->tx_key = setindex;
  11804. +
  11805. + /* Try fast key change if connected and only keys are changed */
  11806. + if ((priv->encode_alg == encode_alg) &&
  11807. + (priv->wep_restrict == restricted) &&
  11808. + netif_carrier_ok(dev)) {
  11809. + err = __orinoco_hw_setup_wepkeys(priv);
  11810. + /* No need to commit if successful */
  11811. + goto out;
  11812. + }
  11813. +
  11814. + priv->encode_alg = encode_alg;
  11815. + priv->wep_restrict = restricted;
  11816. +
  11817. + out:
  11818. + orinoco_unlock(priv, &flags);
  11819. +
  11820. + return err;
  11821. +}
  11822. +
  11823. +static int orinoco_ioctl_getiwencode(struct net_device *dev,
  11824. + struct iw_request_info *info,
  11825. + union iwreq_data *wrqu,
  11826. + char *keybuf)
  11827. +{
  11828. + struct iw_point *erq = &wrqu->encoding;
  11829. + struct orinoco_private *priv = ndev_priv(dev);
  11830. + int index = (erq->flags & IW_ENCODE_INDEX) - 1;
  11831. + unsigned long flags;
  11832. +
  11833. + if (!priv->has_wep)
  11834. + return -EOPNOTSUPP;
  11835. +
  11836. + if (orinoco_lock(priv, &flags) != 0)
  11837. + return -EBUSY;
  11838. +
  11839. + if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
  11840. + index = priv->tx_key;
  11841. +
  11842. + erq->flags = 0;
  11843. + if (!priv->encode_alg)
  11844. + erq->flags |= IW_ENCODE_DISABLED;
  11845. + erq->flags |= index + 1;
  11846. +
  11847. + if (priv->wep_restrict)
  11848. + erq->flags |= IW_ENCODE_RESTRICTED;
  11849. + else
  11850. + erq->flags |= IW_ENCODE_OPEN;
  11851. +
  11852. + erq->length = priv->keys[index].key_len;
  11853. +
  11854. + memcpy(keybuf, priv->keys[index].key, erq->length);
  11855. +
  11856. + orinoco_unlock(priv, &flags);
  11857. + return 0;
  11858. +}
  11859. +
  11860. +static int orinoco_ioctl_setessid(struct net_device *dev,
  11861. + struct iw_request_info *info,
  11862. + union iwreq_data *wrqu,
  11863. + char *essidbuf)
  11864. +{
  11865. + struct iw_point *erq = &wrqu->essid;
  11866. + struct orinoco_private *priv = ndev_priv(dev);
  11867. + unsigned long flags;
  11868. +
  11869. + /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
  11870. + * anyway... - Jean II */
  11871. +
  11872. + /* Hum... Should not use Wireless Extension constant (may change),
  11873. + * should use our own... - Jean II */
  11874. + if (erq->length > IW_ESSID_MAX_SIZE)
  11875. + return -E2BIG;
  11876. +
  11877. + if (orinoco_lock(priv, &flags) != 0)
  11878. + return -EBUSY;
  11879. +
  11880. + /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
  11881. + memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
  11882. +
  11883. + /* If not ANY, get the new ESSID */
  11884. + if (erq->flags)
  11885. + memcpy(priv->desired_essid, essidbuf, erq->length);
  11886. +
  11887. + orinoco_unlock(priv, &flags);
  11888. +
  11889. + return -EINPROGRESS; /* Call commit handler */
  11890. +}
  11891. +
  11892. +static int orinoco_ioctl_getessid(struct net_device *dev,
  11893. + struct iw_request_info *info,
  11894. + union iwreq_data *wrqu,
  11895. + char *essidbuf)
  11896. +{
  11897. + struct iw_point *erq = &wrqu->essid;
  11898. + struct orinoco_private *priv = ndev_priv(dev);
  11899. + int active;
  11900. + int err = 0;
  11901. + unsigned long flags;
  11902. +
  11903. + if (netif_running(dev)) {
  11904. + err = orinoco_hw_get_essid(priv, &active, essidbuf);
  11905. + if (err < 0)
  11906. + return err;
  11907. + erq->length = err;
  11908. + } else {
  11909. + if (orinoco_lock(priv, &flags) != 0)
  11910. + return -EBUSY;
  11911. + memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE);
  11912. + erq->length = strlen(priv->desired_essid);
  11913. + orinoco_unlock(priv, &flags);
  11914. + }
  11915. +
  11916. + erq->flags = 1;
  11917. +
  11918. + return 0;
  11919. +}
  11920. +
  11921. +static int orinoco_ioctl_setfreq(struct net_device *dev,
  11922. + struct iw_request_info *info,
  11923. + union iwreq_data *wrqu,
  11924. + char *extra)
  11925. +{
  11926. + struct iw_freq *frq = &wrqu->freq;
  11927. + struct orinoco_private *priv = ndev_priv(dev);
  11928. + int chan = -1;
  11929. + unsigned long flags;
  11930. + int err = -EINPROGRESS; /* Call commit handler */
  11931. +
  11932. + /* In infrastructure mode the AP sets the channel */
  11933. + if (priv->iw_mode == NL80211_IFTYPE_STATION)
  11934. + return -EBUSY;
  11935. +
  11936. + if ((frq->e == 0) && (frq->m <= 1000)) {
  11937. + /* Setting by channel number */
  11938. + chan = frq->m;
  11939. + } else {
  11940. + /* Setting by frequency */
  11941. + int denom = 1;
  11942. + int i;
  11943. +
  11944. + /* Calculate denominator to rescale to MHz */
  11945. + for (i = 0; i < (6 - frq->e); i++)
  11946. + denom *= 10;
  11947. +
  11948. + chan = ieee80211_frequency_to_channel(frq->m / denom);
  11949. + }
  11950. +
  11951. + if ((chan < 1) || (chan > NUM_CHANNELS) ||
  11952. + !(priv->channel_mask & (1 << (chan - 1))))
  11953. + return -EINVAL;
  11954. +
  11955. + if (orinoco_lock(priv, &flags) != 0)
  11956. + return -EBUSY;
  11957. +
  11958. + priv->channel = chan;
  11959. + if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
  11960. + /* Fast channel change - no commit if successful */
  11961. + struct hermes *hw = &priv->hw;
  11962. + err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
  11963. + HERMES_TEST_SET_CHANNEL,
  11964. + chan, NULL);
  11965. + }
  11966. + orinoco_unlock(priv, &flags);
  11967. +
  11968. + return err;
  11969. +}
  11970. +
  11971. +static int orinoco_ioctl_getfreq(struct net_device *dev,
  11972. + struct iw_request_info *info,
  11973. + union iwreq_data *wrqu,
  11974. + char *extra)
  11975. +{
  11976. + struct iw_freq *frq = &wrqu->freq;
  11977. + struct orinoco_private *priv = ndev_priv(dev);
  11978. + int tmp;
  11979. +
  11980. + /* Locking done in there */
  11981. + tmp = orinoco_hw_get_freq(priv);
  11982. + if (tmp < 0)
  11983. + return tmp;
  11984. +
  11985. + frq->m = tmp * 100000;
  11986. + frq->e = 1;
  11987. +
  11988. + return 0;
  11989. +}
  11990. +
  11991. +static int orinoco_ioctl_getsens(struct net_device *dev,
  11992. + struct iw_request_info *info,
  11993. + union iwreq_data *wrqu,
  11994. + char *extra)
  11995. +{
  11996. + struct iw_param *srq = &wrqu->sens;
  11997. + struct orinoco_private *priv = ndev_priv(dev);
  11998. + struct hermes *hw = &priv->hw;
  11999. + u16 val;
  12000. + int err;
  12001. + unsigned long flags;
  12002. +
  12003. + if (!priv->has_sensitivity)
  12004. + return -EOPNOTSUPP;
  12005. +
  12006. + if (orinoco_lock(priv, &flags) != 0)
  12007. + return -EBUSY;
  12008. + err = hermes_read_wordrec(hw, USER_BAP,
  12009. + HERMES_RID_CNFSYSTEMSCALE, &val);
  12010. + orinoco_unlock(priv, &flags);
  12011. +
  12012. + if (err)
  12013. + return err;
  12014. +
  12015. + srq->value = val;
  12016. + srq->fixed = 0; /* auto */
  12017. +
  12018. + return 0;
  12019. +}
  12020. +
  12021. +static int orinoco_ioctl_setsens(struct net_device *dev,
  12022. + struct iw_request_info *info,
  12023. + union iwreq_data *wrqu,
  12024. + char *extra)
  12025. +{
  12026. + struct iw_param *srq = &wrqu->sens;
  12027. + struct orinoco_private *priv = ndev_priv(dev);
  12028. + int val = srq->value;
  12029. + unsigned long flags;
  12030. +
  12031. + if (!priv->has_sensitivity)
  12032. + return -EOPNOTSUPP;
  12033. +
  12034. + if ((val < 1) || (val > 3))
  12035. + return -EINVAL;
  12036. +
  12037. + if (orinoco_lock(priv, &flags) != 0)
  12038. + return -EBUSY;
  12039. + priv->ap_density = val;
  12040. + orinoco_unlock(priv, &flags);
  12041. +
  12042. + return -EINPROGRESS; /* Call commit handler */
  12043. +}
  12044. +
  12045. +static int orinoco_ioctl_setrate(struct net_device *dev,
  12046. + struct iw_request_info *info,
  12047. + union iwreq_data *wrqu,
  12048. + char *extra)
  12049. +{
  12050. + struct iw_param *rrq = &wrqu->bitrate;
  12051. + struct orinoco_private *priv = ndev_priv(dev);
  12052. + int ratemode;
  12053. + int bitrate; /* 100s of kilobits */
  12054. + unsigned long flags;
  12055. +
  12056. + /* As the user space doesn't know our highest rate, it uses -1
  12057. + * to ask us to set the highest rate. Test it using "iwconfig
  12058. + * ethX rate auto" - Jean II */
  12059. + if (rrq->value == -1)
  12060. + bitrate = 110;
  12061. + else {
  12062. + if (rrq->value % 100000)
  12063. + return -EINVAL;
  12064. + bitrate = rrq->value / 100000;
  12065. + }
  12066. +
  12067. + ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed);
  12068. +
  12069. + if (ratemode == -1)
  12070. + return -EINVAL;
  12071. +
  12072. + if (orinoco_lock(priv, &flags) != 0)
  12073. + return -EBUSY;
  12074. + priv->bitratemode = ratemode;
  12075. + orinoco_unlock(priv, &flags);
  12076. +
  12077. + return -EINPROGRESS;
  12078. +}
  12079. +
  12080. +static int orinoco_ioctl_getrate(struct net_device *dev,
  12081. + struct iw_request_info *info,
  12082. + union iwreq_data *wrqu,
  12083. + char *extra)
  12084. +{
  12085. + struct iw_param *rrq = &wrqu->bitrate;
  12086. + struct orinoco_private *priv = ndev_priv(dev);
  12087. + int err = 0;
  12088. + int bitrate, automatic;
  12089. + unsigned long flags;
  12090. +
  12091. + if (orinoco_lock(priv, &flags) != 0)
  12092. + return -EBUSY;
  12093. +
  12094. + orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic);
  12095. +
  12096. + /* If the interface is running we try to find more about the
  12097. + current mode */
  12098. + if (netif_running(dev)) {
  12099. + int act_bitrate;
  12100. + int lerr;
  12101. +
  12102. + /* Ignore errors if we can't get the actual bitrate */
  12103. + lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate);
  12104. + if (!lerr)
  12105. + bitrate = act_bitrate;
  12106. + }
  12107. +
  12108. + orinoco_unlock(priv, &flags);
  12109. +
  12110. + rrq->value = bitrate;
  12111. + rrq->fixed = !automatic;
  12112. + rrq->disabled = 0;
  12113. +
  12114. + return err;
  12115. +}
  12116. +
  12117. +static int orinoco_ioctl_setpower(struct net_device *dev,
  12118. + struct iw_request_info *info,
  12119. + union iwreq_data *wrqu,
  12120. + char *extra)
  12121. +{
  12122. + struct iw_param *prq = &wrqu->power;
  12123. + struct orinoco_private *priv = ndev_priv(dev);
  12124. + int err = -EINPROGRESS; /* Call commit handler */
  12125. + unsigned long flags;
  12126. +
  12127. + if (orinoco_lock(priv, &flags) != 0)
  12128. + return -EBUSY;
  12129. +
  12130. + if (prq->disabled) {
  12131. + priv->pm_on = 0;
  12132. + } else {
  12133. + switch (prq->flags & IW_POWER_MODE) {
  12134. + case IW_POWER_UNICAST_R:
  12135. + priv->pm_mcast = 0;
  12136. + priv->pm_on = 1;
  12137. + break;
  12138. + case IW_POWER_ALL_R:
  12139. + priv->pm_mcast = 1;
  12140. + priv->pm_on = 1;
  12141. + break;
  12142. + case IW_POWER_ON:
  12143. + /* No flags : but we may have a value - Jean II */
  12144. + break;
  12145. + default:
  12146. + err = -EINVAL;
  12147. + goto out;
  12148. + }
  12149. +
  12150. + if (prq->flags & IW_POWER_TIMEOUT) {
  12151. + priv->pm_on = 1;
  12152. + priv->pm_timeout = prq->value / 1000;
  12153. + }
  12154. + if (prq->flags & IW_POWER_PERIOD) {
  12155. + priv->pm_on = 1;
  12156. + priv->pm_period = prq->value / 1000;
  12157. + }
  12158. + /* It's valid to not have a value if we are just toggling
  12159. + * the flags... Jean II */
  12160. + if (!priv->pm_on) {
  12161. + err = -EINVAL;
  12162. + goto out;
  12163. + }
  12164. + }
  12165. +
  12166. + out:
  12167. + orinoco_unlock(priv, &flags);
  12168. +
  12169. + return err;
  12170. +}
  12171. +
  12172. +static int orinoco_ioctl_getpower(struct net_device *dev,
  12173. + struct iw_request_info *info,
  12174. + union iwreq_data *wrqu,
  12175. + char *extra)
  12176. +{
  12177. + struct iw_param *prq = &wrqu->power;
  12178. + struct orinoco_private *priv = ndev_priv(dev);
  12179. + struct hermes *hw = &priv->hw;
  12180. + int err = 0;
  12181. + u16 enable, period, timeout, mcast;
  12182. + unsigned long flags;
  12183. +
  12184. + if (orinoco_lock(priv, &flags) != 0)
  12185. + return -EBUSY;
  12186. +
  12187. + err = hermes_read_wordrec(hw, USER_BAP,
  12188. + HERMES_RID_CNFPMENABLED, &enable);
  12189. + if (err)
  12190. + goto out;
  12191. +
  12192. + err = hermes_read_wordrec(hw, USER_BAP,
  12193. + HERMES_RID_CNFMAXSLEEPDURATION, &period);
  12194. + if (err)
  12195. + goto out;
  12196. +
  12197. + err = hermes_read_wordrec(hw, USER_BAP,
  12198. + HERMES_RID_CNFPMHOLDOVERDURATION, &timeout);
  12199. + if (err)
  12200. + goto out;
  12201. +
  12202. + err = hermes_read_wordrec(hw, USER_BAP,
  12203. + HERMES_RID_CNFMULTICASTRECEIVE, &mcast);
  12204. + if (err)
  12205. + goto out;
  12206. +
  12207. + prq->disabled = !enable;
  12208. + /* Note : by default, display the period */
  12209. + if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {
  12210. + prq->flags = IW_POWER_TIMEOUT;
  12211. + prq->value = timeout * 1000;
  12212. + } else {
  12213. + prq->flags = IW_POWER_PERIOD;
  12214. + prq->value = period * 1000;
  12215. + }
  12216. + if (mcast)
  12217. + prq->flags |= IW_POWER_ALL_R;
  12218. + else
  12219. + prq->flags |= IW_POWER_UNICAST_R;
  12220. +
  12221. + out:
  12222. + orinoco_unlock(priv, &flags);
  12223. +
  12224. + return err;
  12225. +}
  12226. +
  12227. +static int orinoco_ioctl_set_encodeext(struct net_device *dev,
  12228. + struct iw_request_info *info,
  12229. + union iwreq_data *wrqu,
  12230. + char *extra)
  12231. +{
  12232. + struct orinoco_private *priv = ndev_priv(dev);
  12233. + struct iw_point *encoding = &wrqu->encoding;
  12234. + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
  12235. + int idx, alg = ext->alg, set_key = 1;
  12236. + unsigned long flags;
  12237. + int err = -EINVAL;
  12238. +
  12239. + if (orinoco_lock(priv, &flags) != 0)
  12240. + return -EBUSY;
  12241. +
  12242. + /* Determine and validate the key index */
  12243. + idx = encoding->flags & IW_ENCODE_INDEX;
  12244. + if (idx) {
  12245. + if ((idx < 1) || (idx > 4))
  12246. + goto out;
  12247. + idx--;
  12248. + } else
  12249. + idx = priv->tx_key;
  12250. +
  12251. + if (encoding->flags & IW_ENCODE_DISABLED)
  12252. + alg = IW_ENCODE_ALG_NONE;
  12253. +
  12254. + if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) {
  12255. + /* Clear any TKIP TX key we had */
  12256. + (void) orinoco_clear_tkip_key(priv, priv->tx_key);
  12257. + }
  12258. +
  12259. + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
  12260. + priv->tx_key = idx;
  12261. + set_key = ((alg == IW_ENCODE_ALG_TKIP) ||
  12262. + (ext->key_len > 0)) ? 1 : 0;
  12263. + }
  12264. +
  12265. + if (set_key) {
  12266. + /* Set the requested key first */
  12267. + switch (alg) {
  12268. + case IW_ENCODE_ALG_NONE:
  12269. + priv->encode_alg = ORINOCO_ALG_NONE;
  12270. + err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
  12271. + NULL, 0, NULL, 0);
  12272. + break;
  12273. +
  12274. + case IW_ENCODE_ALG_WEP:
  12275. + if (ext->key_len <= 0)
  12276. + goto out;
  12277. +
  12278. + priv->encode_alg = ORINOCO_ALG_WEP;
  12279. + err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
  12280. + ext->key, ext->key_len, NULL, 0);
  12281. + break;
  12282. +
  12283. + case IW_ENCODE_ALG_TKIP:
  12284. + {
  12285. + u8 *tkip_iv = NULL;
  12286. +
  12287. + if (!priv->has_wpa ||
  12288. + (ext->key_len > sizeof(struct orinoco_tkip_key)))
  12289. + goto out;
  12290. +
  12291. + priv->encode_alg = ORINOCO_ALG_TKIP;
  12292. +
  12293. + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
  12294. + tkip_iv = &ext->rx_seq[0];
  12295. +
  12296. + err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
  12297. + ext->key, ext->key_len, tkip_iv,
  12298. + ORINOCO_SEQ_LEN);
  12299. +
  12300. + err = __orinoco_hw_set_tkip_key(priv, idx,
  12301. + ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
  12302. + priv->keys[idx].key, priv->keys[idx].key_len,
  12303. + tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
  12304. + if (err)
  12305. + printk(KERN_ERR "%s: Error %d setting TKIP key"
  12306. + "\n", dev->name, err);
  12307. +
  12308. + goto out;
  12309. + }
  12310. + default:
  12311. + goto out;
  12312. + }
  12313. + }
  12314. + err = -EINPROGRESS;
  12315. + out:
  12316. + orinoco_unlock(priv, &flags);
  12317. +
  12318. + return err;
  12319. +}
  12320. +
  12321. +static int orinoco_ioctl_get_encodeext(struct net_device *dev,
  12322. + struct iw_request_info *info,
  12323. + union iwreq_data *wrqu,
  12324. + char *extra)
  12325. +{
  12326. + struct orinoco_private *priv = ndev_priv(dev);
  12327. + struct iw_point *encoding = &wrqu->encoding;
  12328. + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
  12329. + int idx, max_key_len;
  12330. + unsigned long flags;
  12331. + int err;
  12332. +
  12333. + if (orinoco_lock(priv, &flags) != 0)
  12334. + return -EBUSY;
  12335. +
  12336. + err = -EINVAL;
  12337. + max_key_len = encoding->length - sizeof(*ext);
  12338. + if (max_key_len < 0)
  12339. + goto out;
  12340. +
  12341. + idx = encoding->flags & IW_ENCODE_INDEX;
  12342. + if (idx) {
  12343. + if ((idx < 1) || (idx > 4))
  12344. + goto out;
  12345. + idx--;
  12346. + } else
  12347. + idx = priv->tx_key;
  12348. +
  12349. + encoding->flags = idx + 1;
  12350. + memset(ext, 0, sizeof(*ext));
  12351. +
  12352. + switch (priv->encode_alg) {
  12353. + case ORINOCO_ALG_NONE:
  12354. + ext->alg = IW_ENCODE_ALG_NONE;
  12355. + ext->key_len = 0;
  12356. + encoding->flags |= IW_ENCODE_DISABLED;
  12357. + break;
  12358. + case ORINOCO_ALG_WEP:
  12359. + ext->alg = IW_ENCODE_ALG_WEP;
  12360. + ext->key_len = min(priv->keys[idx].key_len, max_key_len);
  12361. + memcpy(ext->key, priv->keys[idx].key, ext->key_len);
  12362. + encoding->flags |= IW_ENCODE_ENABLED;
  12363. + break;
  12364. + case ORINOCO_ALG_TKIP:
  12365. + ext->alg = IW_ENCODE_ALG_TKIP;
  12366. + ext->key_len = min(priv->keys[idx].key_len, max_key_len);
  12367. + memcpy(ext->key, priv->keys[idx].key, ext->key_len);
  12368. + encoding->flags |= IW_ENCODE_ENABLED;
  12369. + break;
  12370. + }
  12371. +
  12372. + err = 0;
  12373. + out:
  12374. + orinoco_unlock(priv, &flags);
  12375. +
  12376. + return err;
  12377. +}
  12378. +
  12379. +static int orinoco_ioctl_set_auth(struct net_device *dev,
  12380. + struct iw_request_info *info,
  12381. + union iwreq_data *wrqu, char *extra)
  12382. +{
  12383. + struct orinoco_private *priv = ndev_priv(dev);
  12384. + struct hermes *hw = &priv->hw;
  12385. + struct iw_param *param = &wrqu->param;
  12386. + unsigned long flags;
  12387. + int ret = -EINPROGRESS;
  12388. +
  12389. + if (orinoco_lock(priv, &flags) != 0)
  12390. + return -EBUSY;
  12391. +
  12392. + switch (param->flags & IW_AUTH_INDEX) {
  12393. + case IW_AUTH_WPA_VERSION:
  12394. + case IW_AUTH_CIPHER_PAIRWISE:
  12395. + case IW_AUTH_CIPHER_GROUP:
  12396. + case IW_AUTH_RX_UNENCRYPTED_EAPOL:
  12397. + case IW_AUTH_PRIVACY_INVOKED:
  12398. + case IW_AUTH_DROP_UNENCRYPTED:
  12399. + /*
  12400. + * orinoco does not use these parameters
  12401. + */
  12402. + break;
  12403. +
  12404. + case IW_AUTH_MFP:
  12405. + /* Management Frame Protection not supported.
  12406. + * Only fail if set to required.
  12407. + */
  12408. + if (param->value == IW_AUTH_MFP_REQUIRED)
  12409. + ret = -EINVAL;
  12410. + break;
  12411. +
  12412. + case IW_AUTH_KEY_MGMT:
  12413. + /* wl_lkm implies value 2 == PSK for Hermes I
  12414. + * which ties in with WEXT
  12415. + * no other hints tho :(
  12416. + */
  12417. + priv->key_mgmt = param->value;
  12418. + break;
  12419. +
  12420. + case IW_AUTH_TKIP_COUNTERMEASURES:
  12421. + /* When countermeasures are enabled, shut down the
  12422. + * card; when disabled, re-enable the card. This must
  12423. + * take effect immediately.
  12424. + *
  12425. + * TODO: Make sure that the EAPOL message is getting
  12426. + * out before card disabled
  12427. + */
  12428. + if (param->value) {
  12429. + priv->tkip_cm_active = 1;
  12430. + ret = hermes_disable_port(hw, 0);
  12431. + } else {
  12432. + priv->tkip_cm_active = 0;
  12433. + ret = hermes_enable_port(hw, 0);
  12434. + }
  12435. + break;
  12436. +
  12437. + case IW_AUTH_80211_AUTH_ALG:
  12438. + if (param->value & IW_AUTH_ALG_SHARED_KEY)
  12439. + priv->wep_restrict = 1;
  12440. + else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM)
  12441. + priv->wep_restrict = 0;
  12442. + else
  12443. + ret = -EINVAL;
  12444. + break;
  12445. +
  12446. + case IW_AUTH_WPA_ENABLED:
  12447. + if (priv->has_wpa) {
  12448. + priv->wpa_enabled = param->value ? 1 : 0;
  12449. + } else {
  12450. + if (param->value)
  12451. + ret = -EOPNOTSUPP;
  12452. + /* else silently accept disable of WPA */
  12453. + priv->wpa_enabled = 0;
  12454. + }
  12455. + break;
  12456. +
  12457. + default:
  12458. + ret = -EOPNOTSUPP;
  12459. + }
  12460. +
  12461. + orinoco_unlock(priv, &flags);
  12462. + return ret;
  12463. +}
  12464. +
  12465. +static int orinoco_ioctl_get_auth(struct net_device *dev,
  12466. + struct iw_request_info *info,
  12467. + union iwreq_data *wrqu, char *extra)
  12468. +{
  12469. + struct orinoco_private *priv = ndev_priv(dev);
  12470. + struct iw_param *param = &wrqu->param;
  12471. + unsigned long flags;
  12472. + int ret = 0;
  12473. +
  12474. + if (orinoco_lock(priv, &flags) != 0)
  12475. + return -EBUSY;
  12476. +
  12477. + switch (param->flags & IW_AUTH_INDEX) {
  12478. + case IW_AUTH_KEY_MGMT:
  12479. + param->value = priv->key_mgmt;
  12480. + break;
  12481. +
  12482. + case IW_AUTH_TKIP_COUNTERMEASURES:
  12483. + param->value = priv->tkip_cm_active;
  12484. + break;
  12485. +
  12486. + case IW_AUTH_80211_AUTH_ALG:
  12487. + if (priv->wep_restrict)
  12488. + param->value = IW_AUTH_ALG_SHARED_KEY;
  12489. + else
  12490. + param->value = IW_AUTH_ALG_OPEN_SYSTEM;
  12491. + break;
  12492. +
  12493. + case IW_AUTH_WPA_ENABLED:
  12494. + param->value = priv->wpa_enabled;
  12495. + break;
  12496. +
  12497. + default:
  12498. + ret = -EOPNOTSUPP;
  12499. + }
  12500. +
  12501. + orinoco_unlock(priv, &flags);
  12502. + return ret;
  12503. +}
  12504. +
  12505. +static int orinoco_ioctl_set_genie(struct net_device *dev,
  12506. + struct iw_request_info *info,
  12507. + union iwreq_data *wrqu, char *extra)
  12508. +{
  12509. + struct orinoco_private *priv = ndev_priv(dev);
  12510. + u8 *buf;
  12511. + unsigned long flags;
  12512. +
  12513. + /* cut off at IEEE80211_MAX_DATA_LEN */
  12514. + if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) ||
  12515. + (wrqu->data.length && (extra == NULL)))
  12516. + return -EINVAL;
  12517. +
  12518. + if (wrqu->data.length) {
  12519. + buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
  12520. + if (buf == NULL)
  12521. + return -ENOMEM;
  12522. + } else
  12523. + buf = NULL;
  12524. +
  12525. + if (orinoco_lock(priv, &flags) != 0) {
  12526. + kfree(buf);
  12527. + return -EBUSY;
  12528. + }
  12529. +
  12530. + kfree(priv->wpa_ie);
  12531. + priv->wpa_ie = buf;
  12532. + priv->wpa_ie_len = wrqu->data.length;
  12533. +
  12534. + if (priv->wpa_ie) {
  12535. + /* Looks like wl_lkm wants to check the auth alg, and
  12536. + * somehow pass it to the firmware.
  12537. + * Instead it just calls the key mgmt rid
  12538. + * - we do this in set auth.
  12539. + */
  12540. + }
  12541. +
  12542. + orinoco_unlock(priv, &flags);
  12543. + return 0;
  12544. +}
  12545. +
  12546. +static int orinoco_ioctl_get_genie(struct net_device *dev,
  12547. + struct iw_request_info *info,
  12548. + union iwreq_data *wrqu, char *extra)
  12549. +{
  12550. + struct orinoco_private *priv = ndev_priv(dev);
  12551. + unsigned long flags;
  12552. + int err = 0;
  12553. +
  12554. + if (orinoco_lock(priv, &flags) != 0)
  12555. + return -EBUSY;
  12556. +
  12557. + if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) {
  12558. + wrqu->data.length = 0;
  12559. + goto out;
  12560. + }
  12561. +
  12562. + if (wrqu->data.length < priv->wpa_ie_len) {
  12563. + err = -E2BIG;
  12564. + goto out;
  12565. + }
  12566. +
  12567. + wrqu->data.length = priv->wpa_ie_len;
  12568. + memcpy(extra, priv->wpa_ie, priv->wpa_ie_len);
  12569. +
  12570. +out:
  12571. + orinoco_unlock(priv, &flags);
  12572. + return err;
  12573. +}
  12574. +
  12575. +static int orinoco_ioctl_set_mlme(struct net_device *dev,
  12576. + struct iw_request_info *info,
  12577. + union iwreq_data *wrqu, char *extra)
  12578. +{
  12579. + struct orinoco_private *priv = ndev_priv(dev);
  12580. + struct iw_mlme *mlme = (struct iw_mlme *)extra;
  12581. + unsigned long flags;
  12582. + int ret = 0;
  12583. +
  12584. + if (orinoco_lock(priv, &flags) != 0)
  12585. + return -EBUSY;
  12586. +
  12587. + switch (mlme->cmd) {
  12588. + case IW_MLME_DEAUTH:
  12589. + /* silently ignore */
  12590. + break;
  12591. +
  12592. + case IW_MLME_DISASSOC:
  12593. +
  12594. + ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data,
  12595. + mlme->reason_code);
  12596. + break;
  12597. +
  12598. + default:
  12599. + ret = -EOPNOTSUPP;
  12600. + }
  12601. +
  12602. + orinoco_unlock(priv, &flags);
  12603. + return ret;
  12604. +}
  12605. +
  12606. +static int orinoco_ioctl_reset(struct net_device *dev,
  12607. + struct iw_request_info *info,
  12608. + union iwreq_data *wrqu,
  12609. + char *extra)
  12610. +{
  12611. + struct orinoco_private *priv = ndev_priv(dev);
  12612. +
  12613. + if (!capable(CAP_NET_ADMIN))
  12614. + return -EPERM;
  12615. +
  12616. + if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
  12617. + printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
  12618. +
  12619. + /* Firmware reset */
  12620. + orinoco_reset(&priv->reset_work);
  12621. + } else {
  12622. + printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
  12623. +
  12624. + schedule_work(&priv->reset_work);
  12625. + }
  12626. +
  12627. + return 0;
  12628. +}
  12629. +
  12630. +static int orinoco_ioctl_setibssport(struct net_device *dev,
  12631. + struct iw_request_info *info,
  12632. + union iwreq_data *wrqu,
  12633. + char *extra)
  12634. +
  12635. +{
  12636. + struct orinoco_private *priv = ndev_priv(dev);
  12637. + int val = *((int *) extra);
  12638. + unsigned long flags;
  12639. +
  12640. + if (orinoco_lock(priv, &flags) != 0)
  12641. + return -EBUSY;
  12642. +
  12643. + priv->ibss_port = val;
  12644. +
  12645. + /* Actually update the mode we are using */
  12646. + set_port_type(priv);
  12647. +
  12648. + orinoco_unlock(priv, &flags);
  12649. + return -EINPROGRESS; /* Call commit handler */
  12650. +}
  12651. +
  12652. +static int orinoco_ioctl_getibssport(struct net_device *dev,
  12653. + struct iw_request_info *info,
  12654. + union iwreq_data *wrqu,
  12655. + char *extra)
  12656. +{
  12657. + struct orinoco_private *priv = ndev_priv(dev);
  12658. + int *val = (int *) extra;
  12659. +
  12660. + *val = priv->ibss_port;
  12661. + return 0;
  12662. +}
  12663. +
  12664. +static int orinoco_ioctl_setport3(struct net_device *dev,
  12665. + struct iw_request_info *info,
  12666. + union iwreq_data *wrqu,
  12667. + char *extra)
  12668. +{
  12669. + struct orinoco_private *priv = ndev_priv(dev);
  12670. + int val = *((int *) extra);
  12671. + int err = 0;
  12672. + unsigned long flags;
  12673. +
  12674. + if (orinoco_lock(priv, &flags) != 0)
  12675. + return -EBUSY;
  12676. +
  12677. + switch (val) {
  12678. + case 0: /* Try to do IEEE ad-hoc mode */
  12679. + if (!priv->has_ibss) {
  12680. + err = -EINVAL;
  12681. + break;
  12682. + }
  12683. + priv->prefer_port3 = 0;
  12684. +
  12685. + break;
  12686. +
  12687. + case 1: /* Try to do Lucent proprietary ad-hoc mode */
  12688. + if (!priv->has_port3) {
  12689. + err = -EINVAL;
  12690. + break;
  12691. + }
  12692. + priv->prefer_port3 = 1;
  12693. + break;
  12694. +
  12695. + default:
  12696. + err = -EINVAL;
  12697. + }
  12698. +
  12699. + if (!err) {
  12700. + /* Actually update the mode we are using */
  12701. + set_port_type(priv);
  12702. + err = -EINPROGRESS;
  12703. + }
  12704. +
  12705. + orinoco_unlock(priv, &flags);
  12706. +
  12707. + return err;
  12708. +}
  12709. +
  12710. +static int orinoco_ioctl_getport3(struct net_device *dev,
  12711. + struct iw_request_info *info,
  12712. + union iwreq_data *wrqu,
  12713. + char *extra)
  12714. +{
  12715. + struct orinoco_private *priv = ndev_priv(dev);
  12716. + int *val = (int *) extra;
  12717. +
  12718. + *val = priv->prefer_port3;
  12719. + return 0;
  12720. +}
  12721. +
  12722. +static int orinoco_ioctl_setpreamble(struct net_device *dev,
  12723. + struct iw_request_info *info,
  12724. + union iwreq_data *wrqu,
  12725. + char *extra)
  12726. +{
  12727. + struct orinoco_private *priv = ndev_priv(dev);
  12728. + unsigned long flags;
  12729. + int val;
  12730. +
  12731. + if (!priv->has_preamble)
  12732. + return -EOPNOTSUPP;
  12733. +
  12734. + /* 802.11b has recently defined some short preamble.
  12735. + * Basically, the Phy header has been reduced in size.
  12736. + * This increase performance, especially at high rates
  12737. + * (the preamble is transmitted at 1Mb/s), unfortunately
  12738. + * this give compatibility troubles... - Jean II */
  12739. + val = *((int *) extra);
  12740. +
  12741. + if (orinoco_lock(priv, &flags) != 0)
  12742. + return -EBUSY;
  12743. +
  12744. + if (val)
  12745. + priv->preamble = 1;
  12746. + else
  12747. + priv->preamble = 0;
  12748. +
  12749. + orinoco_unlock(priv, &flags);
  12750. +
  12751. + return -EINPROGRESS; /* Call commit handler */
  12752. +}
  12753. +
  12754. +static int orinoco_ioctl_getpreamble(struct net_device *dev,
  12755. + struct iw_request_info *info,
  12756. + union iwreq_data *wrqu,
  12757. + char *extra)
  12758. +{
  12759. + struct orinoco_private *priv = ndev_priv(dev);
  12760. + int *val = (int *) extra;
  12761. +
  12762. + if (!priv->has_preamble)
  12763. + return -EOPNOTSUPP;
  12764. +
  12765. + *val = priv->preamble;
  12766. + return 0;
  12767. +}
  12768. +
  12769. +/* ioctl interface to hermes_read_ltv()
  12770. + * To use with iwpriv, pass the RID as the token argument, e.g.
  12771. + * iwpriv get_rid [0xfc00]
  12772. + * At least Wireless Tools 25 is required to use iwpriv.
  12773. + * For Wireless Tools 25 and 26 append "dummy" are the end. */
  12774. +static int orinoco_ioctl_getrid(struct net_device *dev,
  12775. + struct iw_request_info *info,
  12776. + union iwreq_data *wrqu,
  12777. + char *extra)
  12778. +{
  12779. + struct iw_point *data = &wrqu->data;
  12780. + struct orinoco_private *priv = ndev_priv(dev);
  12781. + struct hermes *hw = &priv->hw;
  12782. + int rid = data->flags;
  12783. + u16 length;
  12784. + int err;
  12785. + unsigned long flags;
  12786. +
  12787. + /* It's a "get" function, but we don't want users to access the
  12788. + * WEP key and other raw firmware data */
  12789. + if (!capable(CAP_NET_ADMIN))
  12790. + return -EPERM;
  12791. +
  12792. + if (rid < 0xfc00 || rid > 0xffff)
  12793. + return -EINVAL;
  12794. +
  12795. + if (orinoco_lock(priv, &flags) != 0)
  12796. + return -EBUSY;
  12797. +
  12798. + err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
  12799. + extra);
  12800. + if (err)
  12801. + goto out;
  12802. +
  12803. + data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
  12804. + MAX_RID_LEN);
  12805. +
  12806. + out:
  12807. + orinoco_unlock(priv, &flags);
  12808. + return err;
  12809. +}
  12810. +
  12811. +
  12812. +/* Commit handler, called after set operations */
  12813. +static int orinoco_ioctl_commit(struct net_device *dev,
  12814. + struct iw_request_info *info,
  12815. + union iwreq_data *wrqu,
  12816. + char *extra)
  12817. +{
  12818. + struct orinoco_private *priv = ndev_priv(dev);
  12819. + unsigned long flags;
  12820. + int err = 0;
  12821. +
  12822. + if (!priv->open)
  12823. + return 0;
  12824. +
  12825. + if (orinoco_lock(priv, &flags) != 0)
  12826. + return err;
  12827. +
  12828. + err = orinoco_commit(priv);
  12829. +
  12830. + orinoco_unlock(priv, &flags);
  12831. + return err;
  12832. +}
  12833. +
  12834. +static const struct iw_priv_args orinoco_privtab[] = {
  12835. + { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
  12836. + { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
  12837. + { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  12838. + 0, "set_port3" },
  12839. + { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  12840. + "get_port3" },
  12841. + { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  12842. + 0, "set_preamble" },
  12843. + { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  12844. + "get_preamble" },
  12845. + { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  12846. + 0, "set_ibssport" },
  12847. + { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
  12848. + "get_ibssport" },
  12849. + { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
  12850. + "get_rid" },
  12851. +};
  12852. +
  12853. +
  12854. +/*
  12855. + * Structures to export the Wireless Handlers
  12856. + */
  12857. +
  12858. +static const iw_handler orinoco_handler[] = {
  12859. + IW_HANDLER(SIOCSIWCOMMIT, orinoco_ioctl_commit),
  12860. + IW_HANDLER(SIOCGIWNAME, cfg80211_wext_giwname),
  12861. + IW_HANDLER(SIOCSIWFREQ, orinoco_ioctl_setfreq),
  12862. + IW_HANDLER(SIOCGIWFREQ, orinoco_ioctl_getfreq),
  12863. + IW_HANDLER(SIOCSIWMODE, cfg80211_wext_siwmode),
  12864. + IW_HANDLER(SIOCGIWMODE, cfg80211_wext_giwmode),
  12865. + IW_HANDLER(SIOCSIWSENS, orinoco_ioctl_setsens),
  12866. + IW_HANDLER(SIOCGIWSENS, orinoco_ioctl_getsens),
  12867. + IW_HANDLER(SIOCGIWRANGE, cfg80211_wext_giwrange),
  12868. + IW_HANDLER(SIOCSIWAP, orinoco_ioctl_setwap),
  12869. + IW_HANDLER(SIOCGIWAP, orinoco_ioctl_getwap),
  12870. + IW_HANDLER(SIOCSIWSCAN, cfg80211_wext_siwscan),
  12871. + IW_HANDLER(SIOCGIWSCAN, cfg80211_wext_giwscan),
  12872. + IW_HANDLER(SIOCSIWESSID, orinoco_ioctl_setessid),
  12873. + IW_HANDLER(SIOCGIWESSID, orinoco_ioctl_getessid),
  12874. + IW_HANDLER(SIOCSIWRATE, orinoco_ioctl_setrate),
  12875. + IW_HANDLER(SIOCGIWRATE, orinoco_ioctl_getrate),
  12876. + IW_HANDLER(SIOCSIWRTS, cfg80211_wext_siwrts),
  12877. + IW_HANDLER(SIOCGIWRTS, cfg80211_wext_giwrts),
  12878. + IW_HANDLER(SIOCSIWFRAG, cfg80211_wext_siwfrag),
  12879. + IW_HANDLER(SIOCGIWFRAG, cfg80211_wext_giwfrag),
  12880. + IW_HANDLER(SIOCGIWRETRY, cfg80211_wext_giwretry),
  12881. + IW_HANDLER(SIOCSIWENCODE, orinoco_ioctl_setiwencode),
  12882. + IW_HANDLER(SIOCGIWENCODE, orinoco_ioctl_getiwencode),
  12883. + IW_HANDLER(SIOCSIWPOWER, orinoco_ioctl_setpower),
  12884. + IW_HANDLER(SIOCGIWPOWER, orinoco_ioctl_getpower),
  12885. + IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie),
  12886. + IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie),
  12887. + IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme),
  12888. + IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth),
  12889. + IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth),
  12890. + IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext),
  12891. + IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext),
  12892. +};
  12893. +
  12894. +
  12895. +/*
  12896. + Added typecasting since we no longer use iwreq_data -- Moustafa
  12897. + */
  12898. +static const iw_handler orinoco_private_handler[] = {
  12899. + [0] = orinoco_ioctl_reset,
  12900. + [1] = orinoco_ioctl_reset,
  12901. + [2] = orinoco_ioctl_setport3,
  12902. + [3] = orinoco_ioctl_getport3,
  12903. + [4] = orinoco_ioctl_setpreamble,
  12904. + [5] = orinoco_ioctl_getpreamble,
  12905. + [6] = orinoco_ioctl_setibssport,
  12906. + [7] = orinoco_ioctl_getibssport,
  12907. + [9] = orinoco_ioctl_getrid,
  12908. +};
  12909. +
  12910. +const struct iw_handler_def orinoco_handler_def = {
  12911. + .num_standard = ARRAY_SIZE(orinoco_handler),
  12912. + .num_private = ARRAY_SIZE(orinoco_private_handler),
  12913. + .num_private_args = ARRAY_SIZE(orinoco_privtab),
  12914. + .standard = orinoco_handler,
  12915. + .private = orinoco_private_handler,
  12916. + .private_args = orinoco_privtab,
  12917. + .get_wireless_stats = orinoco_get_wireless_stats,
  12918. +};
  12919. diff -Nur linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/wext.h linux-6.18.9/drivers/net/wireless/intersil/orinoco/wext.h
  12920. --- linux-6.18.9.orig/drivers/net/wireless/intersil/orinoco/wext.h 1970-01-01 01:00:00.000000000 +0100
  12921. +++ linux-6.18.9/drivers/net/wireless/intersil/orinoco/wext.h 2026-02-16 14:00:36.623256352 +0100
  12922. @@ -0,0 +1,13 @@
  12923. +/* Wireless extensions support.
  12924. + *
  12925. + * See copyright notice in main.c
  12926. + */
  12927. +#ifndef _ORINOCO_WEXT_H_
  12928. +#define _ORINOCO_WEXT_H_
  12929. +
  12930. +#include <net/iw_handler.h>
  12931. +
  12932. +/* Structure defining all our WEXT handlers */
  12933. +extern const struct iw_handler_def orinoco_handler_def;
  12934. +
  12935. +#endif /* _ORINOCO_WEXT_H_ */